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