inital commit
This commit is contained in:
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package com.reliancy.util;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
|
||||
|
||||
/** Path to a resource almost identical to a URL.
|
||||
* It might but should not hold any handles. It holds the address and
|
||||
* possibly takes care of looking up addresses.
|
||||
* The richest syntax is:
|
||||
* PROTOCOL://USER:PWD@MACHINE:PORT/DATABASE?key=val&...
|
||||
* Properties are held in their own string and need to be decoded.
|
||||
*
|
||||
* We use forward slash for path delimitation of database portion. For the rest we preserve other slashes to allow windows domain\\user or server\\instance.
|
||||
* Special chars are [/@?,:;]
|
||||
* if any are found at the end of protocol we skip ://
|
||||
* if any are found at the beginning of properties we skip ?
|
||||
* if any are found at the beginning of database we skip /
|
||||
*
|
||||
* In windows we have volume or drive letters which are postfixed by colon : then slashes. We treat the volume as part of database.
|
||||
* We store the database without first slash to allow specification of relative paths.
|
||||
* To render it as absolute set protocol or host to empty string instead of null. Then a slash will be prefixed and you will get absolute path.
|
||||
* @author amer
|
||||
*/
|
||||
public class Path {
|
||||
static final String SYMBOLS="/@?,:;";
|
||||
String connectstring;
|
||||
String protocol; ///< protocol guides the interpretation of the other elements in conn, string
|
||||
String userid; ///< authentication
|
||||
String password; ///< authorization
|
||||
String host; ///< machine or computer
|
||||
String port; ///< access to computer
|
||||
String database; ///< name of database or filename
|
||||
String properties; ///< properties are what follows ? in a url
|
||||
|
||||
public Path(String connect) {
|
||||
setConnectString(connect);
|
||||
}
|
||||
|
||||
public Path(Path in) {
|
||||
connectstring=in.connectstring;
|
||||
protocol=in.protocol;
|
||||
userid=in.userid;
|
||||
password=in.password;
|
||||
host=in.host;
|
||||
port=in.port;
|
||||
database=in.database;
|
||||
properties=in.properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getConnectString();
|
||||
}
|
||||
/**
|
||||
* Converts the path to a file.
|
||||
* If absolute is true
|
||||
* @param absolute if true forms absolute path else will return relative path
|
||||
* @return
|
||||
*/
|
||||
public File toFile(boolean absolute){
|
||||
String proto=getProtocol();
|
||||
String host=getHost();
|
||||
try{
|
||||
setProtocol(absolute?"":null);
|
||||
setHost(absolute?"":null);
|
||||
String path=toString();
|
||||
return new File(path);
|
||||
}finally{
|
||||
setProtocol(proto);
|
||||
setHost(host);
|
||||
}
|
||||
}
|
||||
public URL toURL() throws MalformedURLException{
|
||||
String path=toString();
|
||||
if(Handy.isBlank(getHost()) && path.contains("://") && !path.contains(":///")) path=path.replace("://",":///");
|
||||
return new URL(path);
|
||||
}
|
||||
public void clear(){
|
||||
connectstring=null;
|
||||
protocol=null;
|
||||
userid=null;
|
||||
password=null;
|
||||
host=null;
|
||||
port=null;
|
||||
database=null;
|
||||
properties=null;
|
||||
}
|
||||
|
||||
public String getConnectString() {
|
||||
if(connectstring!=null) return connectstring;
|
||||
// assemble the connect string
|
||||
StringBuilder buf=new StringBuilder();
|
||||
//boolean absolute=false;
|
||||
if(!Handy.isBlank(protocol)){
|
||||
buf.append(protocol);
|
||||
if(SYMBOLS.indexOf(protocol.charAt(protocol.length()-1))<0) buf.append("://");
|
||||
}
|
||||
if(!Handy.isBlank(host)){
|
||||
if(userid!=null && password!=null){
|
||||
buf.append(userid).append(":").append(password).append("@");
|
||||
}
|
||||
buf.append(host);
|
||||
if(port!=null) buf.append(":").append(port);
|
||||
}
|
||||
if(!Handy.isBlank(database)){
|
||||
if(buf.length()>0 && SYMBOLS.indexOf(database.charAt(0))<0){
|
||||
// we got something in front so we need to use slash
|
||||
buf.append("/");
|
||||
}else if(protocol!=null || host!=null){
|
||||
boolean winvol=database.length()>2 && database.charAt(1)==':' && (database.charAt(2)=='/' || database.charAt(2)=='\\');
|
||||
// we got nothing in front but if host or protocol empty but not null we treat as absolute
|
||||
if(!winvol) buf.append("/");
|
||||
}
|
||||
buf.append(database);
|
||||
}
|
||||
if(properties!=null){
|
||||
if(SYMBOLS.indexOf(properties.charAt(0))<0) buf.append("?");
|
||||
buf.append(properties);
|
||||
}
|
||||
connectstring=buf.toString();
|
||||
return connectstring;
|
||||
}
|
||||
|
||||
public void setConnectString(String connect) {
|
||||
clear();
|
||||
if (connect == null) {
|
||||
return;
|
||||
}
|
||||
this.connectstring=connect;
|
||||
// first get protocol - everything up to : which is not followed by a symbol (includes :// but also c:/
|
||||
int oldst=0;
|
||||
int st=0;
|
||||
for(int i=0;i<(connectstring.length()-1);i++){
|
||||
char curr=connectstring.charAt(i);
|
||||
if(curr==':'){
|
||||
oldst=st;
|
||||
st=i;
|
||||
}else if(SYMBOLS.indexOf(curr)!=-1){
|
||||
if(curr=='@') st=oldst; // this will back out one : if protocl search ended with @ indicating a server
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(st==1){ st=0;} // this will supress single letter protocols i.e. c:/ ued in windows as part of database/file
|
||||
if(2==(st-oldst)) st=oldst;
|
||||
if(st>0){
|
||||
this.protocol=connectstring.substring(0,st);
|
||||
while(SYMBOLS.indexOf(connectstring.charAt(st))!=-1) st++; // advance over symbols
|
||||
}
|
||||
// next assume the rest is a file/database
|
||||
database = connectstring.substring(st);
|
||||
// now check for user id and password
|
||||
st = database.indexOf('@');
|
||||
boolean checkhost=st>=0;
|
||||
if(!Handy.isBlank(protocol)){
|
||||
checkhost=!protocol.contains(":file") && !protocol.contains(":mem") && !protocol.equals("file") && !protocol.equals("mem");;
|
||||
}
|
||||
if (st != -1) {
|
||||
userid = database.substring(0, st);
|
||||
if(userid.contains("%4")) try{userid=URLDecoder.decode(userid,"UTF-8");}catch(Exception e){}
|
||||
database = database.substring(st + 1);
|
||||
// now try to split user id into password if possible
|
||||
st = userid.indexOf(':');
|
||||
if (st != -1) {
|
||||
password = userid.substring(st + 1);
|
||||
userid = userid.substring(0, st);
|
||||
}
|
||||
}
|
||||
// ok next try to split up machine if possible (only for absolute urls)
|
||||
st = database.indexOf(':');
|
||||
if(st<0) st=database.indexOf('/');
|
||||
if (st != -1 && checkhost) {
|
||||
boolean portfollows=database.charAt(st)==':';
|
||||
host = database.substring(0, st);
|
||||
// now try to recover port
|
||||
if(portfollows){
|
||||
int st2 = database.indexOf(':',st+1);
|
||||
if(st2<0) st2 = database.indexOf('/',st+1);
|
||||
if (st2 != -1 && st2>(st+1)) { // we have a port
|
||||
port = database.substring(st + 1,st2);
|
||||
st=st2;
|
||||
}else{
|
||||
// no port we have : then / - which is used in windows to indicate volume and we treat as part of database
|
||||
st=-1;
|
||||
host="";
|
||||
}
|
||||
}
|
||||
database = database.substring(st + 1);
|
||||
}
|
||||
database=fixSlashes(database);
|
||||
// finally split the properties from database
|
||||
st = database.indexOf('?');
|
||||
if(st==-1) st=database.indexOf(';');
|
||||
if (st != -1) { // we have properties
|
||||
properties = database.substring(st);
|
||||
database = database.substring(0, st);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute ResourcePath will have a protocol
|
||||
*/
|
||||
public boolean isAbsolute() {
|
||||
return (protocol != null || host!=null);
|
||||
}
|
||||
/// will clear host and protocol using empty string thereby making database absolute path
|
||||
public Path setAbsolute(){
|
||||
setHost("");
|
||||
setProtocol("");
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
public Path setDatabase(String database) {
|
||||
this.database = database;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public Path setHost(String host) {
|
||||
this.host = host;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public Path setPassword(String password) {
|
||||
this.password = password;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public Path setPort(String port) {
|
||||
this.port = port;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public Path setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUserid() {
|
||||
return userid;
|
||||
}
|
||||
|
||||
public Path setUserid(String userid) {
|
||||
this.userid = userid;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
public String getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public Path setProperties(String userid) {
|
||||
this.properties = userid;
|
||||
connectstring=null;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String getBase() {
|
||||
return Path.getBase(database);
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return Path.getExtension(database);
|
||||
}
|
||||
|
||||
public String getPathItem() {
|
||||
return Path.getPathItem(database);
|
||||
}
|
||||
|
||||
/** Ensures that we use forward slashes and that single dot is not present mid or and the end.
|
||||
*
|
||||
* @param path a unix or windows or uri path
|
||||
* @return a path with forward slashes
|
||||
*/
|
||||
public static String fixSlashes(String path) {
|
||||
if(path==null || path.length()==0) return path;
|
||||
path=path.replace("\\", "/");
|
||||
path=path.replace("/./","/");
|
||||
while(true){
|
||||
if(path.endsWith("/")) path=path.substring(0,path.length()-1);
|
||||
else if(path.endsWith("/.")) path=path.substring(0,path.length()-2);
|
||||
else break;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/** returns database path given path and file.
|
||||
* We assume the path uses forward backslash for delimitation.
|
||||
*/
|
||||
public static String getBase(String path) {
|
||||
int st1 = path.lastIndexOf('/');
|
||||
int st2 = path.lastIndexOf('\\');
|
||||
int st=st2>st1?st2:st1;
|
||||
if (st == -1) {
|
||||
return null;
|
||||
}
|
||||
return path.substring(0, st);
|
||||
}
|
||||
|
||||
public static String getExtension(String path) {
|
||||
int st=Math.max(path.lastIndexOf('/'),path.lastIndexOf('\\'));
|
||||
int st2 = path.lastIndexOf('.');
|
||||
if (st2 == -1 || (st>0 && st2<st)) {
|
||||
return null;
|
||||
}
|
||||
return path.substring(st2 + 1);
|
||||
}
|
||||
|
||||
public static String getPathItem(String path) {
|
||||
path=path.replace('\\','/');
|
||||
int st11 = path.lastIndexOf('/');
|
||||
int st1=1+st11;
|
||||
int st2 = path.lastIndexOf('.');
|
||||
if (st2 <0) {
|
||||
st2 = path.length();
|
||||
}
|
||||
return path.substring(st1, st2);
|
||||
}
|
||||
/**
|
||||
* Assuming that url starts with base will return string beyond base in url.
|
||||
* @param base
|
||||
* @param url
|
||||
*/
|
||||
public static String getRemainder(String base,String url){
|
||||
if(base.length()>=url.length()) return null;
|
||||
return url.substring(base.length());
|
||||
}
|
||||
/**
|
||||
* unites two paths.
|
||||
* @param base
|
||||
* @param url
|
||||
*/
|
||||
public static String getUnion(String base,String url){
|
||||
if(base==null || base.isEmpty()){
|
||||
return url;
|
||||
}
|
||||
if(url==null || url.isEmpty()){
|
||||
return base;
|
||||
}
|
||||
//if(url.startsWith(base)) return url;
|
||||
if(Handy.indexOf(url,base,0)==0) return url;
|
||||
StringBuilder ret=new StringBuilder();
|
||||
ret.append(base);
|
||||
if(!base.endsWith("/") && !url.startsWith("/")) ret.append("/");
|
||||
if(base.endsWith("/") && url.startsWith("/")) ret.setLength(ret.length()-1);
|
||||
ret.append(url);
|
||||
return ret.toString();
|
||||
}
|
||||
/**
|
||||
* method will split paths used in linux and windows.
|
||||
* in particular for windows it checks if a single letter precedes a colon in which case it considers it a volume
|
||||
* and does not split there.
|
||||
* @param paths paths joined with colon or semi-colon
|
||||
* @return array of paths
|
||||
*/
|
||||
public static String[] splitPaths(String _paths){
|
||||
String[] paths=_paths.replaceAll("(;|:|^)([a-zA-Z]):","$1$2##").split("[:;]");
|
||||
for (int i = 0; i < paths.length; i++) {
|
||||
String path=paths[i];
|
||||
path = path.replace("##",":");
|
||||
path=path.replace("/./","/");
|
||||
path=path.replace("//","/");
|
||||
path=path.replace("\\.\\","\\");
|
||||
path=path.replace("\\\\","\\");
|
||||
paths[i]=path;
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of key,value pairs in the order they occur in the string str.
|
||||
* @param str
|
||||
*/
|
||||
public static String[] splitProperties(String str) {
|
||||
if(str.startsWith("?")) str=str.substring(1);
|
||||
if(str.startsWith(";")) str=str.substring(1);
|
||||
return str.split("&");
|
||||
}
|
||||
public static String[] splitKeyValue(String str) {
|
||||
String[] t=str.split("=");
|
||||
if(t==null || t.length==0) return null;
|
||||
t[0]=Handy.trim(t[0],"'\"");
|
||||
return t;
|
||||
}
|
||||
public static String[] split(String str) {
|
||||
return str.split("/");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user