1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.project.management;
\r
14 import java.util.regex.Matcher;
\r
15 import java.util.regex.Pattern;
\r
17 import org.simantics.databoard.Bindings;
\r
18 import org.simantics.databoard.binding.Binding;
\r
19 import org.simantics.databoard.binding.error.BindingException;
\r
20 import org.simantics.databoard.binding.error.RuntimeBindingException;
\r
21 import org.simantics.db.ReadGraph;
\r
22 import org.simantics.db.RequestProcessor;
\r
23 import org.simantics.db.Resource;
\r
24 import org.simantics.db.common.request.ResourceRead;
\r
25 import org.simantics.db.common.utils.Transaction;
\r
26 import org.simantics.db.exception.DatabaseException;
\r
27 import org.simantics.graph.representation.TransferableGraph1;
\r
28 import org.simantics.layer0.DatabaseManagementResource;
\r
31 * GraphBundle represents a bundle graph that may exist in memory
\r
32 * in a OSGi Bundle Context, a P2 Bundle Pool, or in Simantics Database.
\r
34 * The string representation of the version is in the following format:
\r
35 * <id>/<major.minor.micro(.qualifier)>
\r
37 * Here is what is said about osgi version numbers:
\r
39 * Major - Differences in the major part indicate significant differences
\r
40 * such that backward compability is not guaranteed.
\r
42 * Minor - Changes in the minor part indicate that the newer version of the
\r
43 * entity is backward compatible with the older version, but it
\r
44 * includes additional functionality and/or API.
\r
46 * Service - The service part indicates the presence of bug fixes and minor
\r
47 * implementation (i.e., hidden) changes over previous versions.
\r
49 * Qualifier - The qualifier is not interpreted by the system. Qualifiers are
\r
50 * compared using standard string comparison. Qualifier is determined
\r
51 * at build time by builder. It may be millisecond time or version
\r
52 * control revision number. The value is monotonically increasing.
\r
55 * The class is hash-equals-comparable.
\r
57 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
\r
59 public class GraphBundle implements Comparable<GraphBundle> {
\r
61 /** Versioned Id pattern */
\r
62 static String ID_PATTERN_STRING = "[a-zA-Z_0-9\\-]+(?:\\.[a-zA-Z_0-9\\-]+)*";
\r
63 static String VERSION_PATTERN_STRING = "(\\d+).(\\d+).(\\d+).([a-zA-Z_0-9\\-]+)";
\r
64 static Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING);
\r
65 static Pattern VERSION_PATTERN = Pattern.compile(VERSION_PATTERN_STRING);
\r
66 static Pattern VERSIONED_ID_PATTERN = Pattern.compile("(" + ID_PATTERN_STRING + ")/" + VERSION_PATTERN_STRING + "");
\r
68 /** User-friendly name */
\r
72 TransferableGraph1 graph;
\r
74 /** GraphBundle resource in database */
\r
77 /** Graph hash code */
\r
84 int major, minor, service;
\r
86 // Optional qualifier
\r
89 /** Database install Info, optional */
\r
90 long[] resourceArray;
\r
92 /** Should this ontology be installed immutable **/
\r
93 boolean immutable = true;
\r
97 public GraphBundle(String name, TransferableGraph1 data, String versionedId)
\r
98 throws RuntimeBindingException {
\r
100 // Assert version id is correct
\r
101 Matcher m = VERSIONED_ID_PATTERN.matcher(versionedId);
\r
102 if (!m.matches()) {
\r
103 throw new IllegalArgumentException("Illegal VersionId \""+versionedId+"\", <id>/<major.minor.micro.qualifier> is expected.");
\r
106 Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
\r
109 this.graph = data;
\r
110 this.hashcode = data != null ? binding.hashValue( data ) : 0;
\r
111 this.id = m.group(1);
\r
112 this.major = Integer.valueOf( m.group(2) );
\r
113 this.minor = Integer.valueOf( m.group(3) );
\r
114 if (m.group(4) != null) {
\r
115 this.service = Integer.valueOf( m.group(4) );
\r
117 this.qualifier = m.group(5);
\r
118 } catch (BindingException e) {
\r
120 throw new RuntimeBindingException(e);
\r
124 public GraphBundle(String name, TransferableGraph1 data, String id, String version)
\r
125 throws RuntimeBindingException {
\r
126 Matcher m = ID_PATTERN.matcher(id);
\r
128 throw new IllegalArgumentException("Illegal Id, got \""+id+"\"");
\r
129 m = VERSION_PATTERN.matcher(version);
\r
131 throw new IllegalArgumentException("Illegal Version, got \""+id+"\", <id>/<major.minor.micro.qualifier> is expected.");
\r
133 Binding binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
\r
135 this.graph = data;
\r
136 this.hashcode = binding.hashValue( data );
\r
138 this.major = Integer.valueOf( m.group(1) );
\r
139 this.minor = Integer.valueOf( m.group(2) );
\r
140 this.service = Integer.valueOf( m.group(3) );
\r
141 if (m.group(4) != null) {
\r
142 this.qualifier = m.group(4);
\r
144 } catch (BindingException e) {
\r
146 throw new RuntimeBindingException(e);
\r
150 public String getName() {
\r
155 public int compareTo(GraphBundle o) {
\r
156 int cur = id.compareTo(o.id);
\r
160 cur = major - o.major;
\r
164 cur = minor - o.minor;
\r
168 cur = service - o.service;
\r
173 * This method excepts {@link Transaction#readGraph()} to return a non-null
\r
174 * value, i.e. a database transaction must be in progress that has been
\r
176 * {@link Transaction#startTransaction(RequestProcessor, boolean)}.
\r
179 * @see #getGraph(RequestProcessor)
\r
181 public TransferableGraph1 getGraph() {
\r
182 if (graph == null) {
\r
183 ReadGraph g = Transaction.readGraph();
\r
185 throw new IllegalStateException("No read transaction available");
\r
187 Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
\r
188 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(g);
\r
189 graph = g.getRelatedValue(resource, DatabaseManagement.HasFile, tg_binding);
\r
190 } catch (DatabaseException e) {
\r
191 e.printStackTrace();
\r
197 public TransferableGraph1 getGraph(RequestProcessor processor) {
\r
198 if (graph == null) {
\r
200 graph = processor.syncRequest(new ResourceRead<TransferableGraph1>(resource) {
\r
202 public TransferableGraph1 perform(ReadGraph graph) throws DatabaseException {
\r
203 Binding tg_binding = Bindings.getBindingUnchecked( TransferableGraph1.class );
\r
204 DatabaseManagementResource DatabaseManagement = DatabaseManagementResource.getInstance(graph);
\r
205 return graph.getRelatedValue(resource, DatabaseManagement.HasFile, tg_binding);
\r
208 } catch (DatabaseException e) {
\r
209 e.printStackTrace();
\r
215 public int getHashcode() {
\r
220 public int hashCode() {
\r
221 return 31*id.hashCode() + 7*major + 3*minor + 11*service + (qualifier!=null?13*qualifier.hashCode():0) + hashcode;
\r
225 public boolean equals(Object obj) {
\r
226 if (obj instanceof GraphBundle == false) return false;
\r
227 GraphBundle other = (GraphBundle) obj;
\r
228 if (other.hashcode != hashcode) return false;
\r
229 if (!other.id.equals(id)) return false;
\r
230 if (other.major != major) return false;
\r
231 if (other.minor != minor) return false;
\r
232 if (other.service != service) return false;
\r
233 if (!objectEquals(other.qualifier, qualifier )) return false;
\r
237 static boolean objectEquals(Object o1, Object o2) {
\r
238 if (o1 == o2) return true;
\r
239 if (o1 == null && o2 == null) return true;
\r
240 if (o1 == null || o2 == null) return false;
\r
241 return o1.equals(o2);
\r
244 public boolean getImmutable() {
\r
248 public String getId() {
\r
252 public int getMajor() {
\r
256 public int getMinor() {
\r
260 public int getService() {
\r
264 public String getQualifier() {
\r
268 public String getVersionedId() {
\r
269 return id+"/"+major+"."+minor+"."+service+"."+qualifier;
\r
273 public String toString() {
\r
274 return name+", "+id+"/"+getVersionedId()+", hash="+hashcode;
\r
277 public long[] getResourceArray() {
\r
278 return resourceArray;
\r
281 public void setResourceArray(long[] resourceArray) {
\r
282 this.resourceArray = resourceArray;
\r
285 public static void main(String[] args) {
\r
286 Matcher m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.qualifier");
\r
288 System.out.println( m.groupCount() );
\r
291 m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1");
\r
293 System.out.println( m.groupCount() );
\r
296 m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1.1.200810101010");
\r
298 System.out.println( m.groupCount() );
\r
301 m = VERSIONED_ID_PATTERN.matcher("org.simantics.layer0/1.1");
\r
303 System.out.println( m.groupCount() );
\r