package com.erdaoya.springcloud.comx.utils.rest;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import java.util.*;
import java.net.*;
import java.io.*;
import static org.apache.http.Consts.UTF_8;
/**
* Created by xue on 12/19/16.
* TODO 寻找适合的 url 解析以及请求类
* TODO 实现map 细节再思考
* TODO 同时考虑 client, netty and quasar fiber 写法
* 暂时用手写解析
*/
public class Url implements ArrayAccessBase{
private String url;
private URI aURI;
private UrlQuery query;
public Url(String url) throws UrlException{
this.url = url;
try {
aURI = new URI(url);
List<NameValuePair> list = URLEncodedUtils.parse(aURI, "UTF-8");
HashMap<String, String> parsedParameters = new HashMap<>();
for (NameValuePair pair:list) {
parsedParameters.put(pair.getName(), pair.getValue());
}
//System.out.println(list);
query = new UrlQuery(aURI.getQuery(), parsedParameters);
}catch(Exception ex) {
throw new UrlException(ex);
}
}
/**
* 包含
* query return query;
* url return url;
* queryString URI getQuery
* path URI getPath
* host URI getHost
* scheme URI getScheme
* port URI getPort
* hash|fragment 兼容(hash)
* user
* pass
* portWithDefaultValue
*/
// implements interface TODO
public boolean containsKey(Object key) {
return true;
}
// user & pass 暂时不实现 hash 即 fragment
public Object get(Object key) {
switch ((String)key) {
case "url": return url;
case "query": return query;
case "queryString": return aURI.getQuery();
case "path": return aURI.getPath();
case "host": return aURI.getHost();
case "scheme": return aURI.getScheme();
case "port": return aURI.getPort();
case "fragment": return aURI.getFragment();
case "hash": return aURI.getFragment();
case "userInfo": return aURI.getUserInfo();
}
return null;
}
/**
* @param parameters hashmap<String, String> queryparameters to merge
* @param reserveOriginalParameters Boolean whether to reserve original params
* @return A new Url Object;
*/
public Url mergeQueryParameters(HashMap<String, String> parameters, boolean reserveOriginalParameters) throws UrlException{
HashMap<String, String> originParameters = query.getParameters();
HashMap<String, String> map3 = new HashMap<>();
if (reserveOriginalParameters) {
map3.putAll(parameters);
map3.putAll(originParameters);
} else {
map3.putAll(originParameters);
map3.putAll(parameters);
}
try {
String urlStr = regenerateUrlStringWithParametersStr(map3);
return new Url(urlStr);
} catch (UnsupportedEncodingException ex) {
throw new UrlException(ex);
}
}
protected String regenerateUrlStringWithParametersStr(HashMap<String, String> map) throws UnsupportedEncodingException{
String queryString = aURI.toString().split("\\?")[0];
List<NameValuePair> queryList = new ArrayList<NameValuePair>();
for (String key:map.keySet()) {
queryList.add(new BasicNameValuePair(key, map.get(key)));
}
return queryString + "?" + URLEncodedUtils.format(queryList, UTF_8);
}
/**
* get related path
* @param urlPrefix
* @return
* @throws UrlException
*/
public String getRelatedPath(String urlPrefix) throws UrlException{
Url prefix = new Url(urlPrefix);
if (!prefix.get("host").equals(this.get("host"))) {
throw new UrlException("UrlException: failed to get related path: unmatched host. prefix["+ urlPrefix + "]; URL:[" + getUrl() + "]");
}
if (!prefix.getPortWithDefaultValue().equals(this.getPortWithDefaultValue())) {
throw new UrlException("UrlException: failed to get related path: unmatched port. prefix["+ urlPrefix + "]; URL:[" + getUrl() + "]");
}
String sourcePath = (String)this.get("path");
String prefixPath = (String)prefix.get("path");
if ("".equals(prefixPath)) {
return sourcePath;
}
if (sourcePath.indexOf(prefixPath) != 0) {
throw new UrlException("UrlException: fail to get related path. unmatched path: PREFIX[" + urlPrefix + "]; URL[" + url + "]");
}
return sourcePath.substring(prefixPath.length());
}
/**
* default port;
* if defined, return defined;
* else if has default, return default;
* else return -1;
* @return default port integer
*/
protected Integer getPortWithDefaultValue() {
Integer port = (Integer) get("port");
if (!port.equals(-1)) return port;
if (get("scheme").equals("http")) return 80;
if (get("scheme").equals("https")) return 443;
return -1;
}
public UrlQuery getQuery() {
return query;
}
public String getUrl() {
return url;
}
public URI getaURI() {
return aURI;
}
}