package org.simantics.document.server; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.type.Datatype; import org.simantics.db.DirectStatements; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.primitiverequest.Adapter; import org.simantics.db.common.procedure.adapter.TransientCacheListener; import org.simantics.db.common.request.BinaryRead; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.request.WriteResultRequest; import org.simantics.db.common.utils.Logger; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.function.All; import org.simantics.db.layer0.request.ProjectModels; import org.simantics.db.layer0.request.PropertyInfo; import org.simantics.db.layer0.request.PropertyInfoRequest; import org.simantics.db.layer0.request.VariableProperty; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.request.VariableValueWithBinding; import org.simantics.db.layer0.scl.SCLDatabaseException; import org.simantics.db.layer0.variable.ConstantPropertyVariable; import org.simantics.db.layer0.variable.ProxyChildVariable; import org.simantics.db.layer0.variable.ProxySessionRequest; import org.simantics.db.layer0.variable.ProxyVariableSupport; import org.simantics.db.layer0.variable.ProxyVariables; import org.simantics.db.layer0.variable.StandardAssertedGraphPropertyVariable; import org.simantics.db.layer0.variable.StandardGraphPropertyVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.VariableMap; import org.simantics.db.layer0.variable.VariableMapImpl; import org.simantics.db.layer0.variable.Variables; import org.simantics.db.service.DirectQuerySupport; import org.simantics.document.base.ontology.DocumentationResource; import org.simantics.document.server.bean.Command; import org.simantics.document.server.bean.DataDefinition; import org.simantics.document.server.handler.AbstractEventHandler; import org.simantics.document.server.handler.AbstractResponseHandler; import org.simantics.document.server.handler.EventHandler; import org.simantics.document.server.io.CommandContext; import org.simantics.document.server.io.CommandContextImpl; import org.simantics.document.server.io.CommandContextMutable; import org.simantics.document.server.io.CommandResult; import org.simantics.document.server.io.IConsole; import org.simantics.document.server.request.NodeRequest; import org.simantics.document.server.request.ServerSCLHandlerValueRequest; import org.simantics.document.server.request.ServerSCLValueRequest; import org.simantics.document.server.serverResponse.ServerResponse; import org.simantics.document.server.serverResponse.SuccessResponse; import org.simantics.document.server.state.StateNodeManager; import org.simantics.document.server.state.StateRealm; import org.simantics.document.server.state.StateSessionManager; import org.simantics.modeling.ModelingResources; import org.simantics.modeling.services.CaseInsensitiveComponentFunctionNamingStrategy; import org.simantics.modeling.services.ComponentNamingStrategy; import org.simantics.operation.Layer0X; import org.simantics.project.IProject; import org.simantics.scl.compiler.module.repository.ImportFailureException; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.scl.runtime.SCLContext; import org.simantics.scl.runtime.function.Function; import org.simantics.scl.runtime.function.Function1; import org.simantics.scl.runtime.function.FunctionImpl1; import org.simantics.scl.runtime.function.FunctionImpl4; import org.simantics.scl.runtime.reporting.SCLReportingHandler; import org.simantics.scl.runtime.tuple.Tuple; import org.simantics.scl.runtime.tuple.Tuple0; import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.scl.runtime.tuple.Tuple3; import org.simantics.scl.runtime.tuple.Tuple4; import org.simantics.scl.runtime.tuple.Tuple5; import org.simantics.simulation.experiment.IExperiment; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.simulation.project.IExperimentManager; import org.simantics.structural2.variables.Connection; import org.simantics.structural2.variables.StandardProceduralChildVariable; import org.simantics.structural2.variables.VariableConnectionPointDescriptor; import org.slf4j.LoggerFactory; import gnu.trove.map.hash.THashMap; public class Functions { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Functions.class); @SCLValue(type = "VariableMap") public static VariableMap primitiveProperties = new VariableMapImpl() { private void storePropertyValueAndExceptions(ReadGraph graph, Variable parent, String name, Variable property, Map map) { try { Object value = property.getValue(graph); map.put(name, new ConstantPropertyVariable(parent, name, value, null)); } catch (DatabaseException e) { Variable propertyExceptions = map.get(NodeRequest.PROPERTY_VALUE_EXCEPTIONS); Map exceptionMap; if (propertyExceptions == null) { exceptionMap = new TreeMap(); propertyExceptions = new ConstantPropertyVariable(parent, NodeRequest.PROPERTY_VALUE_EXCEPTIONS, exceptionMap, null); map.put(NodeRequest.PROPERTY_VALUE_EXCEPTIONS, propertyExceptions); } else { try { exceptionMap = propertyExceptions.getValue(graph); } catch (DatabaseException e1) { Logger.defaultLogError(e1); return; } } String label = name; try { label = property.getLabel(graph); } catch (DatabaseException e2) { } exceptionMap.put(label, e); } } @Override public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException { return All.getStandardPropertyDomainPropertyVariableFromValue(graph, context, name); } @Override public Map getVariables(final ReadGraph graph, Variable context, Map map) throws DatabaseException { if(map == null) map = new HashMap(); Variable parent = context.getParent(graph); DocumentationResource DOC = DocumentationResource.getInstance(graph); if(parent instanceof StandardProceduralChildVariable) { StandardProceduralChildVariable procedural = (StandardProceduralChildVariable)parent; for(Variable property : procedural.getProperties(graph/*, DocumentationResource.URIs.Document_AttributeRelation*/)) { if(property instanceof StandardAssertedGraphPropertyVariable) { StandardAssertedGraphPropertyVariable ass = (StandardAssertedGraphPropertyVariable)property; if("dataDefinitions".equals(ass.property.name) || "commands".equals(ass.property.name) || "pollingFunction".equals(ass.property.name)) { storePropertyValueAndExceptions(graph, parent, ass.property.name, property, map); } continue; } Resource predicate = property.getPossiblePredicateResource(graph); if(predicate != null) { PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate)); if(info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) { Variable prop = parent.getProperty(graph, predicate); storePropertyValueAndExceptions(graph, parent, info.name, prop, map); } } } } else { Resource parentRes = parent.getRepresents(graph); { Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_commands); storePropertyValueAndExceptions(graph, parent, "commands", prop, map); } if (graph.getPossibleObject(parentRes, DOC.Properties_dataDefinitions) != null) { Variable prop = new StandardGraphPropertyVariable(graph, parent, DOC.Properties_dataDefinitions); storePropertyValueAndExceptions(graph, parent, "dataDefinitions", prop, map); } DirectQuerySupport dqs = graph.getService(DirectQuerySupport.class); //PrimitivePropertyStatementsProcedure foo = new PrimitivePropertyStatementsProcedure(); DirectStatements ds = dqs.getDirectPersistentStatements(graph, parentRes); for(Statement stm : ds) { Resource predicate = stm.getPredicate(); PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(predicate)); if(info.isHasProperty && info.hasClassification(DocumentationResource.URIs.Document_AttributeRelation)) { Variable prop = new StandardGraphPropertyVariable(graph, parent, predicate); storePropertyValueAndExceptions(graph, parent, info.name, prop, map); } else { Resource definition = graph.getPossibleObject(predicate, DOC.Document_definesAttributeRelation); if(definition != null) { PropertyInfo info2 = graph.syncRequest(new PropertyInfoRequest(definition)); Variable prop = new StandardGraphPropertyVariable(graph, parent, definition); map.put(info2.name, new PrimitiveValueVariable(parent, info2.name, prop)); } } } } return map; } }; static class StandardDocumentProperties implements DocumentProperties { @Override public Collection getKeys(ReadGraph graph, Variable context) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); StandardGraphPropertyVariable asd = new StandardGraphPropertyVariable(graph, context, DOC.Properties_primitiveProperties); Map ps = primitiveProperties.getVariables(graph, asd, null); return ps.keySet(); } @Override public Object getValue(ReadGraph graph, Variable context, String key) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); StandardGraphPropertyVariable asd = new StandardGraphPropertyVariable(graph, context, DOC.Properties_primitiveProperties); Map ps = primitiveProperties.getVariables(graph, asd, null); return ps.get(key).getValue(graph); } } public static DocumentProperties primitiveProperties() throws DatabaseException { return new StandardDocumentProperties(); } @SCLValue(type = "VariableMap") public static VariableMap inputSpaceChildren = new VariableMapImpl() { private Variable getProxy(ReadGraph graph, Variable context) throws DatabaseException { Variable root = Variables.getRootVariable(graph); return new DocumentProxyChildVariable(context, context, root, ProxyChildVariable.CONTEXT_BEGIN); } @Override public Variable getVariable(ReadGraph graph, Variable context, String name) throws DatabaseException { if(ProxyChildVariable.CONTEXT_BEGIN.equals(name)) return getProxy(graph, context); return All.standardChildDomainChildren.getVariable(graph, context, name); } @Override public Map getVariables(ReadGraph graph, Variable context, Map map) throws DatabaseException { map = All.standardChildDomainChildren.getVariables(graph, context, map); if(map == null) map = new THashMap(); map.put(ProxyChildVariable.CONTEXT_BEGIN, getProxy(graph, context)); return map; } }; static class DocumentProxyChildVariable extends ProxyChildVariable implements ProxyVariableSupport { public DocumentProxyChildVariable(Variable base, Variable parent, Variable other, String name) { super(base, parent, other, name); } @Override public Variable create(Variable base, Variable parent, Variable other, String name) { return new DocumentProxyChildVariable(base, parent, other, name); } public Variable getPossibleChild(ReadGraph graph, String name) throws DatabaseException { if(CONTEXT_END.equals(name)) { if(other instanceof ProxyChildVariable) { // The context is also a proxy - let it do the job return super.getPossibleChild(graph, name); } else { return ProxyVariables.tryToOwnRenamed(graph, this, base, CONTEXT_END); } } return super.getPossibleChild(graph, name); } @Override public Variable attachTo(ReadGraph graph, Variable parent) { return attachToRenamed(graph, parent, name); } @Override public Variable attachToRenamed(ReadGraph graph, Variable parent, String name) { if(this.parent.equals(base)) return new DocumentProxyChildVariable(parent, parent, other, name); else return new DocumentProxyChildVariable(base, parent, other, name); } } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable input(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { Variable session = graph.syncRequest(new ProxySessionRequest(context)); DocumentationResource DOC = DocumentationResource.getInstance(graph); String uri = session.getPossiblePropertyValue(graph, DOC.Session_inputURI); if(uri == null) { // TODO HAXX - Please fix this // we have no URI so this probably means that someone has inserted a non-session // into the proxy variable => return that instead return session; } return Variables.getVariable(graph, uri); } public static Variable stateVariable(ReadGraph graph, Variable self) throws DatabaseException { Variable session = graph.syncRequest(new ProxySessionRequest(self)); if (session == null) throw new DatabaseException("No state for " + self.getURI(graph)); return session.getPossibleChild(graph, "__scl__"); } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable state(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { Variable session = graph.syncRequest(new ProxySessionRequest(context)); if (session == null) throw new DatabaseException("No state for " + context.getURI(graph)); return session.getPossibleChild(graph, "__scl__"); } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable icstate(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { Variable session = graph.syncRequest(new ProxySessionRequest(context)); return session.getPossibleChild(graph, "__icstate__"); } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable session(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { return graph.syncRequest(new ProxySessionRequest(context)); } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable experiment(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { // Try if experiment (run) has been used as the input Variable var = input(graph, converter, context); SimulationResource SR = SimulationResource.getInstance(graph); while(var != null && !graph.isInstanceOf(var.getRepresents(graph), SR.Run)) { var = var.getParent(graph); } if(var != null) { IExperiment exp = getExperiment(graph, var); if(exp == null) return null; } return var; } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Variable") public static Variable model(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { Variable var = input(graph, converter, context); ModelingResources MOD = ModelingResources.getInstance(graph); while(var != null && !graph.isInstanceOf(var.getRepresents(graph), MOD.StructuralModel)) { var = var.getParent(graph); } return var; } private static Collection getBroadcasted(ReadGraph graph, Variable target) throws DatabaseException { ArrayList result = new ArrayList(); DocumentationResource DOC = DocumentationResource.getInstance(graph); Variable broadcasted = target.getPossibleProperty(graph, DOC.Relations_broadcasted); if(broadcasted != null) result.add(broadcasted); for(Variable child : DocumentServerUtils.getChildrenInOrdinalOrder(graph, target)) { result.addAll(getBroadcasted(graph, child)); } return result; } private static List getCommands(ReadGraph graph, Collection commandVariables, String trigger, CommandContext constants, boolean broadcast) throws DatabaseException { if(commandVariables.isEmpty()) return Collections.emptyList(); String t = trigger; TreeMap> sequences = new TreeMap>(); DocumentationResource DOC = DocumentationResource.getInstance(graph); int count = 0; for (Variable c : commandVariables) { if(trigger == null) t = c.getName(graph); Connection conn = c.getValue(graph); Variable targetConnectionPoint = DocumentServerUtils.getPossibleCommandTriggerConnectionPoint(graph, c, conn); if (targetConnectionPoint != null) { Variable target = targetConnectionPoint.getParent(graph); if (target != null) { Boolean enabled = target.getPossiblePropertyValue(graph, DOC.Properties_exists, Bindings.BOOLEAN); if(enabled != null && !enabled) continue; Integer ordinal; if (broadcast) { ordinal = ++count; } else { ordinal = 1; try { String o = c.getPossiblePropertyValue(graph, "ordinal"); if(o != null) ordinal = Integer.parseInt(o); } catch (NumberFormatException e) {} } String constantKey = target.getPossiblePropertyValue(graph, "constantKey"); String constantValue = target.getPossiblePropertyValue(graph, "constantValue"); CommandContextMutable newConstants = (CommandContextMutable)constants; if(constantKey != null && constantValue != null) { if(!constantKey.isEmpty()) { newConstants = new CommandContextImpl().merge(constants); newConstants.putString(constantKey, constantValue); } } String requiredKey = target.getPossiblePropertyValue(graph, "requiredKey"); if(requiredKey != null && !requiredKey.isEmpty()) { if (newConstants == constants) { newConstants = new CommandContextImpl().merge(constants); } newConstants.putRow(CommandContext.REQUIRED_KEYS, Collections.singletonList(requiredKey)); } String forbiddenKey = target.getPossiblePropertyValue(graph, "forbiddenKey"); if(forbiddenKey != null && !forbiddenKey.isEmpty()) { if (newConstants == constants) { newConstants = new CommandContextImpl().merge(constants); } newConstants.putRow(CommandContext.FORBIDDEN_KEYS, Collections.singletonList(forbiddenKey)); } if(DOC.Relations_broadcast.equals(targetConnectionPoint.getPredicateResource(graph))) { // This is a broadcast terminal of a container List broadcastCommands = getCommands(graph, getBroadcasted(graph, target), t, newConstants, true); sequences.put(ordinal, broadcastCommands); } else { Command command = new Command(DocumentServerUtils.getId(graph, target), t, targetConnectionPoint.getName(graph), newConstants); sequences.put(ordinal, Collections.singletonList(command)); } } } } List commands = new ArrayList(); for (List commandList : sequences.values()) { for (Command command : commandList) { commands.add(command); } } return commands; } /** * Commands * * @param graph * @param variable * @return * @throws DatabaseException */ public static List commandList(ReadGraph graph, Variable variable) throws DatabaseException { return getCommands(graph, DocumentServerUtils.getTriggerCommands(graph, variable.getParent(graph)), null, new CommandContextImpl(), false); } /** * Data definitions * * @param graph * @param variable * @return * @throws DatabaseException */ public static List dataDefinitions(ReadGraph graph, Variable variable) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); ArrayList dataDefinitions = new ArrayList(); // Find data definition connections for (Variable dataDefinitionRelation : DocumentServerUtils.getDataDefinitions(graph, variable.getParent(graph))) { Connection dataDefinitionConnection = dataDefinitionRelation.getValue(graph); // Find data the other end of definition connection Collection dataDefinitionProviders = DocumentServerUtils.getPossibleOtherConnectionPoints(graph, dataDefinitionRelation, dataDefinitionConnection); if (dataDefinitionProviders != null) { for(Variable dataDefinitionProvider : dataDefinitionProviders) { Variable dataDefinition = dataDefinitionProvider.getParent(graph); if (dataDefinition != null) { // Found other end. Is should contain ONE data // definition connection to the actual data Collection dataCollection = DocumentServerUtils.getDataRelations(graph, dataDefinition); if (dataCollection.size() == 1) { Variable dataRelation = dataCollection.iterator().next(); Connection dataConnection = dataRelation.getValue(graph); // Find data the other end of definition connection Variable dataConnectionPoint = DocumentServerUtils.getPossibleOtherConnectionPoint(graph, dataRelation, dataConnection); if (dataConnectionPoint != null) { Variable data = dataConnectionPoint.getParent(graph); Resource type = dataDefinition.getPossibleType(graph, DOC.Components_Component); if (graph.isInheritedFrom(type, DOC.Components_DefVar)) { String sourceProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_source, Bindings.STRING); String targetProperty = dataDefinition.getPropertyValue(graph, DOC.Properties_target, Bindings.STRING); dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data), sourceProperty, targetProperty)); } else if (graph.isInheritedFrom(type, DOC.Components_DefVars)) { List sourcesProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_sources), String.class); List targetsProperty = toList(dataDefinition.getPropertyValue(graph, DOC.Properties_targets), String.class); for (int i = 0; i < Math.min(sourcesProperty.size(), targetsProperty.size()); i++) { dataDefinitions.add(new DataDefinition(DocumentServerUtils.getId(graph, data), sourcesProperty.get(i), targetsProperty.get(i))); } } } } } } } } return dataDefinitions; } @SuppressWarnings("unchecked") private static List toList(Object o, Class c) { List result = null; if (o instanceof List) { return (List)o; } else if (o instanceof Object[]) { result = new ArrayList(((Object[])o).length); for (T item : (T[])o) { result.add(item); } return result; } else { return Collections.emptyList(); } } @Deprecated public static AbstractEventHandler emptyOnClick(ReadGraph graph) throws DatabaseException { return new EventHandler() { @Override public ServerResponse handle(ReadGraph graph, CommandContext parameters) throws DatabaseException { return null; } }; } @Deprecated public static AbstractEventHandler writeEventHandler(ReadGraph graph, final Variable variable, final Function fn) { final Session session = graph.getSession(); return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { String result = session.sync(new WriteResultRequest() { @Override public String perform(WriteGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Function1 pf = new FunctionImpl1() { @Override public String apply(String key) { return parameters.getString(key); } }; Object response = (String)fn.apply(variable, pf); if(response instanceof String) { return (String)response; } return null; } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); return new SuccessResponse(result); } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } @Deprecated public static AbstractEventHandler readEventHandler(ReadGraph graph, final Variable variable, final Function fn) { final Session session = graph.getSession(); return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { String result = session.sync(new UniqueRead() { @Override public String perform(ReadGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Function1 pf = new FunctionImpl1() { @Override public String apply(String key) { return parameters.getString(key); } }; Object response = (String)fn.apply(variable, pf); if(response instanceof String) { return (String)response; } return null; } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); return new SuccessResponse(result); } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } @Deprecated public static AbstractEventHandler readEventHandler2(ReadGraph graph, final Function fn) { final Session session = graph.getSession(); return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { CommandResult result = session.sync(new UniqueRead() { @Override public CommandResult perform(ReadGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Object response = fn.apply(parameters); if(response instanceof CommandResult) { return (CommandResult)response; } return null; } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); return result; } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } public static AbstractEventHandler responseHandler(ReadGraph graph, Variable self, String function) throws DatabaseException { Variable anyFunction = self.browse(graph, ".#" + function); if(anyFunction == null) return null; final List effects = ServerSCLHandlerValueRequest.getEffects(graph, anyFunction); Function1 fn = anyFunction.getValue(graph); //String expression = anyFunction.getPropertyValue(graph, "expression"); final Session session = graph.getSession(); return new AbstractResponseHandler(fn) { private String formatError(RequestProcessor proc, Throwable t) { try { return proc.syncRequest(new UniqueRead() { @Override public String perform(ReadGraph graph) throws DatabaseException { Variable proxy = ProxyVariables.proxyVariableRoot(graph, anyFunction); String uri2 = proxy.getURI(graph); String uri = self.getParent(graph).getURI(graph); String path = uri.substring(uri2.length()); String expr = anyFunction.getPossiblePropertyValue(graph, "expression"); StringBuilder message = new StringBuilder(); message.append("Handler execution failed\n"); message.append(" handler=" + path + "\n"); message.append(" expression=" + expr + "\n"); message.append(" message=" + t.getMessage() + "\n"); StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); message.append(" stack trace=" + sw); return message.toString(); } }); } catch (DatabaseException e) { return e.getMessage(); } } @Override public CommandResult handle(final CommandContext parameters) { IConsole console = parameters.getValue("__console__"); SCLReportingHandler printer = (console != null) ? new ConsoleSCLReportingHandler(console) : (SCLReportingHandler) SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { Object result = null; if(effects.contains(Types.WRITE_GRAPH)) { result = session.syncRequest(new WriteResultRequest() { @Override public Object perform(WriteGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { return fn.apply(parameters); } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); } else if(effects.contains(Types.READ_GRAPH)) { result = session.sync(new UniqueRead() { @Override public Object perform(ReadGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { return fn.apply(parameters); } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); } else { SCLContext sclContext = SCLContext.getCurrent(); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { result = fn.apply(parameters); } finally { sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } if (result instanceof org.simantics.document.server.serverResponse.Error) { return (CommandResult)result; } if (result instanceof CommandResult) { return (CommandResult)result; } else { CommandContextMutable assignments = new CommandContextImpl(); assignments.putValue("result", result); return new ServerResponse(200, "", assignments); } } catch (Throwable e) { return new org.simantics.document.server.serverResponse.Error(formatError(Simantics.getSession(), e)); } } }; } @Deprecated public static AbstractEventHandler writeEventHandler2(ReadGraph graph, final Function fn) { final Session session = graph.getSession(); return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { CommandResult result = session.syncRequest(new WriteResultRequest() { @Override public CommandResult perform(WriteGraph graph) throws DatabaseException { SCLContext sclContext = SCLContext.getCurrent(); Object oldGraph = sclContext.put("graph", graph); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Object response = fn.apply(parameters); if(response instanceof CommandResult) { return (CommandResult)response; } return null; } finally { sclContext.put("graph", oldGraph); sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } }); return result; } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } @Deprecated public static AbstractEventHandler eventHandler2(ReadGraph graph, final Function fn) { return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { SCLContext sclContext = SCLContext.getCurrent(); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Object response = fn.apply(parameters); if(response instanceof CommandResult) { return (CommandResult)response; } return null; } finally { sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } @Deprecated public static AbstractEventHandler eventHandler(ReadGraph graph, final Function fn) { return new AbstractEventHandler() { @Override public CommandResult handle(final CommandContext parameters) { final SCLReportingHandler printer = (SCLReportingHandler)SCLContext.getCurrent().get(SCLReportingHandler.REPORTING_HANDLER); try { String result = ""; SCLContext sclContext = SCLContext.getCurrent(); Object oldPrinter = sclContext.put(SCLReportingHandler.REPORTING_HANDLER, printer); try { Function1 pf = new FunctionImpl1() { @Override public String apply(String key) { return parameters.getString(key); } }; Object response = (String)fn.apply(pf); if(response instanceof String) { result = (String)response; } } finally { sclContext.put(SCLReportingHandler.REPORTING_HANDLER, oldPrinter); } return new SuccessResponse(result); } catch (Throwable e) { Logger.defaultLogError(e); return new org.simantics.document.server.serverResponse.Error(e.getMessage()); } } }; } @SCLValue(type = "ReadGraph -> Resource -> Variable -> a") public static Object sclValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { return ServerSCLValueRequest.compileAndEvaluate(graph, context); } @SCLValue(type = "ReadGraph -> Resource -> Variable -> a") public static Object sclHandlerValue(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { return ServerSCLHandlerValueRequest.compileAndEvaluate(graph, context); } @SCLValue(type = "ReadGraph -> Resource -> Resource -> ComponentNamingStrategy") public static ComponentNamingStrategy componentNamingStrategy(ReadGraph graph, Resource converter, Resource context) throws DatabaseException { return createComponentNamingStrategy(graph); } public static CaseInsensitiveComponentFunctionNamingStrategy createComponentNamingStrategy(ReadGraph graph) throws DatabaseException { Layer0X L0X = Layer0X.getInstance(graph); @SuppressWarnings({ "unchecked", "rawtypes" }) final Function dependencies = graph.syncRequest(new Adapter(L0X.DependencyResources, Function.class), TransientCacheListener.instance()); @SuppressWarnings("rawtypes") Function moduleNameFunction = new FunctionImpl4>>() { @Override public Object apply(ReadGraph p0, Resource p1, String p2) { return apply(p0, p1, p2); } @SuppressWarnings("unchecked") @Override public List> apply(ReadGraph graph, Resource model, String search, Integer maxResults) { return (List>)dependencies.apply(graph, model, search, maxResults); } }; return new CaseInsensitiveComponentFunctionNamingStrategy("%s%02d", moduleNameFunction); } public static IExperiment getExperiment(ReadGraph graph, Variable variable) throws DatabaseException { if (variable == null) return null; SimulationResource SIMU = SimulationResource.getInstance(graph); Variable var = variable; Resource represents = var.getRepresents(graph); Resource activeRun = null; if (represents != null && graph.isInstanceOf(represents, SIMU.Run)) { activeRun = represents; } IProject project = Simantics.peekProject(); if (activeRun != null && project != null) { IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); if (expMan != null) return expMan.getExperiment(NameUtils.getSafeName(graph, activeRun)); } return null; } public static CommandContextMutable putTuple(CommandContextMutable context, String key, Object tuple) { List list = new ArrayList(); if (tuple instanceof Tuple) { Collections.addAll(list, ((Tuple)tuple).toArray()); } else { list.add(tuple); } context.putRow(key, list); return context; } public static List getTuples(CommandContext context, String key) { List> rows = context.getRows(key); List tuples = new ArrayList(); if (rows != null) { for (List row : rows) { switch (row.size()) { case 0: tuples.add(Tuple0.INSTANCE); break; case 1: tuples.add(row.get(1)); break; case 2: tuples.add(new Tuple2(row.get(0), row.get(1))); break; case 3: tuples.add(new Tuple3(row.get(0), row.get(1), row.get(2))); break; case 4: tuples.add(new Tuple4(row.get(0), row.get(1), row.get(2), row.get(3))); break; case 5: tuples.add(new Tuple5(row.get(0), row.get(1), row.get(2), row.get(3), row.get(4))); break; } } } return tuples; } public static String printContext(CommandContext context) { return context.toString(); } @SCLValue(type = "AbstractEventHandler") public static AbstractEventHandler emptyEvent = new AbstractEventHandler() { @Override public CommandResult handle(CommandContext context) { return null; } }; public static String sclStateKey(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException { String baseURI = base.getURI(graph); String selfURI = self.getURI(graph); String prefix = selfURI.substring(0, selfURI.indexOf(ProxyChildVariable.CONTEXT_BEGIN)); String suffix = selfURI.substring(selfURI.lastIndexOf(ProxyChildVariable.CONTEXT_END) + ProxyChildVariable.CONTEXT_END.length()); String stripped = prefix + suffix; String relative = Variables.getRelativeRVI(baseURI, stripped); return Variables.getRVI(relative, ref); } public static Variable sclStateVariable(ReadGraph graph, Variable base, Variable self, String ref) throws DatabaseException { String id = sclStateKey(graph, base, self, ref); Variable sclVar = base.getPossibleChild(graph, "__scl__"); if(sclVar == null) return null; return sclVar.getPossibleProperty(graph, id); } public static Object sclStateValueOrDefault(ReadGraph graph, Variable base, Variable self, String ref, Object defaultValue) throws DatabaseException { Variable stateVariable = sclStateVariable(graph, base, self, ref); if (stateVariable != null) { return stateVariable.getValue(graph); } else { return defaultValue; } } public static void setSclStateValue(WriteGraph graph, Variable base, Variable self, String ref, Object value) throws DatabaseException { String id = sclStateKey(graph, base, self, ref); StateRealm realm = (StateRealm) StateSessionManager.getInstance().getOrCreateRealm(graph, base.getURI(graph)+"/__scl__"); StateNodeManager nodeManager = (StateNodeManager) realm.getNodeManager(); nodeManager.setState(id, value); } public static Object projectComponentState(ReadGraph graph, Variable self, String ref, Object defaultValue) throws DatabaseException { Resource project = Simantics.getProjectResource(); Variable component = self.getParent(graph); Variable projectVariable = Variables.getVariable(graph, project); return sclStateValueOrDefault(graph, projectVariable, component, ref, defaultValue); } public static void setProjectComponentState(WriteGraph graph, Variable self, String ref, Object value) throws DatabaseException { Resource project = Simantics.getProjectResource(); Variable component = self.getParent(graph); Variable projectVariable = Variables.getVariable(graph, project); setSclStateValue(graph, projectVariable, component, ref, value); } private static Type getSCLType(Object value) throws DatabaseException { Binding b = Bindings.getBindingUnchecked(value.getClass()); Datatype t = b.type(); if(Datatypes.STRING.equals(t)) return Types.STRING; if(Datatypes.DOUBLE.equals(t)) return Types.DOUBLE; throw new DatabaseException("Type not supported"); } public static List documentModelContribution(ReadGraph graph, Resource doc) throws DatabaseException { Resource project = Simantics.getProjectResource(); ArrayList result = new ArrayList(); for(Resource model : graph.syncRequest(new ProjectModels(project))) { result.add(Variables.getVariable(graph, model)); } return result; } public static String documentModelContributionLabel(ReadGraph graph, Variable var) throws DatabaseException { return var.getName(graph); } public static Object getPropertyValueCached(ReadGraph graph, Variable variable, String name, Binding binding) throws DatabaseException { Variable property = graph.syncRequest(new VariableProperty(variable, name)); return graph.syncRequest(new VariableValueWithBinding(property, binding)); } public static class ParentExistsRequest extends VariableRead { public ParentExistsRequest(Variable parent) { super(parent); } @Override public Boolean perform(ReadGraph graph) throws DatabaseException { Variable existsProperty = variable.getPossibleProperty(graph, "exists"); if(existsProperty == null) return true; Boolean exists = existsProperty.getPossibleValue(graph, Bindings.BOOLEAN); if (exists == null || !exists) return false; return graph.syncRequest(new ParentExistsRequest(variable.getParent(graph))); } } public static class PathExistsRequest extends VariableRead { public PathExistsRequest(Variable variable) { super(variable); } @Override public Boolean perform(ReadGraph graph) throws DatabaseException { Variable widget = variable.getParent(graph); Boolean exists = widget.getPossiblePropertyValue(graph, "exists"); if (exists == null || !exists) return false; if (!graph.syncRequest(new ParentExistsRequest(widget.getParent(graph)))) return false; DocumentationResource DOC = DocumentationResource.getInstance(graph); Collection cps = widget.getProperties(graph, DocumentationResource.URIs.Relations_parentRelation); for (Variable cp : cps) { Connection conn = cp.getValue(graph); Variable otherCp = DocumentServerUtils.getPossibleChildConnectionPoint(graph, cp, conn); if (otherCp != null) { Variable parentWidget = otherCp.getParent(graph); if (parentWidget.getPropertyValue(graph, "pathExists")) { return true; } } else { Variable parentCp = graph.sync(new BinaryRead(widget, conn) { @Override public Variable perform(ReadGraph graph) throws DatabaseException { DocumentationResource DOC = DocumentationResource.getInstance(graph); Collection descs = parameter2.getConnection2().getConnectionPointDescriptors(graph, parameter, null); for(VariableConnectionPointDescriptor desc : descs) { if (DOC.Relations_partN.equals(desc.getConnectionPointResource(graph))) { return desc.getVariable(graph); } } return null; } }); if (parentCp != null) { Variable parentWidget = parentCp.getParent(graph); if (parentWidget.getPropertyValue(graph, "pathExists")) { return true; } } } } Resource type = widget.getType(graph); return graph.isInheritedFrom(type, DOC.Components_ParentlessComponent) || (graph.isInheritedFrom(type, DOC.DocumentComponent) && cps.isEmpty()); } } @SCLValue(type = "ReadGraph -> Resource -> Variable -> Boolean") public static boolean pathExists(ReadGraph graph, Resource converter, Variable context) throws DatabaseException { return graph.syncRequest(new PathExistsRequest(context)); } public static String compileDocumentSCLValueExpression(ReadGraph graph, Variable context) { try { ServerSCLValueRequest.validate(graph, context); return ""; } catch (Exception e) { return resolveIssueMessage(e); } } private static String resolveIssueMessage(Exception e) { if (e instanceof ImportFailureException) return ""; if (e.getCause() != null && e.getCause() instanceof ImportFailureException) return ""; if (e instanceof SCLDatabaseException) { SCLDatabaseException ee = (SCLDatabaseException) e; return ee.getMessage(); } if (LOGGER.isDebugEnabled()) LOGGER.debug("", e); return e.getMessage(); } }