Support for creating shared ontology dump to git
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / utils / HeadlessComponentTypePropertiesResultRequest.java
1 package org.simantics.modeling.utils;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6
7 import org.simantics.databoard.Bindings;
8 import org.simantics.databoard.binding.Binding;
9 import org.simantics.databoard.binding.error.BindingException;
10 import org.simantics.databoard.type.Datatype;
11 import org.simantics.databoard.type.NumberType;
12 import org.simantics.db.ReadGraph;
13 import org.simantics.db.RequestProcessor;
14 import org.simantics.db.Resource;
15 import org.simantics.db.common.NamedResource;
16 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
17 import org.simantics.db.common.request.IsEnumeratedValue;
18 import org.simantics.db.common.request.UniqueRead;
19 import org.simantics.db.common.utils.CommonDBUtils;
20 import org.simantics.db.common.utils.NameUtils;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.db.layer0.request.PropertyInfo;
23 import org.simantics.db.layer0.request.PropertyInfoRequest;
24 import org.simantics.db.layer0.util.Layer0Utils;
25 import org.simantics.db.layer0.variable.StandardGraphChildVariable;
26 import org.simantics.db.layer0.variable.StandardGraphPropertyVariable;
27 import org.simantics.db.layer0.variable.Variable;
28 import org.simantics.layer0.Layer0;
29 import org.simantics.modeling.scl.CompileProceduralSCLMonitorRequest;
30 import org.simantics.modeling.scl.CompileSCLMonitorRequest;
31 import org.simantics.operation.Layer0X;
32 import org.simantics.scl.runtime.SCLContext;
33 import org.simantics.scl.runtime.function.Function1;
34 import org.simantics.structural.stubs.StructuralResource2;
35 import org.simantics.utils.ui.ErrorLogger;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class HeadlessComponentTypePropertiesResultRequest extends UniqueRead<ComponentTypePropertiesResult> {
40     
41     private static final Logger LOGGER = LoggerFactory.getLogger(HeadlessComponentTypePropertiesResultRequest.class);
42
43     protected final Resource componentType;
44
45     /**
46      * @param componentTypeViewer
47      */
48     public HeadlessComponentTypePropertiesResultRequest(Resource componentType) {
49         this.componentType = componentType;
50     }
51
52     protected void readSectionSpecificData(ReadGraph graph, ComponentTypeViewerPropertyInfo info) throws DatabaseException {
53     }
54     
55     public static ComponentTypeViewerPropertyInfo readPropertyInfo(ReadGraph graph, Resource relation, Resource componentType, boolean typeIsImmutable) throws DatabaseException {
56
57         Layer0 L0 = Layer0.getInstance(graph);
58         Layer0X L0X = Layer0X.getInstance(graph);
59         StructuralResource2 STR = StructuralResource2.getInstance(graph);
60
61         String name = graph.getRelatedValue(relation, L0.HasName);
62         String type =  graph.getPossibleRelatedValue(relation, L0.RequiresValueType);
63         String label = graph.getPossibleRelatedValue(relation, L0.HasLabel);
64         if (label == null)
65             label = ""; //$NON-NLS-1$
66         String description = graph.getPossibleRelatedValue(relation, L0.HasDescription);
67         if (description == null)
68             description = ""; //$NON-NLS-1$
69         NumberType numberType = null;
70         if(type == null)
71             type = "Double"; //$NON-NLS-1$
72         String unit = graph.getPossibleRelatedValue(relation, L0X.HasUnit, Bindings.STRING);
73         String defaultValue = "0"; //$NON-NLS-1$
74         String expression = null;
75
76         if(componentType != null) {
77             for(Resource assertion : graph.getAssertedObjects(componentType, relation)) {
78                 try {
79                     expression = graph.getPossibleRelatedValue(assertion, L0.SCLValue_expression, Bindings.STRING);
80                     if(expression != null) {
81                         defaultValue = "=" + expression; //$NON-NLS-1$
82                     } else if (graph.sync(new IsEnumeratedValue(assertion))) {
83                         defaultValue = CommonDBUtils.getEnumerationValueName(graph, assertion);
84                     } else {
85                         Datatype dt = getPossibleDatatype(graph, assertion);
86                         if (dt == null)
87                             continue;
88                         if (dt instanceof NumberType)
89                             numberType = (NumberType) dt;
90                         Binding binding = Bindings.getBinding(dt);
91                         Object value = graph.getValue(assertion, binding);
92                         try {
93                             defaultValue = binding.toString(value, true);
94                         } catch (BindingException e) {
95                             ErrorLogger.defaultLogError(e);
96                         }
97                     }
98                 } catch(DatabaseException e) {
99                     ErrorLogger.defaultLogError(e);
100                 }
101             }
102         }
103
104         String valid = expression != null ? validateMonitorExpression(graph, componentType, relation, expression) : null; 
105
106         boolean immutable = typeIsImmutable || graph.isImmutable(relation);
107         ComponentTypeViewerPropertyInfo info =
108                 new ComponentTypeViewerPropertyInfo(relation, name, type, defaultValue, numberType, unit, label, description, expression, valid, immutable);
109
110         return info;
111             
112     }
113     
114     @Override
115     public ComponentTypePropertiesResult perform(ReadGraph graph) throws DatabaseException {
116         List<ComponentTypeViewerPropertyInfo> result = new ArrayList<>();
117         List<NamedResource> connectionPoints = new ArrayList<>();
118         Layer0 L0 = Layer0.getInstance(graph);
119         StructuralResource2 STR = StructuralResource2.getInstance(graph);
120
121         boolean typeIsImmutable = graph.isImmutable(componentType)
122                 || graph.hasStatement(componentType, STR.ComponentType_Locked)
123                 || Layer0Utils.isPublished(graph, componentType)
124                 || Layer0Utils.isContainerPublished(graph, componentType);
125
126         for(Resource relation : graph.getObjects(componentType, L0.DomainOf)) {
127             if(graph.isSubrelationOf(relation, L0.HasProperty)) {
128                 ComponentTypeViewerPropertyInfo info = readPropertyInfo(graph, relation, componentType, typeIsImmutable);
129                 readSectionSpecificData(graph, info);
130                 result.add(info);
131             } else if (graph.isInstanceOf(relation, STR.ConnectionRelation)) {
132                 NamedResource nr = new NamedResource(NameUtils.getSafeName(graph, relation), relation);
133                 connectionPoints.add(nr);
134             }
135         }
136         
137         Collections.sort(result);
138         
139         return new ComponentTypePropertiesResult(result, connectionPoints, typeIsImmutable);
140         
141     }
142     
143     private static Datatype getPossibleDatatype(ReadGraph graph, Resource literal) throws DatabaseException {
144         Binding binding = Bindings.getBindingUnchecked(Datatype.class);
145         for (Resource dataTypeResource : graph.getObjects(literal, Layer0.getInstance(graph).HasDataType)) {
146             Datatype dt = graph.getPossibleValue(dataTypeResource, binding);
147             if (dt != null)
148                 return dt;
149         }
150         return null;
151     }
152
153     public static String validateMonitorExpression(final RequestProcessor processor, final Resource componentType, final Resource relation, final String expression) {
154
155         try {
156             return processor.sync(new UniqueRead<String>() {
157
158                 @Override
159                 public String perform(ReadGraph graph) throws DatabaseException {
160
161                     StructuralResource2 STR = StructuralResource2.getInstance(graph);
162
163                     // TODO: this is a bit hackish but should get the job done in most parts and
164                     // importantly indicates something for the user
165                     PropertyInfo info = graph.syncRequest(new PropertyInfoRequest(relation), TransientCacheAsyncListener.<PropertyInfo>instance());
166                     Variable parent = new StandardGraphChildVariable(null, null, componentType) {
167                         
168                         public Resource getType(ReadGraph graph) throws DatabaseException {
169                             return componentType;
170                         };
171                         
172                         public Variable getPossibleProperty(ReadGraph graph, String name) throws DatabaseException {
173                             Variable prop = super.getPossibleProperty(graph, name);
174                             if (prop != null) {
175                                 return prop;
176                             } else {
177                                 return getChild(graph, name);
178                             }
179                         };
180                     };
181                     
182                     for(Resource literal : graph.getAssertedObjects(componentType, relation)) {
183
184                         try {
185                             Variable context = new StandardGraphPropertyVariable(parent, null, null, info, literal);
186                             if(graph.isInstanceOf(componentType, STR.ProceduralComponentType)) {
187                                 CompileProceduralSCLMonitorRequest.compileAndEvaluate(graph, context);
188                             } else {
189                                 compileAndEvaluate(graph, context, expression);
190                             }
191                             
192                         } catch (Exception e) {
193                             String msg = e.getMessage();
194                             int index = msg.indexOf(":"); //$NON-NLS-1$
195                             if(index > 0) msg = msg.substring(index);
196                             return msg;
197                         }
198                     }
199                     return null;
200                 }
201                 
202             });
203         } catch (DatabaseException e) {
204             LOGGER.error("Could not validate ", e);
205         }
206         return null;
207     }
208     
209     public static void compileAndEvaluate(ReadGraph graph, Variable context, String expression) throws DatabaseException {
210         SCLContext sclContext = SCLContext.getCurrent();
211         Object oldGraph = sclContext.get("graph");
212         try {
213             CompileSCLMonitorRequest compileSCLMonitorRequest = new ValidationCompilationRequest(graph, context, expression);
214             Function1<Variable,Object> exp = graph.syncRequest(compileSCLMonitorRequest);
215             sclContext.put("graph", graph);
216             //return exp.apply(context.getParent(graph));
217         } catch (DatabaseException e) {
218             throw (DatabaseException)e;
219         } catch (Throwable t) {
220             throw new DatabaseException(t);
221         } finally {
222             sclContext.put("graph", oldGraph);
223         }
224     }
225
226     private static final class ValidationCompilationRequest extends CompileSCLMonitorRequest {
227         private final String expression;
228     
229         private ValidationCompilationRequest(ReadGraph graph, Variable context, String expression)
230                 throws DatabaseException {
231             super(graph, context);
232             this.expression = expression;
233         }
234     
235         @Override
236         protected String getExpressionText(ReadGraph graph) throws DatabaseException {
237             return expression;
238         }
239     
240         @Override
241         public int hashCode() {
242             return super.hashCode() + 37 * expression.hashCode();
243         }
244     
245         @Override
246         public boolean equals(Object obj) {
247             return super.equals(obj) && ((ValidationCompilationRequest)obj).expression.equals(expression);
248         }
249     }
250     
251 }