+package org.simantics.modeling.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.binding.error.BindingException;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.NumberType;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.common.NamedResource;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.request.IsEnumeratedValue;
+import org.simantics.db.common.request.UniqueRead;
+import org.simantics.db.common.utils.CommonDBUtils;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.PropertyInfo;
+import org.simantics.db.layer0.request.PropertyInfoRequest;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.StandardGraphChildVariable;
+import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.scl.CompileProceduralSCLMonitorRequest;
+import org.simantics.modeling.scl.CompileSCLMonitorRequest;
+import org.simantics.operation.Layer0X;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.ui.ErrorLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HeadlessComponentTypePropertiesResultRequest extends UniqueRead<ComponentTypePropertiesResult> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HeadlessComponentTypePropertiesResultRequest.class);
+
+ protected final Resource componentType;
+
+ /**
+ * @param componentTypeViewer
+ */
+ public HeadlessComponentTypePropertiesResultRequest(Resource componentType) {
+ this.componentType = componentType;
+ }
+
+ protected void readSectionSpecificData(ReadGraph graph, ComponentTypeViewerPropertyInfo info) throws DatabaseException {
+ }
+
+ @Override
+ public ComponentTypePropertiesResult perform(ReadGraph graph) throws DatabaseException {
+ List<ComponentTypeViewerPropertyInfo> result = new ArrayList<>();
+ List<NamedResource> connectionPoints = new ArrayList<>();
+ Layer0 L0 = Layer0.getInstance(graph);
+ Layer0X L0X = Layer0X.getInstance(graph);
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+ boolean typeIsImmutable = graph.isImmutable(componentType)
+ || graph.hasStatement(componentType, STR.ComponentType_Locked)
+ || Layer0Utils.isPublished(graph, componentType)
+ || Layer0Utils.isContainerPublished(graph, componentType);
+
+ for(Resource relation : graph.getObjects(componentType, L0.DomainOf)) {
+ if(graph.isSubrelationOf(relation, L0.HasProperty)) {
+ String name = graph.getRelatedValue(relation, L0.HasName);
+ String type = graph.getPossibleRelatedValue(relation, L0.RequiresValueType);
+ String label = graph.getPossibleRelatedValue(relation, L0.HasLabel);
+ if (label == null)
+ label = ""; //$NON-NLS-1$
+ String description = graph.getPossibleRelatedValue(relation, L0.HasDescription);
+ if (description == null)
+ description = ""; //$NON-NLS-1$
+ NumberType numberType = null;
+ if(type == null)
+ type = "Double"; //$NON-NLS-1$
+ String unit = graph.getPossibleRelatedValue(relation, L0X.HasUnit, Bindings.STRING);
+ String defaultValue = "0"; //$NON-NLS-1$
+ String expression = null;
+
+ for(Resource assertion : graph.getAssertedObjects(componentType, relation)) {
+ try {
+ expression = graph.getPossibleRelatedValue(assertion, L0.SCLValue_expression, Bindings.STRING);
+ if(expression != null) {
+ defaultValue = "=" + expression; //$NON-NLS-1$
+ } else if (graph.sync(new IsEnumeratedValue(assertion))) {
+ defaultValue = CommonDBUtils.getEnumerationValueName(graph, assertion);
+ } else {
+ Datatype dt = getPossibleDatatype(graph, assertion);
+ if (dt == null)
+ continue;
+ if (dt instanceof NumberType)
+ numberType = (NumberType) dt;
+ Binding binding = Bindings.getBinding(dt);
+ Object value = graph.getValue(assertion, binding);
+ try {
+ defaultValue = binding.toString(value, true);
+ } catch (BindingException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+ }
+ } catch(DatabaseException e) {
+ ErrorLogger.defaultLogError(e);
+ }
+ }
+
+ String valid = expression != null ? validateMonitorExpression(graph, componentType, relation, expression) : null;
+
+ boolean immutable = typeIsImmutable || graph.isImmutable(relation);
+ ComponentTypeViewerPropertyInfo info =
+ new ComponentTypeViewerPropertyInfo(relation, name, type, defaultValue, numberType, unit, label, description, expression, valid, immutable);
+
+ readSectionSpecificData(graph, info);
+
+ result.add(info);
+
+ } else if (graph.isInstanceOf(relation, STR.ConnectionRelation)) {
+ NamedResource nr = new NamedResource(NameUtils.getSafeName(graph, relation), relation);
+ connectionPoints.add(nr);
+ }
+ }
+ Collections.sort(result);
+ return new ComponentTypePropertiesResult(result, connectionPoints, typeIsImmutable);
+ }
+
+ private Datatype getPossibleDatatype(ReadGraph graph, Resource literal) throws DatabaseException {
+ Binding binding = Bindings.getBindingUnchecked(Datatype.class);
+ for (Resource dataTypeResource : graph.getObjects(literal, Layer0.getInstance(graph).HasDataType)) {
+ Datatype dt = graph.getPossibleValue(dataTypeResource, binding);
+ if (dt != null)
+ return dt;
+ }
+ return null;
+ }
+
+ public static String validateMonitorExpression(final RequestProcessor processor, final Resource componentType, final Resource relation, final String expression) {
+
+ try {
+ return processor.sync(new UniqueRead<String>() {
+
+ @Override
+ public String perform(ReadGraph graph) throws DatabaseException {
+
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+ // TODO: this is a bit hackish but should get the job done in most parts and
+ // importantly indicates something for the user
+ PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheAsyncListener.<PropertyInfo>instance());
+ Variable parent = new StandardGraphChildVariable(null, null, componentType) {
+
+ public Resource getType(ReadGraph graph) throws DatabaseException {
+ return componentType;
+ };
+
+ public Variable getPossibleProperty(ReadGraph graph, String name) throws DatabaseException {
+ Variable prop = super.getPossibleProperty(graph, name);
+ if (prop != null) {
+ return prop;
+ } else {
+ return getChild(graph, name);
+ }
+ };
+ };
+
+ for(Resource literal : graph.getAssertedObjects(componentType, relation)) {
+
+ try {
+ Variable context = new StandardGraphPropertyVariable(parent, null, null, info, literal);
+ if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {
+ CompileProceduralSCLMonitorRequest.compileAndEvaluate(graph, context);
+ } else {
+ compileAndEvaluate(graph, context, expression);
+ }
+
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ int index = msg.indexOf(":"); //$NON-NLS-1$
+ if(index > 0) msg = msg.substring(index);
+ return msg;
+ }
+ }
+ return null;
+ }
+
+ });
+ } catch (DatabaseException e) {
+ LOGGER.error("Could not validate ", e);
+ }
+ return null;
+ }
+
+ public static void compileAndEvaluate(ReadGraph graph, Variable context, String expression) throws DatabaseException {
+ SCLContext sclContext = SCLContext.getCurrent();
+ Object oldGraph = sclContext.get("graph");
+ try {
+ CompileSCLMonitorRequest compileSCLMonitorRequest = new ValidationCompilationRequest(graph, context, expression);
+ Function1<Variable,Object> exp = graph.syncRequest(compileSCLMonitorRequest);
+ sclContext.put("graph", graph);
+ //return exp.apply(context.getParent(graph));
+ } catch (DatabaseException e) {
+ throw (DatabaseException)e;
+ } catch (Throwable t) {
+ throw new DatabaseException(t);
+ } finally {
+ sclContext.put("graph", oldGraph);
+ }
+ }
+
+ private static final class ValidationCompilationRequest extends CompileSCLMonitorRequest {
+ private final String expression;
+
+ private ValidationCompilationRequest(ReadGraph graph, Variable context, String expression)
+ throws DatabaseException {
+ super(graph, context);
+ this.expression = expression;
+ }
+
+ @Override
+ protected String getExpressionText(ReadGraph graph) throws DatabaseException {
+ return expression;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() + 37 * expression.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj) && ((ValidationCompilationRequest)obj).expression.equals(expression);
+ }
+ }
+
+}
\ No newline at end of file