-package org.simantics.db.layer0.variable;\r
-\r
-import java.util.Arrays;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.Databoard;\r
-import org.simantics.databoard.annotations.Union;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.util.Bean;\r
-import org.simantics.databoard.util.URIStringUtils;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.RequestProcessor;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.request.UniqueRead;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.AdaptionException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.layer0.variable.Variables.Role;\r
-import org.simantics.db.service.SerialisationSupport;\r
-import org.simantics.layer0.Layer0;\r
-\r
-/**\r
- * Relative Value Indicator is a parent-child reference inside variable-tree \r
- * address space. \r
- * \r
- * @See RVIBuilder\r
- * @author toni.kalajainen\r
- */\r
-public class RVI extends Bean {\r
- \r
- private static final RVIPart[] NONE = {};\r
- \r
- public RVIPart[] parts;\r
- \r
- public RVI() {\r
- super();\r
- }\r
- \r
- public RVI(Binding rviBinding) {\r
- super(rviBinding);\r
- }\r
- \r
- public static RVI empty(Binding rviBinding) {\r
- RVI result = new RVI(rviBinding);\r
- result.parts = NONE;\r
- return result;\r
- }\r
- \r
- public boolean isEmpty() {\r
- return parts.length == 0;\r
- }\r
- \r
- public Variable resolve(ReadGraph graph, Variable base) throws DatabaseException {\r
- for(RVIPart part : parts) {\r
- base = base.resolve(graph, part);\r
- }\r
- return base;\r
- }\r
-\r
- public Variable resolvePossible(ReadGraph graph, Variable base) throws DatabaseException {\r
- for(RVIPart part : parts) {\r
- base = base.resolvePossible(graph, part);\r
- if (base == null)\r
- return null;\r
- }\r
- return base;\r
- }\r
-\r
- @Override\r
- public int hashCode() {\r
- return Arrays.hashCode(parts);\r
- }\r
-\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- RVI other = (RVI) obj;\r
- return Arrays.equals(parts, other.parts);\r
- }\r
-\r
- /**\r
- * Returns a string representation of the all the parts of this RVI for\r
- * visualization purposes. This representation of the RVI does not withstand\r
- * moving the RVI-referenced resource between model composites unlike the\r
- * databoard serialization of this class.\r
- * \r
- * <p>\r
- * Implementation takes the RVI part of a Variable resolved using this RVI\r
- * and the specified Variable as a base for the resolution.\r
- * \r
- * @param graph transaction handle\r
- * @param base base resource to use for resolving the variable\r
- * @return this RVI as a String\r
- * @throws DatabaseException\r
- */\r
- public String asString(ReadGraph graph, Variable base) throws DatabaseException {\r
- String baseURI = base.getURI(graph);\r
- Variable resolved = resolve(graph, base);\r
- return resolved.getURI(graph).substring(baseURI.length());\r
- }\r
-\r
- public UniqueRead<String> asStringRequest(final Resource base) {\r
- return new UniqueRead<String>() {\r
- @Override\r
- public String perform(ReadGraph graph) throws DatabaseException {\r
- Variable v = Variables.getConfigurationContext(graph, base);\r
- return asString(graph, v);\r
- }\r
- };\r
- }\r
-\r
- /**\r
- * Works like {@link #asString(ReadGraph, Variable)} but returns\r
- * <code>null</code> if resolution of the string form fails because of the\r
- * database contents.\r
- * \r
- * @param graph transaction handle\r
- * @param base base resource to use for resolving the variable\r
- * @return this RVI as a String\r
- * @throws DatabaseException\r
- */\r
- public String asPossibleString(ReadGraph graph, Variable base) throws DatabaseException {\r
- try {\r
- return asString(graph, base);\r
- } catch (DatabaseException e) {\r
- return null;\r
- }\r
- }\r
-\r
- /**\r
- * Print as persistent string\r
- */\r
- @Override\r
- public String toString() {\r
- StringBuilder sb = new StringBuilder();\r
- for (RVIPart p : parts) {\r
- if (p instanceof ResourceRVIPart) {\r
- sb.append(p.toString());\r
- } else if (p instanceof StringRVIPart) {\r
- sb.append(((StringRVIPart) p).toEscapedString());\r
- } else if (p instanceof GuidRVIPart) {\r
- sb.append(((GuidRVIPart) p).toEscapedString());\r
- }\r
- }\r
- return sb.toString();\r
- }\r
-\r
- /**\r
- * Resolves this RVI into a string with a best effort method that tries to\r
- * resolve the RVI parts into variables for as long as it can. After\r
- * resolution is finished the remaining RVI parts are simply concatenated\r
- * into the result string as strings without resolving them into variables.\r
- * This is different from {@link #asString(ReadGraph, Variable)} or\r
- * {@link #asPossibleString(ReadGraph, Variable)} in that it doesn't demand\r
- * that the RVI resolves completely. Still at least the first RVI part must\r
- * resolve, otherwise <code>null</code> is returned, since this means that\r
- * the variable no longer exists at all.\r
- * \r
- * @param graph\r
- * database read handle\r
- * @param base\r
- * the base of resolution for the RVI\r
- * @return The RVI of the referenced entity as a string or <code>null</code>\r
- * if zero parts of this RVI can be resolved, i.e. the resources\r
- * referenced by it no longer exist.\r
- * @throws DatabaseException\r
- */\r
- public String toPossibleString(ReadGraph graph, Variable base) throws DatabaseException {\r
- String baseURI = base.getURI(graph);\r
-\r
- Variable resolved = null;\r
- int i = 0;\r
- for (; i < parts.length; ++i) {\r
- RVIPart p = parts[i];\r
- base = base.resolvePossible(graph, p);\r
- if (base == null)\r
- break;\r
- resolved = base;\r
- }\r
- if (resolved == null)\r
- return null;\r
-\r
- StringBuilder sb = new StringBuilder();\r
- String resolvedURI = resolved.getURI(graph);\r
- sb.append(resolvedURI, baseURI.length(), resolvedURI.length());\r
- if (i < parts.length) {\r
- // The tail didn't resolve into a Variable synchronously\r
- // so let's just concatenate the rest by hand into the\r
- // result string.\r
- Layer0 L0 = Layer0.getInstance(graph);\r
- for (; i < parts.length; ++i) {\r
- RVIPart p = parts[i];\r
- if (p instanceof ResourceRVIPart) {\r
- Resource r = ((ResourceRVIPart) p).resource;\r
- String str = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);\r
- if (str == null)\r
- return null;\r
- sb.append(p.getRole().getIdentifier()).append(URIStringUtils.escape(str));\r
- } else if (p instanceof StringRVIPart) {\r
- sb.append(p.getRole().getIdentifier()).append(URIStringUtils.escape(((StringRVIPart) p).string));\r
- } else if (p instanceof GuidRVIPart) {\r
- sb.append(p.getRole().getIdentifier()).append(((GuidRVIPart)p).mostSignificant).append(":").append(((GuidRVIPart)p).leastSignificant);\r
- }\r
- }\r
- }\r
-\r
- return sb.toString();\r
- }\r
-\r
- /**\r
- * Print for USER. Not the real RVI\r
- * \r
- * @param graph\r
- * @return\r
- * @throws AdaptionException\r
- * @throws ValidationException\r
- * @throws ServiceException\r
- */\r
- public String toString(ReadGraph graph) throws DatabaseException {\r
- StringBuilder sb = new StringBuilder();\r
- for (RVIPart p : parts) {\r
- if (p instanceof ResourceRVIPart) {\r
- Resource r = ((ResourceRVIPart) p).resource;\r
- String str = NameUtils.getSafeName(graph, r);\r
- sb.append(p.getRole().getIdentifier()).append(str);\r
- } else if (p instanceof StringRVIPart) {\r
- String str = p.toString();\r
- sb.append(str);\r
- } else if (p instanceof GuidRVIPart) {\r
- String str = p.toString();\r
- sb.append(str);\r
- }\r
- }\r
- return sb.toString();\r
- }\r
- \r
- // Enumeration | ResourceRVIPart | StringRVIPart | GuidRVIPart\r
- @Union({ResourceRVIPart.class, StringRVIPart.class, GuidRVIPart.class})\r
- public static interface RVIPart { public Role getRole(); }\r
- \r
- public static class ResourceRVIPart implements RVIPart {\r
- public Role role;\r
- public Resource resource;\r
- @Override\r
- public Role getRole() {\r
- return role;\r
- }\r
- public ResourceRVIPart() {}\r
- public ResourceRVIPart(Role role, Resource resource) {\r
- if (resource == null)\r
- throw new NullPointerException("null resource");\r
- this.role = role;\r
- this.resource = resource;\r
- }\r
- @Override\r
- public String toString() {\r
- return role.getIdentifier()+"r"+Long.toString( resource.getResourceId() );\r
- }\r
- @Override\r
- public int hashCode() {\r
- return resource.hashCode() * 31 + role.hashCode();\r
- }\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- ResourceRVIPart other = (ResourceRVIPart) obj;\r
- return role == other.role && resource.equals(other.resource);\r
- }\r
- }\r
- \r
- public static class StringRVIPart implements RVIPart {\r
- public Role role;\r
- public String string;\r
- @Override\r
- public Role getRole() {\r
- return role;\r
- }\r
- public StringRVIPart() {}\r
- public StringRVIPart(Role role, String string) {\r
- if (string == null)\r
- throw new NullPointerException("null string");\r
- this.role = role;\r
- this.string = string;\r
- }\r
- @Override\r
- public String toString() {\r
- return role.getIdentifier()+string;\r
- }\r
- public String toEscapedString() {\r
- return role.getIdentifier()+URIStringUtils.escape(string);\r
- }\r
- @Override\r
- public int hashCode() {\r
- return string.hashCode() * 31 + role.hashCode();\r
- }\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- StringRVIPart other = (StringRVIPart) obj;\r
- return role == other.role && string.equals(other.string);\r
- }\r
- }\r
-\r
- public static class GuidRVIPart implements RVIPart {\r
- public Role role;\r
- public long mostSignificant;\r
- public long leastSignificant;\r
- public transient Resource resource;\r
- @Override\r
- public Role getRole() {\r
- return role;\r
- }\r
- public GuidRVIPart() {}\r
- public GuidRVIPart(Role role, Resource resource, long mostSignificant, long leastSignificant) {\r
- this.role = role;\r
- this.resource = resource;\r
- this.mostSignificant = mostSignificant;\r
- this.leastSignificant = leastSignificant;\r
- }\r
- @Override\r
- public String toString() {\r
- return role.getIdentifier()+mostSignificant+":"+leastSignificant;\r
- }\r
- public String toEscapedString() {\r
- String rid = resource != null ? Long.toString( resource.getResourceId() ) : "0";\r
- return role.getIdentifier()+mostSignificant+":"+leastSignificant+":"+rid;\r
- }\r
- @Override\r
- public int hashCode() {\r
- return (longHashCode(leastSignificant) * 51 + longHashCode(mostSignificant)) * 31 + role.hashCode();\r
- }\r
- /*\r
- * TODO: remove this when switched into Java 1.8\r
- */\r
- private static int longHashCode(long value) {\r
- return (int)(value ^ (value >>> 32));\r
- }\r
-\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- GuidRVIPart other = (GuidRVIPart) obj;\r
- return role == other.role && leastSignificant == other.leastSignificant && mostSignificant == other.mostSignificant;\r
- }\r
- \r
- }\r
-\r
- public static RVI fromResourceFormat( RequestProcessor proc, String str ) {\r
- SerialisationSupport support = proc.getService(SerialisationSupport.class);\r
- if (support == null) throw new RuntimeException("No serialization support in Session");\r
- Databoard databoard = proc.getService(Databoard.class);\r
- if (databoard == null) throw new RuntimeException("No databoard support in Session");\r
- \r
- Binding rviBinding = databoard.getBindingUnchecked( RVI.class );\r
- RVIBuilder rb = new RVIBuilder( rviBinding );\r
- int pos = 0, len = str.length();\r
- while (pos<str.length()) {\r
- Role role = null;\r
- char c = str.charAt(pos);\r
- if (c=='#') {\r
- pos++;\r
- role = Role.PROPERTY;\r
- } else if (c=='/') {\r
- pos++;\r
- role = Role.CHILD;\r
- } else {\r
- role = Role.CHILD;\r
- }\r
- int e1 = str.indexOf('#', pos);\r
- int e2 = str.indexOf('/', pos);\r
- e1 = e1<0?len:e1;\r
- e2 = e2<0?len:e2;\r
- int end = e1<e2?e1:e2;\r
- if (str.charAt(pos) == 'r') {\r
- String x = str.substring(pos+1, end);\r
- if (!x.isEmpty()) {\r
- try {\r
- long res = (int) Long.parseLong(x);\r
- Resource r = support.getResource( res );\r
- rb.append( role, r );\r
- pos = end;\r
- continue;\r
- } catch (NumberFormatException nfe) {\r
- } catch (DatabaseException e) {\r
- }\r
- }\r
- }\r
- if (str.indexOf(":", pos+1) > -1) {\r
- String x = str.substring(pos+1, end);\r
- if (!x.isEmpty()) {\r
- String[] parts = x.split(":");\r
- if (parts.length == 3) {\r
- try {\r
- long res = (int) Long.parseLong(parts[2]);\r
- long mostSignificant = Long.parseLong(parts[0]);\r
- long leastSignificant = Long.parseLong(parts[1]);\r
- Resource r = support.getResource( res );\r
- rb.append( role, r, mostSignificant, leastSignificant);\r
- pos = end;\r
- continue;\r
- } catch (NumberFormatException nfe) {\r
- } catch (DatabaseException e) {\r
- }\r
- }\r
- }\r
- }\r
- String text = URIStringUtils.unescape( str.substring(pos, end) );\r
- pos = end;\r
- rb.append( role, text );\r
- }\r
- return rb.toRVI();\r
- }\r
- \r
-}\r
+package org.simantics.db.layer0.variable;
+
+import java.util.Arrays;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.Databoard;
+import org.simantics.databoard.annotations.Union;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.util.Bean;
+import org.simantics.databoard.util.URIStringUtils;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.AdaptionException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.layer0.variable.Variables.Role;
+import org.simantics.db.service.SerialisationSupport;
+import org.simantics.layer0.Layer0;
+
+/**
+ * Relative Value Indicator is a parent-child reference inside variable-tree
+ * address space.
+ *
+ * @See RVIBuilder
+ * @author toni.kalajainen
+ */
+public class RVI extends Bean {
+
+ private static final RVIPart[] NONE = {};
+
+ public RVIPart[] parts;
+
+ public RVI() {
+ super();
+ }
+
+ public RVI(Binding rviBinding) {
+ super(rviBinding);
+ }
+
+ public static RVI empty(Binding rviBinding) {
+ RVI result = new RVI(rviBinding);
+ result.parts = NONE;
+ return result;
+ }
+
+ public boolean isEmpty() {
+ return parts.length == 0;
+ }
+
+ public Variable resolve(ReadGraph graph, Variable base) throws DatabaseException {
+ for(RVIPart part : parts) {
+ base = base.resolve(graph, part);
+ }
+ return base;
+ }
+
+ public Variable resolvePossible(ReadGraph graph, Variable base) throws DatabaseException {
+ for(RVIPart part : parts) {
+ base = base.resolvePossible(graph, part);
+ if (base == null)
+ return null;
+ }
+ return base;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(parts);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ RVI other = (RVI) obj;
+ return Arrays.equals(parts, other.parts);
+ }
+
+ /**
+ * Returns a string representation of the all the parts of this RVI for
+ * visualization purposes. This representation of the RVI does not withstand
+ * moving the RVI-referenced resource between model composites unlike the
+ * databoard serialization of this class.
+ *
+ * <p>
+ * Implementation takes the RVI part of a Variable resolved using this RVI
+ * and the specified Variable as a base for the resolution.
+ *
+ * @param graph transaction handle
+ * @param base base resource to use for resolving the variable
+ * @return this RVI as a String
+ * @throws DatabaseException
+ */
+ public String asString(ReadGraph graph, Variable base) throws DatabaseException {
+ String baseURI = base.getURI(graph);
+ Variable resolved = resolve(graph, base);
+ return resolved.getURI(graph).substring(baseURI.length());
+ }
+
+ public UniqueRead<String> asStringRequest(final Resource base) {
+ return new UniqueRead<String>() {
+ @Override
+ public String perform(ReadGraph graph) throws DatabaseException {
+ Variable v = Variables.getConfigurationContext(graph, base);
+ return asString(graph, v);
+ }
+ };
+ }
+
+ /**
+ * Works like {@link #asString(ReadGraph, Variable)} but returns
+ * <code>null</code> if resolution of the string form fails because of the
+ * database contents.
+ *
+ * @param graph transaction handle
+ * @param base base resource to use for resolving the variable
+ * @return this RVI as a String
+ * @throws DatabaseException
+ */
+ public String asPossibleString(ReadGraph graph, Variable base) throws DatabaseException {
+ try {
+ return asString(graph, base);
+ } catch (DatabaseException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Print as persistent string
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (RVIPart p : parts) {
+ if (p instanceof ResourceRVIPart) {
+ sb.append(p.toString());
+ } else if (p instanceof StringRVIPart) {
+ sb.append(((StringRVIPart) p).toEscapedString());
+ } else if (p instanceof GuidRVIPart) {
+ sb.append(((GuidRVIPart) p).toEscapedString());
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Resolves this RVI into a string with a best effort method that tries to
+ * resolve the RVI parts into variables for as long as it can. After
+ * resolution is finished the remaining RVI parts are simply concatenated
+ * into the result string as strings without resolving them into variables.
+ * This is different from {@link #asString(ReadGraph, Variable)} or
+ * {@link #asPossibleString(ReadGraph, Variable)} in that it doesn't demand
+ * that the RVI resolves completely. Still at least the first RVI part must
+ * resolve, otherwise <code>null</code> is returned, since this means that
+ * the variable no longer exists at all.
+ *
+ * @param graph
+ * database read handle
+ * @param base
+ * the base of resolution for the RVI
+ * @return The RVI of the referenced entity as a string or <code>null</code>
+ * if zero parts of this RVI can be resolved, i.e. the resources
+ * referenced by it no longer exist.
+ * @throws DatabaseException
+ */
+ public String toPossibleString(ReadGraph graph, Variable base) throws DatabaseException {
+ String baseURI = base.getURI(graph);
+
+ Variable resolved = null;
+ int i = 0;
+ for (; i < parts.length; ++i) {
+ RVIPart p = parts[i];
+ base = base.resolvePossible(graph, p);
+ if (base == null)
+ break;
+ resolved = base;
+ }
+ if (resolved == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder();
+ String resolvedURI = resolved.getURI(graph);
+ sb.append(resolvedURI, baseURI.length(), resolvedURI.length());
+ if (i < parts.length) {
+ // The tail didn't resolve into a Variable synchronously
+ // so let's just concatenate the rest by hand into the
+ // result string.
+ Layer0 L0 = Layer0.getInstance(graph);
+ for (; i < parts.length; ++i) {
+ RVIPart p = parts[i];
+ if (p instanceof ResourceRVIPart) {
+ Resource r = ((ResourceRVIPart) p).resource;
+ String str = graph.getPossibleRelatedValue(r, L0.HasName, Bindings.STRING);
+ if (str == null)
+ return null;
+ sb.append(p.getRole().getIdentifier()).append(URIStringUtils.escape(str));
+ } else if (p instanceof StringRVIPart) {
+ sb.append(p.getRole().getIdentifier()).append(URIStringUtils.escape(((StringRVIPart) p).string));
+ } else if (p instanceof GuidRVIPart) {
+ sb.append(p.getRole().getIdentifier()).append(((GuidRVIPart)p).mostSignificant).append(":").append(((GuidRVIPart)p).leastSignificant);
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Print for USER. Not the real RVI
+ *
+ * @param graph
+ * @return
+ * @throws AdaptionException
+ * @throws ValidationException
+ * @throws ServiceException
+ */
+ public String toString(ReadGraph graph) throws DatabaseException {
+ StringBuilder sb = new StringBuilder();
+ for (RVIPart p : parts) {
+ if (p instanceof ResourceRVIPart) {
+ Resource r = ((ResourceRVIPart) p).resource;
+ String str = NameUtils.getSafeName(graph, r);
+ sb.append(p.getRole().getIdentifier()).append(str);
+ } else if (p instanceof StringRVIPart) {
+ String str = p.toString();
+ sb.append(str);
+ } else if (p instanceof GuidRVIPart) {
+ String str = p.toString();
+ sb.append(str);
+ }
+ }
+ return sb.toString();
+ }
+
+ // Enumeration | ResourceRVIPart | StringRVIPart | GuidRVIPart
+ @Union({ResourceRVIPart.class, StringRVIPart.class, GuidRVIPart.class})
+ public static interface RVIPart { public Role getRole(); }
+
+ public static class ResourceRVIPart implements RVIPart {
+ public Role role;
+ public Resource resource;
+ @Override
+ public Role getRole() {
+ return role;
+ }
+ public ResourceRVIPart() {}
+ public ResourceRVIPart(Role role, Resource resource) {
+ if (resource == null)
+ throw new NullPointerException("null resource");
+ this.role = role;
+ this.resource = resource;
+ }
+ @Override
+ public String toString() {
+ return role.getIdentifier()+"r"+Long.toString( resource.getResourceId() );
+ }
+ @Override
+ public int hashCode() {
+ return resource.hashCode() * 31 + role.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ResourceRVIPart other = (ResourceRVIPart) obj;
+ return role == other.role && resource.equals(other.resource);
+ }
+ }
+
+ public static class StringRVIPart implements RVIPart {
+ public Role role;
+ public String string;
+ @Override
+ public Role getRole() {
+ return role;
+ }
+ public StringRVIPart() {}
+ public StringRVIPart(Role role, String string) {
+ if (string == null)
+ throw new NullPointerException("null string");
+ this.role = role;
+ this.string = string;
+ }
+ @Override
+ public String toString() {
+ return role.getIdentifier()+string;
+ }
+ public String toEscapedString() {
+ return role.getIdentifier()+URIStringUtils.escape(string);
+ }
+ @Override
+ public int hashCode() {
+ return string.hashCode() * 31 + role.hashCode();
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StringRVIPart other = (StringRVIPart) obj;
+ return role == other.role && string.equals(other.string);
+ }
+ }
+
+ public static class GuidRVIPart implements RVIPart {
+ public Role role;
+ public long mostSignificant;
+ public long leastSignificant;
+ public transient Resource resource;
+ @Override
+ public Role getRole() {
+ return role;
+ }
+ public GuidRVIPart() {}
+ public GuidRVIPart(Role role, Resource resource, long mostSignificant, long leastSignificant) {
+ this.role = role;
+ this.resource = resource;
+ this.mostSignificant = mostSignificant;
+ this.leastSignificant = leastSignificant;
+ }
+ @Override
+ public String toString() {
+ return role.getIdentifier()+mostSignificant+":"+leastSignificant;
+ }
+ public String toEscapedString() {
+ String rid = resource != null ? Long.toString( resource.getResourceId() ) : "0";
+ return role.getIdentifier()+mostSignificant+":"+leastSignificant+":"+rid;
+ }
+ @Override
+ public int hashCode() {
+ return (longHashCode(leastSignificant) * 51 + longHashCode(mostSignificant)) * 31 + role.hashCode();
+ }
+ /*
+ * TODO: remove this when switched into Java 1.8
+ */
+ private static int longHashCode(long value) {
+ return (int)(value ^ (value >>> 32));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ GuidRVIPart other = (GuidRVIPart) obj;
+ return role == other.role && leastSignificant == other.leastSignificant && mostSignificant == other.mostSignificant;
+ }
+
+ }
+
+ public static RVI fromResourceFormat( RequestProcessor proc, String str ) {
+ SerialisationSupport support = proc.getService(SerialisationSupport.class);
+ if (support == null) throw new RuntimeException("No serialization support in Session");
+ Databoard databoard = proc.getService(Databoard.class);
+ if (databoard == null) throw new RuntimeException("No databoard support in Session");
+
+ Binding rviBinding = databoard.getBindingUnchecked( RVI.class );
+ RVIBuilder rb = new RVIBuilder( rviBinding );
+ int pos = 0, len = str.length();
+ while (pos<str.length()) {
+ Role role = null;
+ char c = str.charAt(pos);
+ if (c=='#') {
+ pos++;
+ role = Role.PROPERTY;
+ } else if (c=='/') {
+ pos++;
+ role = Role.CHILD;
+ } else {
+ role = Role.CHILD;
+ }
+ int e1 = str.indexOf('#', pos);
+ int e2 = str.indexOf('/', pos);
+ e1 = e1<0?len:e1;
+ e2 = e2<0?len:e2;
+ int end = e1<e2?e1:e2;
+ if (str.charAt(pos) == 'r') {
+ String x = str.substring(pos+1, end);
+ if (!x.isEmpty()) {
+ try {
+ long res = (int) Long.parseLong(x);
+ Resource r = support.getResource( res );
+ rb.append( role, r );
+ pos = end;
+ continue;
+ } catch (NumberFormatException nfe) {
+ } catch (DatabaseException e) {
+ }
+ }
+ }
+ if (str.indexOf(":", pos+1) > -1) {
+ String x = str.substring(pos+1, end);
+ if (!x.isEmpty()) {
+ String[] parts = x.split(":");
+ if (parts.length == 3) {
+ try {
+ long res = (int) Long.parseLong(parts[2]);
+ long mostSignificant = Long.parseLong(parts[0]);
+ long leastSignificant = Long.parseLong(parts[1]);
+ Resource r = support.getResource( res );
+ rb.append( role, r, mostSignificant, leastSignificant);
+ pos = end;
+ continue;
+ } catch (NumberFormatException nfe) {
+ } catch (DatabaseException e) {
+ }
+ }
+ }
+ }
+ String text = URIStringUtils.unescape( str.substring(pos, end) );
+ pos = end;
+ rb.append( role, text );
+ }
+ return rb.toRVI();
+ }
+
+}