View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.sequencer.teiid;
25  
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Map;
30  import java.util.UUID;
31  import org.modeshape.common.text.Jsr283Encoder;
32  import org.modeshape.common.text.TextEncoder;
33  import org.modeshape.graph.ExecutionContext;
34  import org.modeshape.graph.property.Name;
35  import org.modeshape.graph.property.Path;
36  import org.modeshape.graph.property.PathFactory;
37  import org.modeshape.graph.property.Reference;
38  import org.modeshape.graph.property.ReferenceFactory;
39  import org.modeshape.graph.property.UuidFactory;
40  import org.modeshape.graph.property.ValueFactories;
41  import org.modeshape.graph.property.ValueFactory;
42  import org.modeshape.graph.property.ValueFormatException;
43  import com.google.common.collect.ArrayListMultimap;
44  import com.google.common.collect.Multimap;
45  
46  /**
47   * 
48   */
49  public class ReferenceResolver {
50  
51      public static final Map<String, String> STANDARD_DATA_TYPE_URLS_TO_NAMES;
52      public static final Map<UUID, String> STANDARD_DATA_TYPE_URLS_BY_UUID;
53      public static final Map<String, UUID> STANDARD_DATA_TYPE_UUIDS_BY_NAMES;
54      protected static final TextEncoder ENCODER = new Jsr283Encoder();
55      static {
56          Map<String, String> dataTypes = new HashMap<String, String>();
57          // Really old models have simple data types hrefs that contain UUIDs ...
58          String sdtUrl = "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance#mmuuid:";
59          dataTypes.put(sdtUrl + "4ca2ae00-3a95-1e20-921b-eeee28353879", "NMTOKEN");
60          dataTypes.put(sdtUrl + "4df43700-3b13-1e20-921b-eeee28353879", "normalizedString");
61          dataTypes.put(sdtUrl + "3425cb80-d844-1e20-9027-be6d2c3b8b3a", "token");
62          dataTypes.put(sdtUrl + "d4d980c0-e623-1e20-8c26-a038c6ed7576", "language");
63          dataTypes.put(sdtUrl + "e66c4600-e65b-1e20-8c26-a038c6ed7576", "Name");
64          dataTypes.put(sdtUrl + "ac00e000-e676-1e20-8c26-a038c6ed7576", "NCName");
65          dataTypes.put(sdtUrl + "4b0f8500-e6a6-1e20-8c26-a038c6ed7576", "NMTOKENS");
66          dataTypes.put(sdtUrl + "dd33ff40-e6df-1e20-8c26-a038c6ed7576", "IDREF");
67          dataTypes.put(sdtUrl + "88b13dc0-e702-1e20-8c26-a038c6ed7576", "ID");
68          dataTypes.put(sdtUrl + "9fece300-e71a-1e20-8c26-a038c6ed7576", "ENTITY");
69          dataTypes.put(sdtUrl + "3c99f780-e72d-1e20-8c26-a038c6ed7576", "IDREFS");
70          dataTypes.put(sdtUrl + "20360100-e742-1e20-8c26-a038c6ed7576", "ENTITIES");
71          dataTypes.put(sdtUrl + "45da3500-e78f-1e20-8c26-a038c6ed7576", "integer");
72          dataTypes.put(sdtUrl + "cbdd6e40-b9d2-1e21-8c26-a038c6ed7576", "nonPositiveInteger");
73          dataTypes.put(sdtUrl + "0e081200-b8a4-1e21-b812-969c8fc8b016", "nonNegativeInteger");
74          dataTypes.put(sdtUrl + "86d29280-b8d3-1e21-b812-969c8fc8b016", "negativeInteger");
75          dataTypes.put(sdtUrl + "8cdee840-b900-1e21-b812-969c8fc8b016", "long");
76          dataTypes.put(sdtUrl + "33add3c0-b98d-1e21-b812-969c8fc8b016", "int");
77          dataTypes.put(sdtUrl + "5bbcf140-b9ae-1e21-b812-969c8fc8b016", "short");
78          dataTypes.put(sdtUrl + "26dc1cc0-b9c8-1e21-b812-969c8fc8b016", "byte");
79          dataTypes.put(sdtUrl + "1cbbd380-b9ea-1e21-b812-969c8fc8b016", "positiveInteger");
80          dataTypes.put(sdtUrl + "54b98780-ba14-1e21-b812-969c8fc8b016", "unsignedLong");
81          dataTypes.put(sdtUrl + "badcbd80-ba63-1e21-b812-969c8fc8b016", "unsignedInt");
82          dataTypes.put(sdtUrl + "327093c0-ba88-1e21-b812-969c8fc8b016", "unsignedShort");
83          dataTypes.put(sdtUrl + "cff745c0-baa2-1e21-b812-969c8fc8b016", "unsignedByte");
84          dataTypes.put(sdtUrl + "bf6c34c0-c442-1e24-9b01-c8207cd53eb7", "string");
85          dataTypes.put(sdtUrl + "dc476100-c483-1e24-9b01-c8207cd53eb7", "boolean");
86          dataTypes.put(sdtUrl + "569dfa00-c456-1e24-9b01-c8207cd53eb7", "decimal");
87          dataTypes.put(sdtUrl + "d86b0d00-c48a-1e24-9b01-c8207cd53eb7", "float");
88          dataTypes.put(sdtUrl + "1f18b140-c4a3-1e24-9b01-c8207cd53eb7", "double");
89          dataTypes.put(sdtUrl + "3b892180-c4a7-1e24-9b01-c8207cd53eb7", "time");
90          dataTypes.put(sdtUrl + "65dcde00-c4ab-1e24-9b01-c8207cd53eb7", "date");
91          dataTypes.put(sdtUrl + "62472700-a064-1e26-9b08-d6079ebe1f0d", "char");
92          dataTypes.put(sdtUrl + "822b9a40-a066-1e26-9b08-d6079ebe1f0d", "biginteger");
93          dataTypes.put(sdtUrl + "f2249740-a078-1e26-9b08-d6079ebe1f0d", "bigdecimal");
94          dataTypes.put(sdtUrl + "6d9809c0-a07e-1e26-9b08-d6079ebe1f0d", "timestamp");
95          dataTypes.put(sdtUrl + "051a0640-b4e8-1e26-9f33-b76fd9d5fa79", "object");
96          dataTypes.put(sdtUrl + "559646c0-4941-1ece-b22b-f49159d22ad3", "clob");
97          dataTypes.put(sdtUrl + "5a793100-1836-1ed0-ba0f-f2334f5fbf95", "blob");
98          dataTypes.put(sdtUrl + "43f5274e-55e1-1f87-ba1c-eea49143eb32", "XMLLiteral");
99          dataTypes.put(sdtUrl + "28d98540-b3e7-1e2a-9a03-beb8638ffd21", "duration");
100         dataTypes.put(sdtUrl + "5c69dec0-b3ea-1e2a-9a03-beb8638ffd21", "dateTime");
101         dataTypes.put(sdtUrl + "17d08040-b3ed-1e2a-9a03-beb8638ffd21", "gYearMonth");
102         dataTypes.put(sdtUrl + "b02c7600-b3f2-1e2a-9a03-beb8638ffd21", "gYear");
103         dataTypes.put(sdtUrl + "6e604140-b3f5-1e2a-9a03-beb8638ffd21", "gMonthDay");
104         dataTypes.put(sdtUrl + "860b7dc0-b3f8-1e2a-9a03-beb8638ffd21", "gDay");
105         dataTypes.put(sdtUrl + "187f5580-b3fb-1e2a-9a03-beb8638ffd21", "gMonth");
106         dataTypes.put(sdtUrl + "6247ec80-e8a4-1e2a-b433-fb67ea35c07e", "anyURI");
107         dataTypes.put(sdtUrl + "eeb5d780-e8c3-1e2a-b433-fb67ea35c07e", "QName");
108         dataTypes.put(sdtUrl + "3dcaf900-e8dc-1e2a-b433-fb67ea35c07e", "NOTATION");
109         dataTypes.put(sdtUrl + "d9998500-ebba-1e2a-9319-8eaa9b2276c7", "hexBinary");
110         dataTypes.put(sdtUrl + "b4c99380-ebc6-1e2a-9319-8eaa9b2276c7", "base64Binary");
111 
112         // Populate the name-to-UUID mapping ...
113         Map<UUID, String> dataTypesByUuid = new HashMap<UUID, String>();
114         Map<String, UUID> dataTypeUuidsByName = new HashMap<String, UUID>();
115         for (Map.Entry<String, String> entry : dataTypes.entrySet()) {
116             String url = entry.getKey();
117             String name = entry.getValue();
118             try {
119                 UUID uuid = UUID.fromString(url.substring(sdtUrl.length()));
120                 dataTypesByUuid.put(uuid, name);
121                 dataTypeUuidsByName.put(name, uuid);
122             } catch (Throwable e) {
123                 e.printStackTrace();
124             }
125         }
126 
127         // Newer models have simple data types hrefs that contain names ...
128         String xsdUrl = "http://www.w3.org/2001/XMLSchema#";
129         for (String value : new HashSet<String>(dataTypes.values())) {
130             dataTypes.put(xsdUrl + value, value);
131         }
132         sdtUrl = "http://www.metamatrix.com/metamodels/SimpleDatatypes-instance#";
133         for (String value : new HashSet<String>(dataTypes.values())) {
134             dataTypes.put(sdtUrl + value, value);
135         }
136 
137         STANDARD_DATA_TYPE_URLS_TO_NAMES = Collections.unmodifiableMap(dataTypes);
138         STANDARD_DATA_TYPE_URLS_BY_UUID = Collections.unmodifiableMap(dataTypesByUuid);
139         STANDARD_DATA_TYPE_UUIDS_BY_NAMES = Collections.unmodifiableMap(dataTypeUuidsByName);
140     }
141 
142     private final Multimap<Path, UUID> unresolved = ArrayListMultimap.create();
143     private final Map<UUID, Path> mmuuidToNodePath = new HashMap<UUID, Path>();
144     private final Map<UUID, UUID> mmuuidToNodeUuid = new HashMap<UUID, UUID>();
145     private final ValueFactory<String> stringFactory;
146     private final ReferenceFactory referenceFactory;
147     private final PathFactory pathFactory;
148     private final UuidFactory uuidFactory;
149 
150     public ReferenceResolver( ExecutionContext context ) {
151         ValueFactories valueFactories = context.getValueFactories();
152         this.referenceFactory = valueFactories.getWeakReferenceFactory();
153         this.uuidFactory = valueFactories.getUuidFactory();
154         this.pathFactory = valueFactories.getPathFactory();
155         this.stringFactory = valueFactories.getStringFactory();
156     }
157 
158     public void clear() {
159         mmuuidToNodePath.clear();
160         mmuuidToNodeUuid.clear();
161         unresolved.clear();
162     }
163 
164     public void recordXmiUuid( UUID xmiUuid,
165                                Path actualPath ) {
166         mmuuidToNodePath.put(xmiUuid, actualPath);
167     }
168 
169     public void recordXmiUuidToJcrUuid( UUID xmiUuid,
170                                         UUID jcrUuid ) {
171         if (xmiUuid != null) mmuuidToNodeUuid.put(xmiUuid, jcrUuid);
172     }
173 
174     /**
175      * @return unresolved
176      */
177     public Multimap<Path, UUID> getUnresolved() {
178         return unresolved;
179     }
180 
181     public UUID resolveInternalReference( String href ) {
182         if (href == null) {
183             return null;
184         }
185         UUID mmuuid = null;
186         if (href.startsWith("mmuuid/")) {
187             // It's a local reference ...
188             try {
189                 mmuuid = uuidFactory.create(href.substring(7));
190             } catch (ValueFormatException e) {
191                 // ignore
192             }
193         } else {
194             try {
195                 mmuuid = uuidFactory.create(href);
196             } catch (ValueFormatException e) {
197                 // ignore
198             }
199         }
200         return mmuuid;
201     }
202 
203     public ResolvedReference resolve( Path ownerPath,
204                                       Name attributeName,
205                                       String href ) {
206         if (href == null) {
207             return null;
208         }
209         // First check the standard data types ...
210         String name = STANDARD_DATA_TYPE_URLS_TO_NAMES.get(href);
211         if (name != null) {
212             // If the href contains a UUID, then extract it ...
213             int index = href.indexOf("mmuuid/");
214             String id = null;
215             if (index != -1) {
216                 id = href.substring(index + "mmuuid/".length());
217             } else {
218                 UUID uuid = STANDARD_DATA_TYPE_UUIDS_BY_NAMES.get(name);
219                 if (uuid != null) id = uuid.toString();
220             }
221             return new ResolvedReference(href, name, id);
222         }
223         UUID mmuuid = resolveInternalReference(href);
224         if (mmuuid == null) {
225             // Not an internal reference ...
226             int index = href.indexOf("mmuuid/");
227             String id = null;
228             if (index != -1) {
229                 id = href.substring(index + "mmuuid/".length());
230             }
231             mmuuid = this.uuidFactory.create(id);
232             ResolvedReference result = resolve(ownerPath, attributeName, href, mmuuid);
233             if (result == null) {
234                 return new ResolvedReference(href, null, null, id, null);
235             }
236         }
237         return resolve(ownerPath, attributeName, href, mmuuid);
238     }
239 
240     public ResolvedReference resolve( Path ownerPath,
241                                       Name attributeName,
242                                       String href,
243                                       UUID mmuuid ) {
244         if (mmuuid == null) {
245             return null;
246         }
247         Path path = mmuuidToNodePath.get(mmuuid);
248         Reference weakReference = referenceFactory.create(mmuuidToNodeUuid.get(mmuuid));
249         if (path == null && ownerPath != null && attributeName != null) {
250             // Record this unresolved reference for later resolution ...
251             Path propPath = pathFactory.create(ownerPath, attributeName);
252             unresolved.put(propPath, mmuuid);
253         }
254         if (path != null || weakReference != null) {
255             String resolvedName = path != null ? stringFactory.create(path.getLastSegment()) : null;
256             return new ResolvedReference(href, resolvedName, path, mmuuid.toString(), weakReference);
257         }
258         return null;
259     }
260 
261     public static class ResolvedReference {
262         private final String href;
263         private final Reference reference;
264         private final String name;
265         private final Path path;
266         private final String id;
267         private final boolean standardDataType;
268 
269         public ResolvedReference( String href,
270                                   String standardDataTypeName,
271                                   String id ) {
272             this.href = href;
273             this.standardDataType = true;
274             this.name = standardDataTypeName;
275             this.id = id;
276             this.reference = null;
277             this.path = null;
278         }
279 
280         public ResolvedReference( String href,
281                                   String name,
282                                   Path path,
283                                   String id,
284                                   Reference reference ) {
285             this.href = href;
286             this.standardDataType = false;
287             this.name = name;
288             this.reference = reference;
289             this.path = path;
290             this.id = id;
291         }
292 
293         public boolean isStandardDataType() {
294             return standardDataType;
295         }
296 
297         public String getHref() {
298             return href;
299         }
300 
301         public String getName() {
302             return name;
303         }
304 
305         public Path getPath() {
306             return path;
307         }
308 
309         public String getId() {
310             return id;
311         }
312 
313         public Reference getWeakReferenceValue() {
314             return reference;
315         }
316     }
317 
318 }