SnmpRelativeOid.java
package eu.linuxengineering.snmp;
import java.util.Arrays;
import org.opennms.protocols.snmp.SnmpObjectId;
import eu.javaexperience.parse.ParsePrimitive;
import eu.javaexperience.regex.RegexTools;
import net.sf.snmpadaptor4j.object.SnmpOid;
public class SnmpRelativeOid
{
/**
* -3: `from the root` element (eg: /)
* -2: current element (eg.: ./)
* -1: backward (eg.: ../)
* 0 and greater: valid oid elements
* */
protected int[] path;
public SnmpRelativeOid(int[] path)
{
this.path = path;
}
public int[] getPathComponents()
{
return path;
}
public SnmpOid resolve(SnmpOid oid)
{
if(isStatic())
{
return SnmpOid.newInstance(Arrays.copyOfRange(path, 1, path.length));
}
int[] p = oid.getOid();
int ep = p.length;
p = Arrays.copyOf(p, ep+path.length);
for(int i=0;i<path.length;++i)
{
int el = path[i];
if(PATH_CURRENT_ELEMENT == el)
{
continue;
}
else if(PATH_BACKWARD == el)
{
--ep;
}
else
{
p[ep++] = el;
}
}
return SnmpOid.newInstance(Arrays.copyOf(p, ep));
}
public boolean isStatic()
{
if(path[0] != PATH_FROM_ROOT)
{
return false;
}
for(int i=0;i<path.length;++i)
{
if(path[i] == PATH_BACKWARD)
{
return false;
}
}
return true;
}
public static final int PATH_FROM_ROOT = -3;
public static final int PATH_CURRENT_ELEMENT = -2;
public static final int PATH_BACKWARD = -1;
/**
* OID as file path expression looks like:
* ram free on linux: /1/3/6/1/4/1/2021/4/11/0
*
* this may contain back steps like:
* /1/3/6/10/../1
* in this case the 10 is wiped out becuse of back step likely in the
* filesystem operations
*
* it may contain back steps like:
* ./../10
* which can be resolved only relatively to a given node
* (in filesystem analogy for extample relatively to the current working
* directory)
* */
public static int[] parseAsFilePathExpression(String path)
{
path = path.trim();
if("/".equals(path))
{
return new int[]{PATH_FROM_ROOT};
}
String[] components = RegexTools.SLASHES.split(path);
int[] ret = new int[components.length+1];
int ep = 0;
for(int i=0;i<components.length;++i)
{
String comp = components[i];
if(0 == i && "".equals(comp))
{
ret[ep++] = PATH_FROM_ROOT;
}
else if(".".equals(comp))
{
if(0 == i)
{
ret[ep++] = PATH_CURRENT_ELEMENT;
}
//skip intermediate . elements like: 1/./././4 => 1/4
}
else if("..".equals(comp))
{
//pop out the previous non relative expression
if(ep > 0)
{
//eg "/../../../../../" this resolves to "/"
if(PATH_FROM_ROOT == ret[ep-1])//only occures when 0 == ep
{
continue;
}
else if(ret[ep-1] >= 0)
{
--ep;
continue;
}
else if(ret[ep-1] == PATH_CURRENT_ELEMENT)
{
--ep;
}
}
ret[ep++] = PATH_BACKWARD;
}
else
{
int val = ParsePrimitive.tryParseInt(comp, Integer.MIN_VALUE);
if(val == Integer.MIN_VALUE || val < 0)
{
throw new RuntimeException("Illegal path element `"+comp+"` at location `"+i+"` in path expression: `"+path+"`");
}
ret[ep++] = val;
}
}
return Arrays.copyOf(ret, ep);
}
public String renderPath()
{
StringBuilder sb = new StringBuilder();
for(int i=0;i<path.length;++i)
{
int el = path[i];
if(sb.length() > 0 || (1 == i && PATH_FROM_ROOT == path[0]))
{
sb.append("/");
}
if(PATH_FROM_ROOT == el)
{
continue;
}
if(PATH_CURRENT_ELEMENT == el)
{
sb.append(".");
}
else if(PATH_BACKWARD == el)
{
sb.append("..");
}
else
{
sb.append(el);
}
}
return sb.toString();
}
@Override
public String toString()
{
return "SnmpRelativeOid: "+renderPath();
}
public static SnmpRelativeOid parse(String path)
{
return new SnmpRelativeOid(parseAsFilePathExpression(path));
}
}