1 /*******************************************************************************
2 * Copyright (c) 2012 Association for Decentralized Information Management in
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.db.layer0.migration;
14 import java.io.DataInputStream;
16 import java.io.IOException;
17 import java.net.MalformedURLException;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashSet;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.NullProgressMonitor;
28 import org.simantics.databoard.Bindings;
29 import org.simantics.databoard.adapter.AdaptException;
30 import org.simantics.databoard.binding.mutable.Variant;
31 import org.simantics.databoard.container.DataContainer;
32 import org.simantics.databoard.container.DataContainers;
33 import org.simantics.db.ReadGraph;
34 import org.simantics.db.Resource;
35 import org.simantics.db.Session;
36 import org.simantics.db.WriteGraph;
37 import org.simantics.db.WriteOnlyGraph;
38 import org.simantics.db.common.CommentMetadata;
39 import org.simantics.db.common.primitiverequest.PossibleResource;
40 import org.simantics.db.common.request.BinaryRead;
41 import org.simantics.db.common.request.FreshEscapedName;
42 import org.simantics.db.common.request.UnaryRead;
43 import org.simantics.db.common.request.WriteRequest;
44 import org.simantics.db.common.utils.VersionMap;
45 import org.simantics.db.common.utils.VersionMapRequest;
46 import org.simantics.db.common.utils.Versions;
47 import org.simantics.db.exception.DatabaseException;
48 import org.simantics.db.layer0.adapter.Instances;
49 import org.simantics.db.layer0.adapter.impl.DefaultPasteHandler;
50 import org.simantics.db.layer0.adapter.impl.SharedOntologyImportAdvisor;
51 import org.simantics.db.layer0.adapter.impl.TrashBinRemover;
52 import org.simantics.db.layer0.internal.SimanticsInternal;
53 import org.simantics.db.layer0.util.ExternalDownloadBean;
54 import org.simantics.db.layer0.util.Layer0Utils;
55 import org.simantics.db.layer0.util.TGTransferableGraphSource;
56 import org.simantics.db.service.XSupport;
57 import org.simantics.graph.db.IImportAdvisor;
58 import org.simantics.graph.db.ImportResult;
59 import org.simantics.graph.db.MissingDependencyException;
60 import org.simantics.graph.db.TransferableGraphException;
61 import org.simantics.graph.representation.Identity;
62 import org.simantics.graph.representation.Root;
63 import org.simantics.graph.representation.TransferableGraph1;
64 import org.simantics.graph.representation.TransferableGraphUtils;
65 import org.simantics.layer0.Layer0;
66 import org.simantics.operation.Layer0X;
67 import org.simantics.simulation.ontology.SimulationResource;
68 import org.simantics.utils.datastructures.Pair;
69 import org.simantics.utils.datastructures.collections.CollectionUtils;
71 public class MigrationUtils {
73 public static final boolean DEBUG = false;
75 public static MigrationState newState() {
76 return new MigrationStateImpl();
79 public static MigrationStep getStep(Session session, String uri) throws DatabaseException {
80 return session.sync(new UnaryRead<String, MigrationStep>(uri) {
83 public MigrationStep perform(ReadGraph graph) throws DatabaseException {
84 Resource r = graph.getResource(parameter);
85 return graph.adapt(r, MigrationStep.class);
91 // public static TransferableGraph1 getTG(Session session, MigrationState state) {
92 // return getTG(session, state, true, false);
95 public static void clearTempResource(Session session, final Resource resource) {
96 session.asyncRequest(new WriteRequest() {
99 public void perform(WriteGraph graph) throws DatabaseException {
100 graph.deny(resource, Layer0.getInstance(graph).PartOf);
106 * Activate the imported resource, if there are no other active models and the resource is a Model.
108 private static void activateIfNoActiveModel(WriteGraph graph, Resource root, Resource parent) throws DatabaseException {
109 Layer0X L0X = Layer0X.getInstance(graph);
110 SimulationResource SIMU = SimulationResource.getInstance(graph);
111 if(!graph.hasStatement(parent, L0X.Activates) && graph.isInstanceOf(root, SIMU.Model))
112 graph.claim(parent, L0X.Activates, root);
115 public static Collection<Resource> importTo(IProgressMonitor monitor, Session session, MigrationState state, final Resource parent, final IImportAdvisor advisor) throws DatabaseException, TransferableGraphException {
116 final Resource resource = getResource(monitor, session, state);
117 final ArrayList<Resource> result = new ArrayList<Resource>();
118 if(resource != null) {
119 session.syncRequest(new WriteRequest() {
122 public void perform(WriteGraph graph) throws DatabaseException {
124 Layer0 L0 = Layer0.getInstance(graph);
126 for(Resource root : graph.getObjects(resource, L0.ConsistsOf)) {
128 String baseName = Versions.getBaseName(graph, root);
129 String version = Versions.getVersion(graph, root);
130 if(version != null) {
131 VersionMap map = graph.syncRequest(new VersionMapRequest(parent));
132 if(map.contains(baseName, version)) {
133 String newName = graph.syncRequest(new FreshEscapedName(parent, Layer0.getInstance(graph).ConsistsOf, baseName));
134 graph.claimLiteral(root, L0.HasName, newName + "@1", Bindings.STRING);
137 String newName = graph.syncRequest(new FreshEscapedName(parent, Layer0.getInstance(graph).ConsistsOf, baseName));
138 if(!newName.equals(baseName)) {
139 graph.claimLiteral(root, L0.HasName, newName, Bindings.STRING);
143 graph.deny(root, L0.PartOf);
144 graph.claim(root, L0.PartOf, parent);
146 // FIXME : Model activation must be done in "activations" virtual graph.
147 // FIXME : This step should be optional, not all the products use active models.
148 //activateIfNoActiveModel(graph, root, parent);
150 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);
151 graph.addMetadata(cm.add("Imported " + graph.getURI(root) + ", resource " + root));
157 graph.deny(resource, L0.PartOf);
162 TransferableGraph1 tg = getTG(session, state);
164 DefaultPasteHandler.defaultExecute(tg, parent, new IImportAdvisor() {
167 public Resource createRoot(WriteOnlyGraph graph, Root root) throws DatabaseException {
168 Resource r = advisor.createRoot(graph, root);
174 public Resource analyzeRoot(ReadGraph graph, Root root) throws DatabaseException {
175 return advisor.analyzeRoot(graph, root);
184 public static Collection<MigrationStep> getMigrationSteps(DataContainer header) throws DatabaseException {
186 return SimanticsInternal.sync(new BinaryRead<String,Integer,Collection<MigrationStep>>(header.format, header.version) {
189 public Collection<MigrationStep> perform(ReadGraph graph) throws DatabaseException {
191 Layer0 L0 = Layer0.getInstance(graph);
192 ArrayList<Pair<Double,MigrationStep>> steps = new ArrayList<Pair<Double,MigrationStep>>();
193 Instances query = graph.adapt(L0.Migration, Instances.class);
194 Set<Resource> migrations = new HashSet<Resource>();
195 for(Resource ontology : Layer0Utils.listOntologies(graph)) {
196 migrations.addAll(Layer0Utils.sortByCluster(graph, query.find(graph, ontology)));
198 for(Resource migration : migrations) {
200 System.err.println("getMigrationSteps: " + graph.getURI(migration));
201 String format = graph.getRelatedValue(migration, L0.Migration_format);
203 System.err.println("-format=" + format);
204 if(parameter.equals(format)) {
205 Integer from = graph.getRelatedValue(migration, L0.Migration_from);
207 System.err.println("-from=" + from);
208 Resource step = graph.getSingleObject(migration, L0.Migration_step);
209 if(parameter2.equals(from)) {
210 Double priority = graph.getRelatedValue(migration, L0.Migration_priority);
211 steps.add(Pair.make(-priority, graph.adapt(step, MigrationStep.class)));
213 System.err.println("=> ACCEPT");
216 System.err.println("=> REJECT");
221 Resource base = graph.getResource(baseURI);
223 System.err.println("getMigrationSteps format=" + parameter + ", version=" + parameter2);
224 for(Resource migration : graph.sync(new ObjectsWithType(base, L0.ConsistsOf, L0.Migration))) {
226 return CollectionUtils.sortByFirst(steps);
232 public static Resource importMigrated(IProgressMonitor monitor, Session session, File modelFile, MigrationState state, IImportAdvisor advisor, Resource target) throws Exception {
233 Collection<Resource> roots = importMigratedMany(monitor, session, modelFile, state, advisor, target);
234 if(roots.size() == 1) {
235 return roots.iterator().next();
241 public static Collection<Resource> importMigratedMany(IProgressMonitor monitor, Session session, File modelFile, MigrationState state, IImportAdvisor advisor, Resource target) throws Exception {
243 //assert(target != null);
244 assert(advisor != null);
246 if(monitor == null) monitor = new NullProgressMonitor();
249 System.err.println("importMigrated: file=" + (modelFile != null ? modelFile.getAbsolutePath() : null));
251 //String baseURI = state.getProperty(MigrationStateKeys.BASE_URI);
253 // System.err.println("importMigrated: baseURI=" + baseURI);
255 state.setProperty(MigrationStateKeys.MODEL_FILE, modelFile);
256 state.setProperty(MigrationStateKeys.SESSION, session);
257 state.setProperty(MigrationStateKeys.PROGRESS_MONITOR, monitor);
258 state.setProperty(MigrationStateKeys.IMPORT_ADVISOR, advisor);
260 DataContainer dc = state.getProperty(MigrationStateKeys.CURRENT_DATA_CONTAINER);
261 Collection<MigrationStep> migration = getMigrationSteps(dc);
263 // TransferableGraph1 tg = state.getProperty(MigrationStateKeys.CURRENT_TG);
264 // state.setProperty(MigrationStateKeys.TG_EXTENSIONS, tg.extensions);
266 for(MigrationStep step : migration) {
267 step.applyTo(monitor, session, state);
268 if (monitor.isCanceled())
272 if (monitor.isCanceled()) {
273 // Move possibly created material into TrashBin and quit.
274 final Resource root = state.probeProperty(MigrationStateKeys.CURRENT_RESOURCE);
276 session.syncRequest(new WriteRequest() {
278 public void perform(WriteGraph graph) throws DatabaseException {
279 new TrashBinRemover(root).remove(graph);
283 return Collections.emptyList();
286 // Absolute path imports end up here
288 Collection<Resource> roots = state.getProperty(MigrationStateKeys.CURRENT_ROOT_RESOURCES);
292 // Finally import model into final destination
293 return importTo(monitor, session, state, target, advisor);
297 public static TransferableGraph1 getTG(Session session, MigrationState state) throws DatabaseException {
298 return state.getProperty(MigrationStateKeys.CURRENT_TG);
301 public static Resource getResource(IProgressMonitor monitor, Session session, MigrationState state) throws DatabaseException {
302 return state.getProperty(MigrationStateKeys.CURRENT_RESOURCE);
305 public static Collection<Resource> getRootResources(IProgressMonitor monitor, Session session, MigrationState state) throws DatabaseException {
306 return state.getProperty(MigrationStateKeys.CURRENT_ROOT_RESOURCES);
310 * Get a property from the specified MigrationState and return specified
311 * default value if the property value is <code>null</code>.
313 * @param state the state to get the property from
314 * @param key the property to get
315 * @param defaultValue
316 * the default value to return if the property value is
318 * @return the property value
319 * @throws DatabaseException
320 * if fetching the property fails for some reason
322 public static <T> T getProperty(MigrationState state, String key, T defaultValue) throws DatabaseException {
323 T t = state.getProperty(key);
324 return t != null ? t : defaultValue;
327 public static MigratedImportResult importSharedOntology(Session session, TransferableGraph1 tg, boolean published) throws DatabaseException {
328 return importSharedOntology(null, session, tg, published);
331 public static MigratedImportResult importSharedOntology(IProgressMonitor monitor, Session session, TransferableGraph1 tg, boolean published) throws DatabaseException {
333 if(monitor == null) monitor = new NullProgressMonitor();
335 Variant edbVariant = tg.extensions.get(ExternalDownloadBean.EXTENSION_KEY);
336 if(edbVariant != null) {
338 ExternalDownloadBean edb = (ExternalDownloadBean)edbVariant.getValue(ExternalDownloadBean.BINDING);
339 for(Map.Entry<String, String> entry : edb.downloads.entrySet()) {
340 String uri = entry.getKey();
341 Resource existing = session.syncRequest(new PossibleResource(uri));
342 if(existing == null) {
343 String download = entry.getValue();
344 URL url = new URL(download);
345 DataContainer container = DataContainers.readFile(new DataInputStream(url.openStream()));
346 TransferableGraph1 dependencyTg = (TransferableGraph1) container.content.getValue(TransferableGraph1.BINDING);
347 importSharedOntology(monitor, session, dependencyTg, true);
350 } catch (AdaptException e) {
351 throw new DatabaseException(e);
352 } catch (MalformedURLException e) {
353 throw new DatabaseException(e);
354 } catch (IOException e) {
355 throw new DatabaseException(e);
360 Collection<Identity> roots = TransferableGraphUtils.getRoots(tg);
361 if(roots.size() == 1) {
363 TGTransferableGraphSource tgSource = new TGTransferableGraphSource(tg);
364 SharedOntologyImportAdvisor advisor = new SharedOntologyImportAdvisor(published);
366 MigrationState state = newState();
367 state.setProperty(MigrationStateKeys.UPDATE_DEPENDENCIES, false);
368 state.setProperty(MigrationStateKeys.CURRENT_TGS, tgSource);
369 state.setProperty(MigrationStateKeys.SESSION, session);
370 state.setProperty(MigrationStateKeys.PROGRESS_MONITOR, monitor);
371 state.setProperty(MigrationStateKeys.CURRENT_DATA_CONTAINER, new DataContainer("sharedLibrary", 1, new Variant(TransferableGraph1.BINDING, tg)));
373 MigrationUtils.importMigrated(monitor, session, null, state, advisor, null);
375 Collection<Resource> resultRoots = state.getProperty(MigrationStateKeys.CURRENT_ROOT_RESOURCES);
376 ImportResult result = state.getProperty(MigrationStateKeys.IMPORT_RESULT);
377 return new MigratedImportResult(resultRoots, result);
378 } catch (TransferableGraphException e) {
379 throw new DatabaseException(e);
380 } catch (MissingDependencyException e) {
382 } catch (DatabaseException e) {
384 } catch (Exception e) {
385 throw new DatabaseException(e);
387 session.getService(XSupport.class).setServiceMode(false, false);