-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.project.management;\r
-\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.binding.error.BindingException;\r
-import org.simantics.databoard.binding.error.RuntimeBindingException;\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.ResourceRead;\r
-import org.simantics.db.common.utils.Transaction;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.graph.representation.TransferableGraph1;\r
-import org.simantics.layer0.DatabaseManagementResource;\r
-\r
-/**\r
- * GraphBundle represents a bundle graph that may exist in memory \r
- * in a OSGi Bundle Context, a P2 Bundle Pool, or in Simantics Database.\r
- * \r
- * The string representation of the version is in the following format: \r
- * <id>/<major.minor.micro(.qualifier)>\r
- * \r
- * Here is what is said about osgi version numbers:\r
- * \r
- * Major - Differences in the major part indicate significant differences \r
- * such that backward compability is not guaranteed.\r
- * \r
- * Minor - Changes in the minor part indicate that the newer version of the\r
- * entity is backward compatible with the older version, but it \r
- * includes additional functionality and/or API.\r
- * \r
- * Service - The service part indicates the presence of bug fixes and minor\r
- * implementation (i.e., hidden) changes over previous versions.\r
- * \r
- * Qualifier - The qualifier is not interpreted by the system. Qualifiers are\r
- * compared using standard string comparison. Qualifier is determined\r
- * at build time by builder. It may be millisecond time or version \r
- * control revision number. The value is monotonically increasing. \r
- * \r
- * \r
- * The class is hash-equals-comparable.\r
- *\r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
- */\r
-public class GraphBundle implements Comparable<GraphBundle> {\r
-\r
- /** Versioned Id pattern */ \r
- static String ID_PATTERN_STRING = "[a-zA-Z_0-9\\-]+(?:\\.[a-zA-Z_0-9\\-]+)*";\r
- static String VERSION_PATTERN_STRING = "(\\d+).(\\d+).(\\d+).([a-zA-Z_0-9\\-]+)";\r
- static Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING);\r
- static Pattern VERSION_PATTERN = Pattern.compile(VERSION_PATTERN_STRING);\r
- static Pattern VERSIONED_ID_PATTERN = Pattern.compile("(" + ID_PATTERN_STRING + ")/" + VERSION_PATTERN_STRING + "");\r
- \r
- /** User-friendly name */\r
- String name;\r
- \r
- /** Actual graph */\r
- TransferableGraph1 graph;\r
- \r
- /** GraphBundle resource in database */ \r
- Resource resource;\r
- \r
- /** Graph hash code */\r
- int hashcode;\r
- \r
- /** Id */\r
- String id;\r
- \r
- // Version\r
- int major, minor, service;\r
- \r
- // Optional qualifier\r
- String qualifier;\r
- \r
- /** Database install Info, optional */\r
- long[] resourceArray;\r
-\r
- /** Should this ontology be installed immutable **/\r
- boolean immutable = true;\r
-\r
- GraphBundle() {}\r
- \r
- public GraphBundle(String name, TransferableGraph1 data, String versionedId) \r
- throws RuntimeBindingException { \r
- try { \r
- // Assert version id is correct\r
- Matcher m = VERSIONED_ID_PATTERN.matcher(versionedId); \r
- if (!m.matches()) {\r
- throw new IllegalArgumentException("Illegal VersionId \""+versionedId+"\", <id>/<major.minor.micro.qualifier> is expected.");\r
- }\r
- \r
- Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class ); \r
- \r
- this.name = name;\r
- this.graph = data; \r
- this.hashcode = data != null ? binding.hashValue( data ) : 0;\r
- this.id = m.group(1);\r
- this.major = Integer.valueOf( m.group(2) );\r
- this.minor = Integer.valueOf( m.group(3) );\r
- if (m.group(4) != null) {\r
- this.service = Integer.valueOf( m.group(4) );\r
- }\r
- this.qualifier = m.group(5);\r
- } catch (BindingException e) {\r
- // Unexpected\r
- throw new RuntimeBindingException(e);\r
- } \r
- }\r
- \r
- public GraphBundle(String name, TransferableGraph1 data, String id, String version) \r
- throws RuntimeBindingException { \r
- Matcher m = ID_PATTERN.matcher(id);\r
- if (!m.matches()) \r
- throw new IllegalArgumentException("Illegal Id, got \""+id+"\"");\r
- m = VERSION_PATTERN.matcher(version);\r
- if (!m.matches()) \r
- throw new IllegalArgumentException("Illegal Version, got \""+id+"\", <id>/<major.minor.micro.qualifier> is expected.");\r
- try { \r
- Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class ); \r
- this.name = name;\r
- this.graph = data; \r
- this.hashcode = binding.hashValue( data );\r
- this.id = id;\r
- this.major = Integer.valueOf( m.group(1) );\r
- this.minor = Integer.valueOf( m.group(2) );\r
- this.service = Integer.valueOf( m.group(3) );\r
- if (m.group(4) != null) {\r
- this.qualifier = m.group(4);\r
- }\r
- } catch (BindingException e) {\r
- // Unexpected\r
- throw new RuntimeBindingException(e);\r
- }\r
- }\r
- \r
- public String getName() {\r
- return name;\r
- }\r
-\r
- @Override\r
- public int compareTo(GraphBundle o) {\r
- int cur = id.compareTo(o.id);\r
- if(cur != 0)\r
- return cur;\r
- \r
- cur = major - o.major;\r
- if(cur != 0)\r
- return cur;\r
- \r
- cur = minor - o.minor;\r
- if(cur != 0)\r
- return cur;\r
- \r
- cur = service - o.service; \r
- return cur;\r
- }\r
- \r
- /**\r
- * This method excepts {@link Transaction#readGraph()} to return a non-null\r
- * value, i.e. a database transaction must be in progress that has been\r
- * started with\r
- * {@link Transaction#startTransaction(RequestProcessor, boolean)}.\r
- * \r
- * @return\r
- * @see #getGraph(RequestProcessor)\r
- */\r
- public TransferableGraph1 getGraph() {\r
- if (graph == null) {\r
- ReadGraph g = Transaction.readGraph();\r
- if (g == null)\r
- throw new IllegalStateException("No read transaction available");\r
- try {\r
- Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);\r
- graph = g.getRelatedValue(resource, DatabaseManagement.HasFile, tg_binding); \r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- return graph;\r
- }\r
-\r
- public TransferableGraph1 getGraph(RequestProcessor processor) {\r
- if (graph == null) {\r
- try {\r
- graph = processor.syncRequest(new ResourceRead<TransferableGraph1>(resource) {\r
- @Override\r
- public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException {\r
- Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );\r
- DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(graph);\r
- return graph.getRelatedValue(resource, DatabaseManagement.HasFile, tg_binding); \r
- }\r
- });\r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- return graph;\r
- }\r
- \r
- public int getHashcode() {\r
- return hashcode;\r
- }\r
- \r
- @Override\r
- public int hashCode() {\r
- return 31*id.hashCode() + 7*major + 3*minor + 11*service + (qualifier!=null?13*qualifier.hashCode():0) + hashcode;\r
- }\r
- \r
- @Override\r
- public boolean equals(Object obj) {\r
- if (obj instanceof GraphBundle == false) return false;\r
- GraphBundle other = (GraphBundle) obj;\r
- if (other.hashcode != hashcode) return false;\r
- if (!other.id.equals(id)) return false;\r
- if (other.major != major) return false;\r
- if (other.minor != minor) return false;\r
- if (other.service != service) return false;\r
- if (!objectEquals(other.qualifier, qualifier )) return false;\r
- return true;\r
- } \r
- \r
- static boolean objectEquals(Object o1, Object o2) {\r
- if (o1 == o2) return true;\r
- if (o1 == null && o2 == null) return true;\r
- if (o1 == null || o2 == null) return false;\r
- return o1.equals(o2);\r
- } \r
- \r
- public boolean getImmutable() {\r
- return immutable;\r
- }\r
- \r
- public String getId() {\r
- return id;\r
- }\r
- \r
- public int getMajor() {\r
- return major;\r
- }\r
- \r
- public int getMinor() {\r
- return minor;\r
- }\r
- \r
- public int getService() {\r
- return service;\r
- }\r
- \r
- public String getQualifier() {\r
- return qualifier;\r
- }\r
-\r
- public String getVersionedId() {\r
- return id+"/"+major+"."+minor+"."+service+"."+qualifier;\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- return name+", "+id+"/"+getVersionedId()+", hash="+hashcode;\r
- }\r
-\r
- public long[] getResourceArray() {\r
- return resourceArray;\r
- }\r
-\r
- public void setResourceArray(long[] resourceArray) {\r
- this.resourceArray = resourceArray;\r
- }\r
- \r
- public static void main(String[] args) {\r
- Matcher m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.qualifier");\r
- if (m.matches()) {\r
- System.out.println( m.groupCount() );\r
- }\r
- \r
- m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1");\r
- if (m.matches()) {\r
- System.out.println( m.groupCount() );\r
- }\r
- \r
- m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.200810101010");\r
- if (m.matches()) {\r
- System.out.println( m.groupCount() );\r
- }\r
- \r
- m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1");\r
- if (m.matches()) {\r
- System.out.println( m.groupCount() );\r
- }\r
- \r
- }\r
- \r
-}\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.project.management;
+
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.binding.error.RuntimeBindingException;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.common.utils.Transaction;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.graph.representation.TransferableGraph1;
+import org.simantics.layer0.DatabaseManagementResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * GraphBundle represents a bundle graph that may exist in memory
+ * in a OSGi Bundle Context, a P2 Bundle Pool, or in Simantics Database.
+ *
+ * The string representation of the version is in the following format:
+ * <id>/<major.minor.micro(.qualifier)>
+ *
+ * Here is what is said about osgi version numbers:
+ *
+ * Major - Differences in the major part indicate significant differences
+ * such that backward compability is not guaranteed.
+ *
+ * Minor - Changes in the minor part indicate that the newer version of the
+ * entity is backward compatible with the older version, but it
+ * includes additional functionality and/or API.
+ *
+ * Service - The service part indicates the presence of bug fixes and minor
+ * implementation (i.e., hidden) changes over previous versions.
+ *
+ * Qualifier - The qualifier is not interpreted by the system. Qualifiers are
+ * compared using standard string comparison. Qualifier is determined
+ * at build time by builder. It may be millisecond time or version
+ * control revision number. The value is monotonically increasing.
+ *
+ *
+ * The class is hash-equals-comparable.
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class GraphBundle implements Comparable<GraphBundle> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphBundle.class);
+
+ /** Versioned Id pattern */
+ static String ID_PATTERN_STRING = "[a-zA-Z_0-9\\-]+(?:\\.[a-zA-Z_0-9\\-]+)*";
+ static String VERSION_PATTERN_STRING = "(\\d+).(\\d+).(\\d+).([a-zA-Z_0-9\\-]+)";
+ static Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING);
+ static Pattern VERSION_PATTERN = Pattern.compile(VERSION_PATTERN_STRING);
+ static Pattern VERSIONED_ID_PATTERN = Pattern.compile("(" + ID_PATTERN_STRING + ")/" + VERSION_PATTERN_STRING + "");
+
+ /** User-friendly name */
+ String name;
+
+ /** If {@link #graph} is null then this may be defined to fetch the data on-demand */
+ Supplier<TransferableGraph1> graphSource;
+
+ /** Actual graph */
+ TransferableGraph1 graph;
+
+ /** GraphBundle resource in database */
+ Resource resource;
+
+ /** Graph hash code */
+ int hashcode;
+
+ /** Id */
+ String id;
+
+ // Version
+ int major, minor, service;
+
+ // Optional qualifier
+ String qualifier;
+
+ /** Database install Info, optional */
+ long[] resourceArray;
+
+ /** Should this ontology be installed immutable **/
+ boolean immutable = true;
+
+ GraphBundle() {}
+
+ public GraphBundle(String name, TransferableGraph1 data, String versionedId)
+ throws RuntimeBindingException {
+ try {
+ // Assert version id is correct
+ Matcher m = VERSIONED_ID_PATTERN.matcher(versionedId);
+ if (!m.matches()) {
+ throw new IllegalArgumentException("Illegal VersionId \""+versionedId+"\", <id>/<major.minor.micro.qualifier> is expected.");
+ }
+
+ this.name = name;
+ this.graph = data;
+ this.hashcode = hash(data);
+ this.id = m.group(1);
+ this.major = Integer.valueOf( m.group(2) );
+ this.minor = Integer.valueOf( m.group(3) );
+ if (m.group(4) != null) {
+ this.service = Integer.valueOf( m.group(4) );
+ }
+ this.qualifier = m.group(5);
+ } catch (BindingException e) {
+ // Unexpected
+ throw new RuntimeBindingException(e);
+ }
+ }
+
+ public GraphBundle(String name, TransferableGraph1 data, String id, String version)
+ throws RuntimeBindingException {
+ Matcher m = ID_PATTERN.matcher(id);
+ if (!m.matches())
+ throw new IllegalArgumentException("Illegal Id, got \""+id+"\"");
+ m = VERSION_PATTERN.matcher(version);
+ if (!m.matches())
+ throw new IllegalArgumentException("Illegal Version, got \""+id+"\", <id>/<major.minor.micro.qualifier> is expected.");
+ try {
+ this.name = name;
+ this.graph = data;
+ this.hashcode = hash(data);
+ this.id = id;
+ this.major = Integer.valueOf( m.group(1) );
+ this.minor = Integer.valueOf( m.group(2) );
+ this.service = Integer.valueOf( m.group(3) );
+ if (m.group(4) != null) {
+ this.qualifier = m.group(4);
+ }
+ } catch (BindingException e) {
+ // Unexpected
+ throw new RuntimeBindingException(e);
+ }
+ }
+
+ public GraphBundle(String name, Supplier<TransferableGraph1> source, int hashCode, String id, String version) {
+ Matcher m = ID_PATTERN.matcher(id);
+ if (!m.matches())
+ throw new IllegalArgumentException("Illegal Id, got \""+id+"\"");
+ m = VERSION_PATTERN.matcher(version);
+ if (!m.matches())
+ throw new IllegalArgumentException("Illegal Version, got \""+id+"\", <id>/<major.minor.micro.qualifier> is expected.");
+ this.name = name;
+ this.graphSource = source;
+ this.hashcode = hashCode;
+ this.id = id;
+ this.major = Integer.valueOf( m.group(1) );
+ this.minor = Integer.valueOf( m.group(2) );
+ this.service = Integer.valueOf( m.group(3) );
+ if (m.group(4) != null) {
+ this.qualifier = m.group(4);
+ }
+ }
+
+ private int hash(TransferableGraph1 data) throws BindingException {
+ return data == null ? 0 : TransferableGraph1.BINDING.hashValue( data );
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int compareTo(GraphBundle o) {
+ int cur = id.compareTo(o.id);
+ if(cur != 0)
+ return cur;
+
+ cur = major - o.major;
+ if(cur != 0)
+ return cur;
+
+ cur = minor - o.minor;
+ if(cur != 0)
+ return cur;
+
+ cur = service - o.service;
+ return cur;
+ }
+
+ /**
+ * This method excepts {@link Transaction#readGraph()} to return a non-null
+ * value, i.e. a database transaction must be in progress that has been
+ * started with
+ * {@link Transaction#startTransaction(RequestProcessor, boolean)}.
+ *
+ * @return
+ * @see #getGraph(RequestProcessor)
+ */
+ public TransferableGraph1 getGraph() {
+ if (graph == null) {
+ if (graphSource != null) {
+ graph = graphSource.get();
+ }
+ if (graph == null) {
+ ReadGraph g = Transaction.readGraph();
+ if (g == null)
+ throw new IllegalStateException("No read transaction available");
+ try {
+ graph = readTg(g);
+ } catch (DatabaseException e) {
+ LOGGER.error("Failed to read transferable graph from " + resource, e);
+ }
+ }
+ }
+ return graph;
+ }
+
+ public TransferableGraph1 getGraph(RequestProcessor processor) {
+ if (graph == null) {
+ try {
+ graph = processor.syncRequest(new ResourceRead<TransferableGraph1>(resource) {
+ @Override
+ public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException {
+ return readTg(graph);
+ }
+ });
+ } catch (DatabaseException e) {
+ LOGGER.error("Failed to read transferable graph from " + resource, e);
+ }
+ }
+ return graph;
+ }
+
+ private TransferableGraph1 readTg(ReadGraph graph) throws DatabaseException {
+ DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(graph);
+ return graph.getRelatedValue(resource, DatabaseManagement.HasFile, TransferableGraph1.BINDING);
+ }
+
+ public int getHashcode() {
+ return hashcode;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31*id.hashCode() + 7*major + 3*minor + 11*service + (qualifier!=null?13*qualifier.hashCode():0) + hashcode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof GraphBundle == false) return false;
+ GraphBundle other = (GraphBundle) obj;
+ if (other.hashcode != hashcode) return false;
+ if (!other.id.equals(id)) return false;
+ if (other.major != major) return false;
+ if (other.minor != minor) return false;
+ if (other.service != service) return false;
+ if (!objectEquals(other.qualifier, qualifier )) return false;
+ return true;
+ }
+
+ static boolean objectEquals(Object o1, Object o2) {
+ if (o1 == o2) return true;
+ if (o1 == null && o2 == null) return true;
+ if (o1 == null || o2 == null) return false;
+ return o1.equals(o2);
+ }
+
+ public boolean getImmutable() {
+ return immutable;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getService() {
+ return service;
+ }
+
+ public String getQualifier() {
+ return qualifier;
+ }
+
+ public String getVersionedId() {
+ return id+"/"+major+"."+minor+"."+service+"."+qualifier;
+ }
+
+ @Override
+ public String toString() {
+ return name+", "+id+"/"+getVersionedId()+", hash="+hashcode;
+ }
+
+ public long[] getResourceArray() {
+ return resourceArray;
+ }
+
+ public void setResourceArray(long[] resourceArray) {
+ this.resourceArray = resourceArray;
+ }
+
+ public static void main(String[] args) {
+ Matcher m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.qualifier");
+ if (m.matches()) {
+ System.out.println( m.groupCount() );
+ }
+
+ m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1");
+ if (m.matches()) {
+ System.out.println( m.groupCount() );
+ }
+
+ m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.200810101010");
+ if (m.matches()) {
+ System.out.println( m.groupCount() );
+ }
+
+ m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1");
+ if (m.matches()) {
+ System.out.println( m.groupCount() );
+ }
+
+ }
+
+}
+