1 package org.simantics.document.server;
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.HashMap;
12 import java.util.TreeMap;
14 import org.simantics.Simantics;
15 import org.simantics.databoard.Bindings;
16 import org.simantics.databoard.Datatypes;
17 import org.simantics.databoard.binding.Binding;
18 import org.simantics.databoard.type.Datatype;
19 import org.simantics.db.AsyncReadGraph;
20 import org.simantics.db.DirectStatements;
21 import org.simantics.db.ReadGraph;
22 import org.simantics.db.RequestProcessor;
23 import org.simantics.db.Resource;
24 import org.simantics.db.Session;
25 import org.simantics.db.Statement;
26 import org.simantics.db.WriteGraph;
27 import org.simantics.db.common.primitiverequest.Adapter;
28 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
29 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
30 import org.simantics.db.common.request.BinaryRead;
31 import org.simantics.db.common.request.ResourceAsyncRead;
32 import org.simantics.db.common.request.UniqueRead;
33 import org.simantics.db.common.request.WriteResultRequest;
34 import org.simantics.db.common.utils.Logger;
35 import org.simantics.db.common.utils.NameUtils;
36 import org.simantics.db.exception.DatabaseException;
37 import org.simantics.db.exception.ServiceException;
38 import org.simantics.db.layer0.function.All;
39 import org.simantics.db.layer0.request.ProjectModels;
40 import org.simantics.db.layer0.request.PropertyInfo;
41 import org.simantics.db.layer0.request.PropertyInfoRequest;
42 import org.simantics.db.layer0.request.VariableProperty;
43 import org.simantics.db.layer0.request.VariableRead;
44 import org.simantics.db.layer0.request.VariableValueWithBinding;
45 import org.simantics.db.layer0.scl.SCLDatabaseException;
46 import org.simantics.db.layer0.variable.ConstantPropertyVariable;
47 import org.simantics.db.layer0.variable.ProxyChildVariable;
48 import org.simantics.db.layer0.variable.ProxySessionRequest;
49 import org.simantics.db.layer0.variable.ProxyVariableSupport;
50 import org.simantics.db.layer0.variable.ProxyVariables;
51 import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable;
52 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
53 import org.simantics.db.layer0.variable.Variable;
54 import org.simantics.db.layer0.variable.VariableMap;
55 import org.simantics.db.layer0.variable.VariableMapImpl;
56 import org.simantics.db.layer0.variable.Variables;
57 import org.simantics.db.procedure.AsyncProcedure;
58 import org.simantics.db.service.DirectQuerySupport;
59 import org.simantics.document.base.ontology.DocumentationResource;
60 import org.simantics.document.server.bean.Command;
61 import org.simantics.document.server.bean.DataDefinition;
62 import org.simantics.document.server.handler.AbstractEventHandler;
63 import org.simantics.document.server.handler.AbstractResponseHandler;
64 import org.simantics.document.server.handler.EventHandler;
65 import org.simantics.document.server.io.CommandContext;
66 import org.simantics.document.server.io.CommandContextImpl;
67 import org.simantics.document.server.io.CommandContextMutable;
68 import org.simantics.document.server.io.CommandResult;
69 import org.simantics.document.server.io.IConsole;
70 import org.simantics.document.server.request.NodeRequest;
71 import org.simantics.document.server.request.ServerSCLHandlerValueRequest;
72 import org.simantics.document.server.request.ServerSCLValueRequest;
73 import org.simantics.document.server.serverResponse.ServerResponse;
74 import org.simantics.document.server.serverResponse.SuccessResponse;
75 import org.simantics.document.server.state.StateNodeManager;
76 import org.simantics.document.server.state.StateRealm;
77 import org.simantics.document.server.state.StateSessionManager;
78 import org.simantics.modeling.ModelingResources;
79 import org.simantics.modeling.services.CaseInsensitiveComponentFunctionNamingStrategy;
80 import org.simantics.modeling.services.ComponentNamingStrategy;
81 import org.simantics.operation.Layer0X;
82 import org.simantics.project.IProject;
83 import org.simantics.scl.compiler.module.repository.ImportFailureException;
84 import org.simantics.scl.compiler.types.TCon;
85 import org.simantics.scl.compiler.types.Type;
86 import org.simantics.scl.compiler.types.Types;
87 import org.simantics.scl.reflection.annotations.SCLValue;
88 import org.simantics.scl.runtime.SCLContext;
89 import org.simantics.scl.runtime.function.Function;
90 import org.simantics.scl.runtime.function.Function1;
91 import org.simantics.scl.runtime.function.FunctionImpl1;
92 import org.simantics.scl.runtime.function.FunctionImpl4;
93 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
94 import org.simantics.scl.runtime.tuple.Tuple;
95 import org.simantics.scl.runtime.tuple.Tuple0;
96 import org.simantics.scl.runtime.tuple.Tuple2;
97 import org.simantics.scl.runtime.tuple.Tuple3;
98 import org.simantics.scl.runtime.tuple.Tuple4;
99 import org.simantics.scl.runtime.tuple.Tuple5;
100 import org.simantics.simulation.experiment.IExperiment;
101 import org.simantics.simulation.ontology.SimulationResource;
102 import org.simantics.simulation.project.IExperimentManager;
103 import org.simantics.structural2.variables.Connection;
104 import org.simantics.structural2.variables.StandardProceduralChildVariable;
105 import org.simantics.structural2.variables.VariableConnectionPointDescriptor;
106 import org.slf4j.LoggerFactory;
108 import gnu.trove.map.hash.THashMap;
110 public class Functions {
112 private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Functions.class);
114 @SCLValue(type = "VariableMap")
115 public static VariableMap primitiveProperties = new VariableMapImpl() {
116 private void storePropertyValueAndExceptions(ReadGraph graph, Variable parent, String name, Variable property, Map<String, Variable> map) {
118 Object value = property.getValue(graph);
119 map.put(name, new ConstantPropertyVariable(parent, name, value, null));
120 } catch (DatabaseException e) {
121 Variable propertyExceptions = map.get(NodeRequest.PROPERTY_VALUE_EXCEPTIONS);
122 Map<String, Exception> exceptionMap;
123 if (propertyExceptions == null) {
124 exceptionMap = new TreeMap<String, Exception>();
125 propertyExceptions = new ConstantPropertyVariable(parent, NodeRequest.PROPERTY_VALUE_EXCEPTIONS, exceptionMap, null);
126 map.put(NodeRequest.PROPERTY_VALUE_EXCEPTIONS, propertyExceptions);
129 exceptionMap = propertyExceptions.getValue(graph);
130 } catch (DatabaseException e1) {
131 Logger.defaultLogError(e1);
137 label = property.getLabel(graph);
138 } catch (DatabaseException e2) {
141 exceptionMap.put(label, e);
146 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
147 return All.getStandardPropertyDomainPropertyVariableFromValue(graph, context, name);
151 public Map<String, Variable> getVariables(final ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
153 if(map == null) map = new HashMap<String,Variable>();
155 Variable parent = context.getParent(graph);
157 DocumentationResource DOC = DocumentationResource.getInstance(graph);
159 if(parent instanceof StandardProceduralChildVariable) {
161 StandardProceduralChildVariable procedural = (StandardProceduralChildVariable)parent;
162 for(Variable property : procedural.getProperties(graph/*, DocumentationResource.URIs.Document_AttributeRelation*/)) {
163 if(property instanceof StandardAssertedGraphPropertyVariable) {
164 StandardAssertedGraphPropertyVariable ass = (StandardAssertedGraphPropertyVariable)property;
165 if("dataDefinitions".equals(ass.property.name) || "commands".equals(ass.property.name) || "pollingFunction".equals(ass.property.name)) {
166 storePropertyValueAndExceptions(graph, parent, ass.property.name, property, map);
170 Resource predicate = property.getPossiblePredicateResource(graph);
171 if(predicate != null) {
172 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
173 if(info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
174 Variable prop = parent.getProperty(graph, predicate);
175 storePropertyValueAndExceptions(graph, parent, info.name, prop, map);
182 Resource parentRes = parent.getRepresents(graph);
184 Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_commands);
185 storePropertyValueAndExceptions(graph, parent, "commands", prop, map);
188 if (graph.getPossibleObject(parentRes, DOC.Properties_dataDefinitions) != null) {
189 Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_dataDefinitions);
190 storePropertyValueAndExceptions(graph, parent, "dataDefinitions", prop, map);
193 DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class);
194 //PrimitivePropertyStatementsProcedure foo = new PrimitivePropertyStatementsProcedure();
196 DirectStatements ds = dqs.getDirectPersistentStatements(graph, parentRes);
198 for(Statement stm : ds) {
199 Resource predicate = stm.getPredicate();
200 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
202 if(info.isHasProperty && info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
203 Variable prop = new StandardGraphPropertyVariable(graph, parent, predicate);
204 storePropertyValueAndExceptions(graph, parent, info.name, prop, map);
206 Resource definition = graph.getPossibleObject(predicate, DOC.Document_definesAttributeRelation);
207 if(definition != null) {
208 PropertyInfo info2 = graph.syncRequest(new PropertyInfoRequest(definition));
209 Variable prop = new StandardGraphPropertyVariable(graph, parent, definition);
210 map.put(info2.name, new PrimitiveValueVariable(parent, info2.name, prop));
221 static class DocumentPropertyKeys extends ResourceAsyncRead<List<String>> {
223 protected DocumentPropertyKeys(Resource resource) {
228 public void perform(AsyncReadGraph graph, final AsyncProcedure<List<String>> procedure) {
230 final List<String> result = new ArrayList<>();
232 DocumentationResource DOC = DocumentationResource.getInstance(graph);
235 if(graph.hasStatement(resource, DOC.Properties_commands))
236 result.add("commands");
237 if(graph.hasStatement(resource, DOC.Properties_dataDefinitions))
238 result.add("dataDefinitions");
239 } catch(ServiceException e) {
240 LOGGER.info(e.getMessage(), e);
243 graph.forEachDirectPredicate(resource, new AsyncProcedure<Set<Resource>>() {
246 public void execute(AsyncReadGraph graph, Set<Resource> predicates) {
248 for(Resource predicate : predicates) {
252 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
254 if(info.isHasProperty && info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
255 result.add(info.name);
257 Resource definition = graph.getPossibleObject(predicate, DOC.Document_definesAttributeRelation);
258 if(definition != null) {
259 PropertyInfo info2 = graph.syncRequest(new PropertyInfoRequest(definition));
260 result.add(info2.name);
264 } catch (DatabaseException e) {
265 LOGGER.info(e.getMessage(), e);
270 procedure.execute(graph, result);
275 public void exception(AsyncReadGraph graph, Throwable throwable) {
276 LOGGER.info(throwable.getMessage(), throwable);
277 procedure.exception(graph, throwable);
286 static class StandardDocumentProperties implements DocumentProperties {
289 public Collection<String> getKeys(ReadGraph graph, Variable parent) throws DatabaseException {
291 if(parent instanceof StandardProceduralChildVariable) {
293 StandardProceduralChildVariable procedural = (StandardProceduralChildVariable)parent;
294 List<String> result = new ArrayList<>();
295 for(Variable property : procedural.getProperties(graph)) {
296 if(property instanceof StandardAssertedGraphPropertyVariable) {
297 StandardAssertedGraphPropertyVariable ass = (StandardAssertedGraphPropertyVariable)property;
298 if("dataDefinitions".equals(ass.property.name) || "commands".equals(ass.property.name) || "pollingFunction".equals(ass.property.name)) {
299 result.add(ass.property.name);
303 Resource predicate = property.getPossiblePredicateResource(graph);
304 if(predicate != null) {
305 PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate));
306 if(info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) {
307 result.add(info.name);
316 Resource parentRes = parent.getRepresents(graph);
317 return graph.syncRequest(new DocumentPropertyKeys(parentRes), TransientCacheAsyncListener.instance());
324 public Object getValue(ReadGraph graph, Variable context, String key) throws DatabaseException {
325 return context.getPropertyValue(graph, key);
330 public static DocumentProperties primitiveProperties() throws DatabaseException {
331 return new StandardDocumentProperties();
334 @SCLValue(type = "VariableMap")
335 public static VariableMap inputSpaceChildren = new VariableMapImpl() {
337 private Variable getProxy(ReadGraph graph, Variable context) throws DatabaseException {
338 Variable root = Variables.getRootVariable(graph);
339 return new DocumentProxyChildVariable(context, context, root, ProxyChildVariable.CONTEXT_BEGIN);
343 public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException {
345 if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context);
346 return All.standardChildDomainChildren.getVariable(graph, context, name);
351 public Map<String, Variable> getVariables(ReadGraph graph, Variable context, Map<String, Variable> map) throws DatabaseException {
353 map = All.standardChildDomainChildren.getVariables(graph, context, map);
354 if(map == null) map = new THashMap<String,Variable>();
355 map.put(ProxyChildVariable.CONTEXT_BEGIN, getProxy(graph, context));
362 static class DocumentProxyChildVariable extends ProxyChildVariable implements ProxyVariableSupport {
364 public DocumentProxyChildVariable(Variable base, Variable parent, Variable other, String name) {
365 super(base, parent, other, name);
369 public Variable create(Variable base, Variable parent, Variable other, String name) {
370 return new DocumentProxyChildVariable(base, parent, other, name);
373 public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException {
375 if(CONTEXT_END.equals(name)) {
376 if(other instanceof ProxyChildVariable) {
377 // The context is also a proxy - let it do the job
378 return super.getPossibleChild(graph, name);
380 return ProxyVariables.tryToOwnRenamed(graph, this, base, CONTEXT_END);
384 return super.getPossibleChild(graph, name);
389 public Variable attachTo(ReadGraph graph, Variable parent) {
390 return attachToRenamed(graph, parent, name);
394 public Variable attachToRenamed(ReadGraph graph, Variable parent, String name) {
395 if(this.parent.equals(base))
396 return new DocumentProxyChildVariable(parent, parent, other, name);
398 return new DocumentProxyChildVariable(base, parent, other, name);
403 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
404 public static Variable input(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
405 Variable session = graph.syncRequest(new ProxySessionRequest(context));
406 DocumentationResource DOC = DocumentationResource.getInstance(graph);
407 String uri = session.getPossiblePropertyValue(graph, DOC.Session_inputURI);
409 // TODO HAXX - Please fix this
410 // we have no URI so this probably means that someone has inserted a non-session
411 // into the proxy variable => return that instead
414 return Variables.getVariable(graph, uri);
417 public static Variable stateVariable(ReadGraph graph, Variable self) throws DatabaseException {
418 Variable session = graph.syncRequest(new ProxySessionRequest(self));
420 throw new DatabaseException("No state for " + self.getURI(graph));
421 return session.getPossibleChild(graph, "__scl__");
424 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
425 public static Variable state(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
426 Variable session = graph.syncRequest(new ProxySessionRequest(context));
428 throw new DatabaseException("No state for " + context.getURI(graph));
429 return session.getPossibleChild(graph, "__scl__");
432 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
433 public static Variable icstate(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
434 Variable session = graph.syncRequest(new ProxySessionRequest(context));
435 return session.getPossibleChild(graph, "__icstate__");
438 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
439 public static Variable session(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
440 return graph.syncRequest(new ProxySessionRequest(context));
443 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
444 public static Variable experiment(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
445 // Try if experiment (run) has been used as the input
446 Variable var = input(graph, converter, context);
447 SimulationResource SR = SimulationResource.getInstance(graph);
448 while(var != null && !graph.isInstanceOf(var.getRepresents(graph), SR.Run)) {
449 var = var.getParent(graph);
453 IExperiment exp = getExperiment(graph, var);
461 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable")
462 public static Variable model(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
463 Variable var = input(graph, converter, context);
464 ModelingResources MOD = ModelingResources.getInstance(graph);
465 while(var != null && !graph.isInstanceOf(var.getRepresents(graph), MOD.StructuralModel)) {
466 var = var.getParent(graph);
472 private static Collection<Variable> getBroadcasted(ReadGraph graph, Variable target) throws DatabaseException {
474 ArrayList<Variable> result = new ArrayList<Variable>();
476 DocumentationResource DOC = DocumentationResource.getInstance(graph);
478 Variable broadcasted = target.getPossibleProperty(graph, DOC.Relations_broadcasted);
479 if(broadcasted != null) result.add(broadcasted);
481 for(Variable child : DocumentServerUtils.getChildrenInOrdinalOrder(graph, target)) {
482 result.addAll(getBroadcasted(graph, child));
489 private static List<Command> getCommands(ReadGraph graph, Collection<Variable> commandVariables, String trigger, CommandContext constants, boolean broadcast) throws DatabaseException {
491 if(commandVariables.isEmpty()) return Collections.emptyList();
494 TreeMap<Integer, List<Command>> sequences = new TreeMap<Integer, List<Command>>();
496 DocumentationResource DOC = DocumentationResource.getInstance(graph);
499 for (Variable c : commandVariables) {
502 t = c.getName(graph);
504 Connection conn = c.getValue(graph);
505 Variable targetConnectionPoint = DocumentServerUtils.getPossibleCommandTriggerConnectionPoint(graph, c, conn);
506 if (targetConnectionPoint != null) {
507 Variable target = targetConnectionPoint.getParent(graph);
508 if (target != null) {
510 Boolean enabled = target.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN);
511 if(enabled != null && !enabled) continue;
519 String o = c.getPossiblePropertyValue(graph, "ordinal");
521 ordinal = Integer.parseInt(o);
522 } catch (NumberFormatException e) {}
525 String constantKey = target.getPossiblePropertyValue(graph, "constantKey");
526 String constantValue = target.getPossiblePropertyValue(graph, "constantValue");
528 CommandContextMutable newConstants = (CommandContextMutable)constants;
529 if(constantKey != null && constantValue != null) {
530 if(!constantKey.isEmpty()) {
531 newConstants = new CommandContextImpl().merge(constants);
532 newConstants.putString(constantKey, constantValue);
536 String requiredKey = target.getPossiblePropertyValue(graph, "requiredKey");
537 if(requiredKey != null && !requiredKey.isEmpty()) {
538 if (newConstants == constants) {
539 newConstants = new CommandContextImpl().merge(constants);
541 newConstants.putRow(CommandContext.REQUIRED_KEYS, Collections.<Object>singletonList(requiredKey));
544 String forbiddenKey = target.getPossiblePropertyValue(graph, "forbiddenKey");
545 if(forbiddenKey != null && !forbiddenKey.isEmpty()) {
546 if (newConstants == constants) {
547 newConstants = new CommandContextImpl().merge(constants);
549 newConstants.putRow(CommandContext.FORBIDDEN_KEYS, Collections.<Object>singletonList(forbiddenKey));
552 if(DOC.Relations_broadcast.equals(targetConnectionPoint.getPredicateResource(graph))) {
554 // This is a broadcast terminal of a container
555 List<Command> broadcastCommands = getCommands(graph, getBroadcasted(graph, target), t, newConstants, true);
556 sequences.put(ordinal, broadcastCommands);
560 Command command = new Command(DocumentServerUtils.getId(graph, target), t,
561 targetConnectionPoint.getName(graph), newConstants);
562 sequences.put(ordinal, Collections.singletonList(command));
570 List<Command> commands = new ArrayList<Command>();
571 for (List<Command> commandList : sequences.values()) {
572 for (Command command : commandList) {
573 commands.add(command);
586 * @throws DatabaseException
588 public static List<Command> commandList(ReadGraph graph, Variable variable) throws DatabaseException {
589 return getCommands(graph, DocumentServerUtils.getTriggerCommands(graph, variable.getParent(graph)), null, new CommandContextImpl(), false);
598 * @throws DatabaseException
600 public static List<DataDefinition> dataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException {
601 DocumentationResource DOC = DocumentationResource.getInstance(graph);
602 ArrayList<DataDefinition> dataDefinitions = new ArrayList<DataDefinition>();
603 // Find data definition connections
604 for (Variable dataDefinitionRelation : DocumentServerUtils.getDataDefinitions(graph, variable.getParent(graph))) {
605 Connection dataDefinitionConnection = dataDefinitionRelation.getValue(graph);
606 // Find data the other end of definition connection
607 Collection<Variable> dataDefinitionProviders = DocumentServerUtils.getPossibleOtherConnectionPoints(graph,
608 dataDefinitionRelation, dataDefinitionConnection);
609 if (dataDefinitionProviders != null) {
611 for(Variable dataDefinitionProvider : dataDefinitionProviders) {
613 Variable dataDefinition = dataDefinitionProvider.getParent(graph);
614 if (dataDefinition != null) {
615 // Found other end. Is should contain ONE data
616 // definition connection to the actual data
617 Collection<Variable> dataCollection = DocumentServerUtils.getDataRelations(graph, dataDefinition);
618 if (dataCollection.size() == 1) {
619 Variable dataRelation = dataCollection.iterator().next();
620 Connection dataConnection = dataRelation.getValue(graph);
621 // Find data the other end of definition connection
622 Variable dataConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph,
623 dataRelation, dataConnection);
624 if (dataConnectionPoint != null) {
625 Variable data = dataConnectionPoint.getParent(graph);
626 Resource type = dataDefinition.getPossibleType(graph, DOC.Components_Component);
628 if (graph.isInheritedFrom(type, DOC.Components_DefVar)) {
630 String sourceProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_source,
632 String targetProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_target,
635 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
636 sourceProperty, targetProperty));
638 } else if (graph.isInheritedFrom(type, DOC.Components_DefVars)) {
640 List<String> sourcesProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_sources), String.class);
641 List<String> targetsProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_targets), String.class);
643 for (int i = 0; i < Math.min(sourcesProperty.size(), targetsProperty.size()); i++) {
644 dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data),
645 sourcesProperty.get(i), targetsProperty.get(i)));
654 return dataDefinitions;
657 @SuppressWarnings("unchecked")
658 private static <T> List<T> toList(Object o, Class<T> c) {
659 List<T> result = null;
660 if (o instanceof List) {
662 } else if (o instanceof Object[]) {
663 result = new ArrayList<T>(((Object[])o).length);
664 for (T item : (T[])o) {
669 return Collections.<T>emptyList();
674 public static AbstractEventHandler emptyOnClick(ReadGraph graph) throws DatabaseException {
675 return new EventHandler() {
677 public ServerResponse handle(ReadGraph graph, CommandContext parameters) throws DatabaseException {
684 public static AbstractEventHandler writeEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
686 final Session session = graph.getSession();
688 return new AbstractEventHandler() {
691 public CommandResult handle(final CommandContext parameters) {
693 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
697 String result = session.sync(new WriteResultRequest<String>() {
700 public String perform(WriteGraph graph) throws DatabaseException {
701 SCLContext sclContext = SCLContext.getCurrent();
702 Object oldGraph = sclContext.put("graph", graph);
703 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
705 Function1<String,String> pf = new FunctionImpl1<String,String>() {
707 public String apply(String key) {
708 return parameters.getString(key);
711 Object response = (String)fn.apply(variable, pf);
712 if(response instanceof String) {
713 return (String)response;
717 sclContext.put("graph", oldGraph);
718 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
725 return new SuccessResponse(result);
727 } catch (Throwable e) {
728 Logger.defaultLogError(e);
729 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
738 public static AbstractEventHandler readEventHandler(ReadGraph graph, final Variable variable, final Function fn) {
740 final Session session = graph.getSession();
742 return new AbstractEventHandler() {
745 public CommandResult handle(final CommandContext parameters) {
747 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
751 String result = session.sync(new UniqueRead<String>() {
754 public String perform(ReadGraph graph) throws DatabaseException {
755 SCLContext sclContext = SCLContext.getCurrent();
756 Object oldGraph = sclContext.put("graph", graph);
757 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
759 Function1<String,String> pf = new FunctionImpl1<String,String>() {
761 public String apply(String key) {
762 return parameters.getString(key);
765 Object response = (String)fn.apply(variable, pf);
766 if(response instanceof String) {
767 return (String)response;
771 sclContext.put("graph", oldGraph);
772 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
779 return new SuccessResponse(result);
781 } catch (Throwable e) {
782 Logger.defaultLogError(e);
783 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
792 public static AbstractEventHandler readEventHandler2(ReadGraph graph, final Function fn) {
794 final Session session = graph.getSession();
796 return new AbstractEventHandler() {
799 public CommandResult handle(final CommandContext parameters) {
801 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
805 CommandResult result = session.sync(new UniqueRead<CommandResult>() {
808 public CommandResult perform(ReadGraph graph) throws DatabaseException {
809 SCLContext sclContext = SCLContext.getCurrent();
810 Object oldGraph = sclContext.put("graph", graph);
811 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
813 Object response = fn.apply(parameters);
814 if(response instanceof CommandResult) {
815 return (CommandResult)response;
819 sclContext.put("graph", oldGraph);
820 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
829 } catch (Throwable e) {
830 Logger.defaultLogError(e);
831 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
839 public static AbstractEventHandler responseHandler(ReadGraph graph, Variable self, String function) throws DatabaseException {
841 Variable anyFunction = self.browse(graph, ".#" + function);
842 if(anyFunction == null) return null;
844 final List<TCon> effects = ServerSCLHandlerValueRequest.getEffects(graph, anyFunction);
846 Function1<CommandContext, CommandResult> fn = anyFunction.getValue(graph);
847 //String expression = anyFunction.getPropertyValue(graph, "expression");
849 final Session session = graph.getSession();
851 return new AbstractResponseHandler(fn) {
853 private String formatError(RequestProcessor proc, Throwable t) {
857 return proc.syncRequest(new UniqueRead<String>() {
860 public String perform(ReadGraph graph) throws DatabaseException {
861 Variable proxy = ProxyVariables.proxyVariableRoot(graph, anyFunction);
862 String uri2 = proxy.getURI(graph);
863 String uri = self.getParent(graph).getURI(graph);
865 String path = uri.substring(uri2.length());
867 String expr = anyFunction.getPossiblePropertyValue(graph, "expression");
868 StringBuilder message = new StringBuilder();
869 message.append("Handler execution failed\n");
870 message.append(" handler=" + path + "\n");
871 message.append(" expression=" + expr + "\n");
872 message.append(" message=" + t.getMessage() + "\n");
874 StringWriter sw = new StringWriter();
875 t.printStackTrace(new PrintWriter(sw));
876 message.append(" stack trace=" + sw);
878 return message.toString();
883 } catch (DatabaseException e) {
885 return e.getMessage();
892 public CommandResult handle(final CommandContext parameters) {
894 IConsole console = parameters.getValue("__console__");
895 SCLReportingHandler printer = (console != null) ? new ConsoleSCLReportingHandler(console)
896 : (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
900 Object result = null;
901 if(effects.contains(Types.WRITE_GRAPH)) {
903 result = session.syncRequest(new WriteResultRequest<Object>() {
906 public Object perform(WriteGraph graph)
907 throws DatabaseException {
908 SCLContext sclContext = SCLContext.getCurrent();
909 Object oldGraph = sclContext.put("graph", graph);
910 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
912 return fn.apply(parameters);
914 sclContext.put("graph", oldGraph);
915 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
921 } else if(effects.contains(Types.READ_GRAPH)) {
923 result = session.sync(new UniqueRead<Object>() {
926 public Object perform(ReadGraph graph) throws DatabaseException {
928 SCLContext sclContext = SCLContext.getCurrent();
929 Object oldGraph = sclContext.put("graph", graph);
930 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
933 return fn.apply(parameters);
935 sclContext.put("graph", oldGraph);
936 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
944 SCLContext sclContext = SCLContext.getCurrent();
945 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
947 result = fn.apply(parameters);
949 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
954 if (result instanceof org.simantics.document.server.serverResponse.Error) {
955 return (CommandResult)result;
958 if (result instanceof CommandResult) {
959 return (CommandResult)result;
961 CommandContextMutable assignments = new CommandContextImpl();
962 assignments.putValue("result", result);
963 return new ServerResponse(200, "", assignments);
966 } catch (Throwable e) {
967 return new org.simantics.document.server.serverResponse.Error(formatError(Simantics.getSession(), e));
976 public static AbstractEventHandler writeEventHandler2(ReadGraph graph, final Function fn) {
978 final Session session = graph.getSession();
980 return new AbstractEventHandler() {
983 public CommandResult handle(final CommandContext parameters) {
985 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
989 CommandResult result = session.syncRequest(new WriteResultRequest<CommandResult>() {
992 public CommandResult perform(WriteGraph graph) throws DatabaseException {
993 SCLContext sclContext = SCLContext.getCurrent();
994 Object oldGraph = sclContext.put("graph", graph);
995 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
997 Object response = fn.apply(parameters);
998 if(response instanceof CommandResult) {
999 return (CommandResult)response;
1003 sclContext.put("graph", oldGraph);
1004 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1013 } catch (Throwable e) {
1014 Logger.defaultLogError(e);
1015 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
1025 public static AbstractEventHandler eventHandler2(ReadGraph graph, final Function fn) {
1027 return new AbstractEventHandler() {
1030 public CommandResult handle(final CommandContext parameters) {
1032 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
1036 SCLContext sclContext = SCLContext.getCurrent();
1037 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
1039 Object response = fn.apply(parameters);
1040 if(response instanceof CommandResult) {
1041 return (CommandResult)response;
1045 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1048 } catch (Throwable e) {
1049 Logger.defaultLogError(e);
1050 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
1059 public static AbstractEventHandler eventHandler(ReadGraph graph, final Function fn) {
1061 return new AbstractEventHandler() {
1064 public CommandResult handle(final CommandContext parameters) {
1066 final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER);
1072 SCLContext sclContext = SCLContext.getCurrent();
1073 Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer);
1075 Function1<String,String> pf = new FunctionImpl1<String,String>() {
1077 public String apply(String key) {
1078 return parameters.getString(key);
1081 Object response = (String)fn.apply(pf);
1082 if(response instanceof String) {
1083 result = (String)response;
1086 sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter);
1089 return new SuccessResponse(result);
1091 } catch (Throwable e) {
1092 Logger.defaultLogError(e);
1093 return new org.simantics.document.server.serverResponse.Error(e.getMessage());
1101 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1102 public static Object sclValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1103 return ServerSCLValueRequest.compileAndEvaluate(graph, context);
1106 @SCLValue(type = "ReadGraph -> Resource -> Variable -> a")
1107 public static Object sclHandlerValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1108 return ServerSCLHandlerValueRequest.compileAndEvaluate(graph, context);
1111 @SCLValue(type = "ReadGraph -> Resource -> Resource -> ComponentNamingStrategy")
1112 public static ComponentNamingStrategy componentNamingStrategy(ReadGraph graph, Resource converter, Resource context) throws DatabaseException {
1113 return createComponentNamingStrategy(graph);
1116 public static CaseInsensitiveComponentFunctionNamingStrategy createComponentNamingStrategy(ReadGraph graph) throws DatabaseException {
1117 Layer0X L0X = Layer0X.getInstance(graph);
1118 @SuppressWarnings({ "unchecked", "rawtypes" })
1119 final Function dependencies = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.<Function>instance());
1120 @SuppressWarnings("rawtypes")
1121 Function moduleNameFunction = new FunctionImpl4<ReadGraph, Resource, String, Integer, List<Map<String, Object>>>() {
1123 public Object apply(ReadGraph p0, Resource p1, String p2) {
1124 return apply(p0, p1, p2);
1126 @SuppressWarnings("unchecked")
1128 public List<Map<String, Object>> apply(ReadGraph graph, Resource model, String search, Integer maxResults) {
1129 return (List<Map<String, Object>>)dependencies.apply(graph, model, search, maxResults);
1132 return new CaseInsensitiveComponentFunctionNamingStrategy("%s%02d", moduleNameFunction);
1135 public static IExperiment getExperiment(ReadGraph graph, Variable variable) throws DatabaseException {
1136 if (variable == null)
1139 SimulationResource SIMU = SimulationResource.getInstance(graph);
1141 Variable var = variable;
1142 Resource represents = var.getRepresents(graph);
1143 Resource activeRun = null;
1144 if (represents != null && graph.isInstanceOf(represents, SIMU.Run)) {
1145 activeRun = represents;
1148 IProject project = Simantics.peekProject();
1149 if (activeRun != null && project != null) {
1150 IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER);
1152 return expMan.getExperiment(NameUtils.getSafeName(graph, activeRun));
1158 public static CommandContextMutable putTuple(CommandContextMutable context, String key, Object tuple) {
1159 List<Object> list = new ArrayList<Object>();
1160 if (tuple instanceof Tuple) {
1161 Collections.addAll(list, ((Tuple)tuple).toArray());
1165 context.putRow(key, list);
1169 public static List<Object> getTuples(CommandContext context, String key) {
1170 List<List<Object>> rows = context.getRows(key);
1171 List<Object> tuples = new ArrayList<Object>();
1173 for (List<Object> row : rows) {
1174 switch (row.size()) {
1175 case 0: tuples.add(Tuple0.INSTANCE); break;
1176 case 1: tuples.add(row.get(1)); break;
1177 case 2: tuples.add(new Tuple2(row.get(0), row.get(1))); break;
1178 case 3: tuples.add(new Tuple3(row.get(0), row.get(1), row.get(2))); break;
1179 case 4: tuples.add(new Tuple4(row.get(0), row.get(1), row.get(2), row.get(3))); break;
1180 case 5: tuples.add(new Tuple5(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4))); break;
1187 public static String printContext(CommandContext context) {
1188 return context.toString();
1191 @SCLValue(type = "AbstractEventHandler")
1192 public static AbstractEventHandler emptyEvent = new AbstractEventHandler() {
1195 public CommandResult handle(CommandContext context) {
1201 public static String sclStateKey(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1203 String baseURI = base.getURI(graph);
1205 String selfURI = self.getURI(graph);
1207 String prefix = selfURI.substring(0, selfURI.indexOf(ProxyChildVariable.CONTEXT_BEGIN));
1208 String suffix = selfURI.substring(selfURI.lastIndexOf(ProxyChildVariable.CONTEXT_END) + ProxyChildVariable.CONTEXT_END.length());
1209 String stripped = prefix + suffix;
1211 String relative = Variables.getRelativeRVI(baseURI, stripped);
1213 return Variables.getRVI(relative, ref);
1217 public static Variable sclStateVariable(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException {
1219 String id = sclStateKey(graph, base, self, ref);
1221 Variable sclVar = base.getPossibleChild(graph, "__scl__");
1222 if(sclVar == null) return null;
1224 return sclVar.getPossibleProperty(graph, id);
1228 public static Object sclStateValueOrDefault(ReadGraph graph, Variable base, Variable self, String ref, Object defaultValue) throws DatabaseException {
1230 Variable stateVariable = sclStateVariable(graph, base, self, ref);
1231 if (stateVariable != null) {
1233 return stateVariable.getValue(graph);
1237 return defaultValue;
1242 public static void setSclStateValue(WriteGraph graph, Variable base, Variable self, String ref, Object value) throws DatabaseException {
1244 String id = sclStateKey(graph, base, self, ref);
1246 StateRealm realm = (StateRealm) StateSessionManager.getInstance().getOrCreateRealm(graph, base.getURI(graph)+"/__scl__");
1247 StateNodeManager nodeManager = (StateNodeManager) realm.getNodeManager();
1248 nodeManager.setState(id, value);
1252 public static Object projectComponentState(ReadGraph graph, Variable self, String ref, Object defaultValue) throws DatabaseException {
1253 Resource project = Simantics.getProjectResource();
1254 Variable component = self.getParent(graph);
1255 Variable projectVariable = Variables.getVariable(graph, project);
1256 return sclStateValueOrDefault(graph, projectVariable, component, ref, defaultValue);
1259 public static void setProjectComponentState(WriteGraph graph, Variable self, String ref, Object value) throws DatabaseException {
1260 Resource project = Simantics.getProjectResource();
1261 Variable component = self.getParent(graph);
1262 Variable projectVariable = Variables.getVariable(graph, project);
1263 setSclStateValue(graph, projectVariable, component, ref, value);
1266 private static Type getSCLType(Object value) throws DatabaseException {
1267 Binding b = Bindings.getBindingUnchecked(value.getClass());
1268 Datatype t = b.type();
1269 if(Datatypes.STRING.equals(t)) return Types.STRING;
1270 if(Datatypes.DOUBLE.equals(t)) return Types.DOUBLE;
1271 throw new DatabaseException("Type not supported");
1274 public static List<Variable> documentModelContribution(ReadGraph graph, Resource doc) throws DatabaseException {
1275 Resource project = Simantics.getProjectResource();
1276 ArrayList<Variable> result = new ArrayList<Variable>();
1277 for(Resource model : graph.syncRequest(new ProjectModels(project))) {
1278 result.add(Variables.getVariable(graph, model));
1283 public static String documentModelContributionLabel(ReadGraph graph, Variable var) throws DatabaseException {
1284 return var.getName(graph);
1287 public static Object getPropertyValueCached(ReadGraph graph, Variable variable, String name, Binding binding) throws DatabaseException {
1288 Variable property = graph.syncRequest(new VariableProperty(variable, name));
1289 return graph.syncRequest(new VariableValueWithBinding<Object>(property, binding));
1292 public static class ParentExistsRequest extends VariableRead<Boolean> {
1294 public ParentExistsRequest(Variable parent) {
1299 public Boolean perform(ReadGraph graph) throws DatabaseException {
1301 Variable existsProperty = variable.getPossibleProperty(graph, "exists");
1302 if(existsProperty == null) return true;
1304 Boolean exists = existsProperty.getPossibleValue(graph, Bindings.BOOLEAN);
1305 if (exists == null || !exists) return false;
1307 return graph.syncRequest(new ParentExistsRequest(variable.getParent(graph)));
1313 public static class PathExistsRequest extends VariableRead<Boolean> {
1315 public PathExistsRequest(Variable variable) {
1320 public Boolean perform(ReadGraph graph) throws DatabaseException {
1322 Variable widget = variable.getParent(graph);
1324 Boolean exists = widget.getPossiblePropertyValue(graph, "exists");
1325 if (exists == null || !exists) return false;
1327 if (!graph.syncRequest(new ParentExistsRequest(widget.getParent(graph)))) return false;
1329 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1330 Collection <Variable> cps = widget.getProperties(graph, DocumentationResource.URIs.Relations_parentRelation);
1331 for (Variable cp : cps) {
1333 Connection conn = cp.getValue(graph);
1334 Variable otherCp = DocumentServerUtils.getPossibleChildConnectionPoint(graph, cp, conn);
1335 if (otherCp != null) {
1336 Variable parentWidget = otherCp.getParent(graph);
1337 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1341 Variable parentCp = graph.sync(new BinaryRead<Variable, Connection, Variable>(widget, conn) {
1343 public Variable perform(ReadGraph graph) throws DatabaseException {
1344 DocumentationResource DOC = DocumentationResource.getInstance(graph);
1345 Collection<VariableConnectionPointDescriptor> descs = parameter2.getConnection2().getConnectionPointDescriptors(graph, parameter, null);
1347 for(VariableConnectionPointDescriptor desc : descs) {
1348 if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) {
1349 return desc.getVariable(graph);
1355 if (parentCp != null) {
1356 Variable parentWidget = parentCp.getParent(graph);
1357 if (parentWidget.<Boolean>getPropertyValue(graph, "pathExists")) {
1364 Resource type = widget.getType(graph);
1365 return graph.isInheritedFrom(type, DOC.Components_ParentlessComponent) ||
1366 (graph.isInheritedFrom(type, DOC.DocumentComponent) && cps.isEmpty());
1370 @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean")
1371 public static boolean pathExists(ReadGraph graph, Resource converter, Variable context) throws DatabaseException {
1372 return graph.syncRequest(new PathExistsRequest(context));
1375 public static String compileDocumentSCLValueExpression(ReadGraph graph, Variable context) {
1377 ServerSCLValueRequest.validate(graph, context);
1379 } catch (Exception e) {
1380 return resolveIssueMessage(e);
1384 public static String compileDocumentSCLHandlerValueExpression(ReadGraph graph, Variable context) {
1386 ServerSCLHandlerValueRequest.compile(graph, context);
1388 } catch (Exception e) {
1389 return resolveIssueMessage(e);
1393 private static String resolveIssueMessage(Exception e) {
1394 if (e instanceof ImportFailureException)
1396 if (e.getCause() != null && e.getCause() instanceof ImportFailureException)
1398 if (e instanceof SCLDatabaseException) {
1399 SCLDatabaseException ee = (SCLDatabaseException) e;
1400 return ee.getMessage();
1402 if (LOGGER.isDebugEnabled())
1403 LOGGER.debug("", e);
1404 return e.getMessage();