diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/AbstractEntityAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/AbstractEntityAdaptor.java index c582d20c3b8f8b0d8443a9937f50da3e7ee71771..c2809d864eb76586c92fbea45453fd7fdce27b0d 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/AbstractEntityAdaptor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/AbstractEntityAdaptor.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePropertyTypePE; import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder; import ch.systemsx.cisd.openbis.generic.shared.dto.PropertyTypePE; @@ -45,32 +46,33 @@ public class AbstractEntityAdaptor implements IEntityAdaptor { for (EntityPropertyPE property : propertiesHolder.getProperties()) { - if (property.getEntityTypePropertyType().isDynamic()) - { - // values of dynamic properties can't be referred to - it wouldn't be deterministic - continue; - } - final PropertyTypePE propertyType = - property.getEntityTypePropertyType().getPropertyType(); + EntityTypePropertyTypePE etpt = property.getEntityTypePropertyType(); + final PropertyTypePE propertyType = etpt.getPropertyType(); final String propertyTypeCode = propertyType.getCode(); - final String value; - if (property.getMaterialValue() != null) - { - value = property.getMaterialValue().getCode(); - } else if (property.getVocabularyTerm() != null) - { - value = property.getVocabularyTerm().getCode(); - } else - { - value = property.getValue(); - } - if (propertyType.getTransformation() == null) + if (etpt.isDynamic()) { - addProperty(new BasicPropertyAdaptor(propertyTypeCode, value, property)); + addProperty(new DynamicPropertyAdaptor(propertyTypeCode, this, property)); } else { - addProperty(new XmlPropertyAdaptor(propertyTypeCode, value, property, - propertyType.getTransformation())); + final String value; + if (property.getMaterialValue() != null) + { + value = property.getMaterialValue().getCode(); + } else if (property.getVocabularyTerm() != null) + { + value = property.getVocabularyTerm().getCode(); + } else + { + value = property.getValue(); + } + if (propertyType.getTransformation() == null) + { + addProperty(new BasicPropertyAdaptor(propertyTypeCode, value, property)); + } else + { + addProperty(new XmlPropertyAdaptor(propertyTypeCode, value, property, + propertyType.getTransformation())); + } } } } diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyAdaptor.java new file mode 100644 index 0000000000000000000000000000000000000000..73f22ff36c3fe5aff19a6740fad822fba8c08a15 --- /dev/null +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/DynamicPropertyAdaptor.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.dynamic_property.calculator; + +import ch.systemsx.cisd.openbis.generic.server.dataaccess.IPropertyValueValidator; +import ch.systemsx.cisd.openbis.generic.server.dataaccess.PropertyValidator; +import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant; +import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePropertyTypePE; + +/** + * {@link IEntityPropertyAdaptor} for dynamic property with lazy evaluation and cyclic dependencies + * detection. + * + * @author Piotr Buczek + */ +// TODO 2010-11-05, Piotr Buczek: refactor to use DynamicPropertyEvaluator +class DynamicPropertyAdaptor implements IEntityPropertyAdaptor +{ + private enum State + { + EMPTY, EVALUATING, EVALUATED + } + + private static final IPropertyValueValidator validator = new PropertyValidator(); + + private static final String ERROR_PREFIX = "ERROR: "; + + private State state = State.EMPTY; + + private String value = null; + + private final String code; + + private final EntityPropertyPE propertyPE; + + private final IEntityAdaptor entityAdaptor; + + public DynamicPropertyAdaptor(String code, IEntityAdaptor entityAdaptor, + EntityPropertyPE propertyPE) + { + this.code = code; + this.entityAdaptor = entityAdaptor; + this.propertyPE = propertyPE; + } + + public String propertyTypeCode() + { + return code; + } + + private String doGetValue() + { + switch (state) + { + case EMPTY: + // start evaluation + state = State.EVALUATING; + value = doEvaluate(); + break; + case EVALUATING: + // cycle found - return an error + state = State.EVALUATED; + String errorMsg = + ERROR_PREFIX + "cycle found in dependencies of property " + + propertyTypeCode(); + value = BasicConstant.ERROR_PROPERTY_PREFIX + errorMsg; + break; + case EVALUATED: + // value was already computed + break; + } + return value; + } + + private String doEvaluate() + { + EntityTypePropertyTypePE etpt = propertyPE.getEntityTypePropertyType(); + assert etpt != null; + try + { + // TODO 2010-11-05, Piotr Buczek: use cache + final DynamicPropertyCalculator calculator = + DynamicPropertyCalculator.create(etpt.getScript().getScript()); + calculator.setEntity(entityAdaptor); + final String dynamicValue = calculator.evalAsString(); + final String validatedValue = + validator.validatePropertyValue(etpt.getPropertyType(), dynamicValue); + return validatedValue; + } catch (Exception e) + { + String errorMsg = ERROR_PREFIX + e.getMessage(); + // operationLog.info(errorMsg); + return BasicConstant.ERROR_PROPERTY_PREFIX + errorMsg; + } + } + + public String valueAsString() + { + return doGetValue(); + } + + public String renderedValue() + { + return valueAsString(); + } + + public EntityPropertyPE getPropertyPE() + { + return propertyPE; + } + + // + // Object + // + + @Override + public String toString() + { + return propertyTypeCode() + " " + valueAsString(); + } + +} diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/XmlPropertyAdaptor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/XmlPropertyAdaptor.java index 48d62b804197730da8bc342345a724887aa7ae24..6862cd715b7eabe32fc3e94d19dae614205dcf90 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/XmlPropertyAdaptor.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/dynamic_property/calculator/XmlPropertyAdaptor.java @@ -20,7 +20,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE; import ch.systemsx.cisd.openbis.generic.shared.util.XmlUtils; /** - * {@link IEntityPropertyAdaptor} implementation for xml property. + * {@link IEntityPropertyAdaptor} implementation for xml property with lazy evaluation of rendered + * value using XSLT script. * * @author Piotr Buczek */ @@ -28,6 +29,8 @@ class XmlPropertyAdaptor extends BasicPropertyAdaptor { private final String xsltTransformation; + private String renderedValue = null; + public XmlPropertyAdaptor(String code, String value, EntityPropertyPE propertyPE, String xsltTransformation) { @@ -42,6 +45,15 @@ class XmlPropertyAdaptor extends BasicPropertyAdaptor @Override public String renderedValue() + { + if (renderedValue == null) + { + renderedValue = doRenderValue(); + } + return renderedValue; + } + + private String doRenderValue() { final String xml = super.valueAsString(); return XmlUtils.transform(xsltTransformation, xml);