/**
* Path.java
*
* Copyright 2012 Niolex, Inc.
*
* Niolex licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.niolex.commons.remote;
/**
* Store the path to navigate into objects.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.0
* @since 2012-7-26
*/
public class Path {
/**
* The Path Type enumeration.
*
* @author <a href="mailto:xiejiyun@gmail.com">Xie, Jiyun</a>
* @version 1.0.5, $Date: 2012-11-23$
*/
public static enum Type {
FIELD, MAP, ARRAY, INVALID;
}
// Path Type, default to Field.
private Type type = Type.FIELD;
// Path Name, the fields name.
private String name;
// This is for Map Type.
private String key;
// This is for Array Type.
private int idx;
// The Path chain.
private Path next;
/**
* The static method to parse a Path chain from the string representation.
*
* @param strPath the string path
* @return the parsed Path chain
*/
public static Path parsePath(String strPath) {
strPath += '.';
int start = 0;
int end = 0;
int fstart = 0, fend = 0;
final Path path = new Path();
Path cur = path;
// Current parse phase, 0 - 1 - 2 - 3
// 1 means node
// 2 means array[list]
// 3 means map
int curPhase = 1;
for (int i = 0; i < strPath.length(); ++i) {
char ch = strPath.charAt(i);
switch (ch) {
case '.':
switch (curPhase) {
case 1:
end = i;
if (start < end) {
// This is not a empty node, create it.
cur.next = makePath(strPath, start, end);
cur = cur.next;
}
start = i + 1;
break;
case 3:
break;
default:
path.name = "Invalid Path at " + strPath.substring(0, i);
path.type = Type.INVALID;
return path;
}
break;
case '[':
switch (curPhase) {
case 1:
curPhase = 2;
end = i;
fstart = i + 1;
break;
case 3:
break;
default:
path.name = "Invalid Path at " + strPath.substring(0, i);
path.type = Type.INVALID;
return path;
}
break;
case ']':
switch (curPhase) {
case 3:
break;
case 2:
curPhase = 1;
fend = i;
if (start < end && fstart < fend) {
// This is a correct array node.
try {
int idx = Integer.parseInt(strPath.substring(fstart, fend));
cur.next = makePath(strPath, start, end, idx);
cur = cur.next;
start = i + 1;
break;
} catch (Exception e) {}
}
default:
path.name = "Invalid Path at " + strPath.substring(0, i);
path.type = Type.INVALID;
return path;
}
break;
case '{':
switch (curPhase) {
case 1:
curPhase = 3;
end = i;
fstart = i + 1;
break;
case 3:
break;
default:
path.name = "Invalid Path at " + strPath.substring(0, i);
path.type = Type.INVALID;
return path;
}
break;
case '}':
switch (curPhase) {
case 3:
curPhase = 1;
fend = i;
if (start < end && fstart < fend) {
// This is a correct map node.
cur.next = makePath(strPath, start, end, strPath.substring(fstart, fend));
cur = cur.next;
start = i + 1;
break;
}
default:
path.name = "Invalid Path at " + strPath.substring(0, i);
path.type = Type.INVALID;
return path;
}
break;
default:
break;
}
}// End of for.
if (curPhase != 1) {
path.name = "Invalid Path at " + strPath.substring(0, strPath.length() - 2);
path.type = Type.INVALID;
return path;
}
return path.next;
}
/**
* Make path for field section.
*
* @param strPath the string path
* @param start the field start index
* @param end the field end index
* @return the path
*/
private static Path makePath(String strPath, int start, int end) {
Path p = new Path();
p.name = strPath.substring(start, end);
return p;
}
/**
* Make path for map section.
*
* @param strPath the string path
* @param start the field start index
* @param end the field end index
* @param substring the map key
* @return the path
*/
private static Path makePath(String strPath, int start, int end, String substring) {
Path p = makePath(strPath, start, end);
p.type = Type.MAP;
p.key = substring;
return p;
}
/**
* Make path for array section.
*
* @param strPath the string path
* @param start the field start index
* @param end the field end index
* @param idx2 the array index
* @return the path
*/
private static Path makePath(String strPath, int start, int end, int idx2) {
Path p = makePath(strPath, start, end);
p.type = Type.ARRAY;
p.idx = idx2;
return p;
}
public Type getType() {
return type;
}
public String getName() {
return name;
}
public String getKey() {
return key;
}
public int getIdx() {
return idx;
}
public Path next() {
return next;
}
@Override
public String toString() {
String str = null;
switch (type) {
case FIELD:
str = "." + name;
break;
case ARRAY:
str = name + "[" + idx + "]";
break;
case MAP:
str = name + "{" + key + "}";
break;
case INVALID:
default:
str = name;
break;
}
return next == null ? str : str + " => " + next.toString();
}
}