/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.syncope.core.rest.data;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.validation.ValidationException;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.apache.syncope.client.mod.AbstractAttributableMod;
import org.apache.syncope.client.mod.AttributeMod;
import org.apache.syncope.client.to.AbstractAttributableTO;
import org.apache.syncope.client.to.AttributeTO;
import org.apache.syncope.client.validation.SyncopeClientCompositeErrorException;
import org.apache.syncope.client.validation.SyncopeClientException;
import org.apache.syncope.core.persistence.beans.AbstractAttr;
import org.apache.syncope.core.persistence.beans.AbstractAttrValue;
import org.apache.syncope.core.persistence.beans.AbstractAttributable;
import org.apache.syncope.core.persistence.beans.AbstractDerAttr;
import org.apache.syncope.core.persistence.beans.AbstractDerSchema;
import org.apache.syncope.core.persistence.beans.AbstractSchema;
import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
import org.apache.syncope.core.persistence.beans.AbstractVirSchema;
import org.apache.syncope.core.persistence.beans.ExternalResource;
import org.apache.syncope.core.persistence.beans.SchemaMapping;
import org.apache.syncope.core.persistence.dao.AttrDAO;
import org.apache.syncope.core.persistence.dao.AttrValueDAO;
import org.apache.syncope.core.persistence.dao.ConfDAO;
import org.apache.syncope.core.persistence.dao.DerAttrDAO;
import org.apache.syncope.core.persistence.dao.DerSchemaDAO;
import org.apache.syncope.core.persistence.dao.MembershipDAO;
import org.apache.syncope.core.persistence.dao.PolicyDAO;
import org.apache.syncope.core.persistence.dao.ResourceDAO;
import org.apache.syncope.core.persistence.dao.RoleDAO;
import org.apache.syncope.core.persistence.dao.SchemaDAO;
import org.apache.syncope.core.persistence.dao.UserDAO;
import org.apache.syncope.core.persistence.dao.VirAttrDAO;
import org.apache.syncope.core.persistence.dao.VirSchemaDAO;
import org.apache.syncope.core.propagation.PropagationByResource;
import org.apache.syncope.core.util.AttributableUtil;
import org.apache.syncope.core.util.JexlUtil;
import org.apache.syncope.types.AttributableType;
import org.apache.syncope.types.PropagationOperation;
import org.apache.syncope.types.SyncopeClientExceptionType;
public abstract class AbstractAttributableDataBinder {
/**
* Logger.
*/
protected static final Logger LOG = LoggerFactory.getLogger(AbstractAttributableDataBinder.class);
@Autowired
protected ConfDAO confDAO;
@Autowired
protected RoleDAO roleDAO;
@Autowired
protected SchemaDAO schemaDAO;
@Autowired
protected DerSchemaDAO derivedSchemaDAO;
@Autowired
protected VirSchemaDAO virtualSchemaDAO;
@Autowired
protected AttrDAO attributeDAO;
@Autowired
protected DerAttrDAO derAttrDAO;
@Autowired
protected VirAttrDAO virAttrDAO;
@Autowired
protected AttrValueDAO attributeValueDAO;
@Autowired
protected UserDAO userDAO;
@Autowired
protected ResourceDAO resourceDAO;
@Autowired
protected MembershipDAO membershipDAO;
@Autowired
protected PolicyDAO policyDAO;
@Autowired
private JexlUtil jexlUtil;
private <T extends AbstractSchema> T getSchema(final String schemaName, final Class<T> reference) {
T schema = null;
if (StringUtils.isNotBlank(schemaName)) {
schema = schemaDAO.find(schemaName, reference);
// safely ignore invalid schemas from AttributeTO
// see http://code.google.com/p/syncope/issues/detail?id=17
if (schema == null) {
LOG.debug("Ignoring invalid schema {}", schemaName);
} else if (schema.isReadonly()) {
schema = null;
LOG.debug("Ignoring virtual or readonly schema {}", schemaName);
}
}
return schema;
}
private <T extends AbstractDerSchema> T getDerivedSchema(final String derSchemaName, final Class<T> reference) {
T derivedSchema = null;
if (StringUtils.isNotBlank(derSchemaName)) {
derivedSchema = derivedSchemaDAO.find(derSchemaName, reference);
if (derivedSchema == null) {
LOG.debug("Ignoring invalid derived schema {}", derSchemaName);
}
}
return derivedSchema;
}
private <T extends AbstractVirSchema> T getVirtualSchema(final String virSchemaName, final Class<T> reference) {
T virtualSchema = null;
if (StringUtils.isNotBlank(virSchemaName)) {
virtualSchema = virtualSchemaDAO.find(virSchemaName, reference);
if (virtualSchema == null) {
LOG.debug("Ignoring invalid virtual schema {}", virSchemaName);
}
}
return virtualSchema;
}
private ExternalResource getResource(final String resourceName) {
ExternalResource resource = resourceDAO.find(resourceName);
if (resource == null) {
LOG.debug("Ignoring invalid resource {} ", resourceName);
}
return resource;
}
protected void fillAttribute(final List<String> values, final AttributableUtil attributableUtil,
final AbstractSchema schema, final AbstractAttr attribute, final SyncopeClientException invalidValues) {
// if the schema is multivalue, all values are considered for
// addition, otherwise only the fist one - if provided - is
// considered
List<String> valuesProvided = schema.isMultivalue()
? values
: (values.isEmpty()
? Collections.EMPTY_LIST
: Collections.singletonList(values.iterator().next()));
for (String value : valuesProvided) {
if (value == null || value.isEmpty()) {
LOG.debug("Null value for {}, ignoring", schema.getName());
} else {
try {
attribute.addValue(value, attributableUtil);
} catch (ValidationException e) {
LOG.error("Invalid value for attribute " + schema.getName() + ": " + value, e);
invalidValues.addElement(schema.getName() + ": " + value);
}
}
}
}
private boolean evaluateMandatoryCondition(final String mandatoryCondition,
final List<? extends AbstractAttr> attributes) {
JexlContext jexlContext = new MapContext();
jexlUtil.addAttrsToContext(attributes, jexlContext);
return Boolean.parseBoolean(jexlUtil.evaluate(mandatoryCondition, jexlContext));
}
private boolean evaluateMandatoryCondition(final ExternalResource resource,
final List<? extends AbstractAttr> attributes, final String intAttrName,
final AttributableUtil attributableUtil) {
boolean result = false;
for (Iterator<SchemaMapping> itor = resource.getMappings(intAttrName, attributableUtil.intMappingType()).
iterator(); itor.hasNext() && !result;) {
SchemaMapping mapping = itor.next();
result |= evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributes);
}
return result;
}
private boolean evaluateMandatoryCondition(final Collection<ExternalResource> resources,
final List<? extends AbstractAttr> attributes, final String intAttrName,
final AttributableUtil attributableUtil) {
boolean result = false;
ExternalResource resource;
for (Iterator<ExternalResource> itor = resources.iterator(); itor.hasNext() && !result;) {
resource = itor.next();
if (resource.isForceMandatoryConstraint()) {
result |= evaluateMandatoryCondition(resource, attributes, intAttrName, attributableUtil);
}
}
return result;
}
private SyncopeClientException checkMandatory(final AttributableUtil attributableUtil,
final AbstractAttributable attributable) {
SyncopeClientException requiredValuesMissing = new SyncopeClientException(
SyncopeClientExceptionType.RequiredValuesMissing);
LOG.debug("Check mandatory constraint among resources {}", attributable.getResources());
// Check if there is some mandatory schema defined for which no value
// has been provided
List<AbstractSchema> allSchemas = schemaDAO.findAll(attributableUtil.schemaClass());
for (AbstractSchema schema : allSchemas) {
if (attributable.getAttribute(schema.getName()) == null
&& !schema.isReadonly()
&& (evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable.getAttributes()) || evaluateMandatoryCondition(
attributable.getResources(), attributable.getAttributes(), schema.getName(),
attributableUtil))) {
LOG.error("Mandatory schema " + schema.getName() + " not provided with values");
requiredValuesMissing.addElement(schema.getName());
}
}
return requiredValuesMissing;
}
public PropagationByResource fillVirtual(final AbstractAttributable attributable,
final Set<String> vAttrsToBeRemoved, final Set<AttributeMod> vAttrsToBeUpdated,
final AttributableUtil attributableUtil) {
PropagationByResource propByRes = new PropagationByResource();
// 1. virtual attributes to be removed
for (String vAttrToBeRemoved : vAttrsToBeRemoved) {
AbstractVirSchema virtualSchema = getVirtualSchema(vAttrToBeRemoved, attributableUtil.virtualSchemaClass());
if (virtualSchema != null) {
AbstractVirAttr virtualAttribute = attributable.getVirtualAttribute(virtualSchema.getName());
if (virtualAttribute == null) {
LOG.debug("No virtual attribute found for schema {}", virtualSchema.getName());
} else {
attributable.removeVirtualAttribute(virtualAttribute);
virAttrDAO.delete(virtualAttribute);
}
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (virtualSchema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.virtualIntMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
// TODO: must be avoided to use virtual attribute as AccountId
if (mapping.isAccountid() && virtualAttribute != null
&& !virtualAttribute.getValues().isEmpty()) {
propByRes.addOldAccountId(mapping.getResource().getName(), virtualAttribute.getValues().get(
0));
}
}
}
}
}
LOG.debug("Virtual attributes to be removed:\n{}", propByRes);
// 2. virtual attributes to be updated
for (AttributeMod vAttrToBeUpdated : vAttrsToBeUpdated) {
AbstractVirSchema virtualSchema = getVirtualSchema(vAttrToBeUpdated.getSchema(), attributableUtil.
virtualSchemaClass());
if (virtualSchema != null) {
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (virtualSchema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.virtualIntMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
}
}
AbstractVirAttr virtualAttribute = attributable.getVirtualAttribute(virtualSchema.getName());
if (virtualAttribute == null) {
virtualAttribute = attributableUtil.newVirtualAttribute();
virtualAttribute.setVirtualSchema(virtualSchema);
attributable.addVirtualAttribute(virtualAttribute);
}
final List<String> values = new ArrayList<String>(virtualAttribute.getValues());
values.removeAll(vAttrToBeUpdated.getValuesToBeRemoved());
values.addAll(vAttrToBeUpdated.getValuesToBeAdded());
virtualAttribute.setValues(values);
// Owner cannot be specified before otherwise a virtual attribute remove will be invalidated.
virtualAttribute.setOwner(attributable);
}
}
LOG.debug("Virtual attributes to be added:\n{}", propByRes);
return propByRes;
}
protected PropagationByResource fill(final AbstractAttributable attributable,
final AbstractAttributableMod attributableMod, final AttributableUtil attributableUtil,
final SyncopeClientCompositeErrorException compositeErrorException)
throws SyncopeClientCompositeErrorException {
PropagationByResource propByRes = new PropagationByResource();
SyncopeClientException invalidValues = new SyncopeClientException(SyncopeClientExceptionType.InvalidValues);
// 1. resources to be removed
ExternalResource resource;
for (String resourceToBeRemoved : attributableMod.getResourcesToBeRemoved()) {
resource = getResource(resourceToBeRemoved);
if (resource != null) {
propByRes.add(PropagationOperation.DELETE, resource.getName());
attributable.removeResource(resource);
}
}
LOG.debug("Resources to be removed:\n{}", propByRes);
// 2. resources to be added
for (String resourceToBeAdded : attributableMod.getResourcesToBeAdded()) {
resource = getResource(resourceToBeAdded);
if (resource != null) {
propByRes.add(PropagationOperation.CREATE, resource.getName());
attributable.addResource(resource);
}
}
LOG.debug("Resources to be added:\n{}", propByRes);
AbstractSchema schema;
AbstractAttr attribute;
AbstractDerSchema derivedSchema;
AbstractDerAttr derivedAttribute;
// 3. attributes to be removed
for (String attributeToBeRemoved : attributableMod.getAttributesToBeRemoved()) {
schema = getSchema(attributeToBeRemoved, attributableUtil.schemaClass());
if (schema != null) {
attribute = attributable.getAttribute(schema.getName());
if (attribute == null) {
LOG.debug("No attribute found for schema {}", schema);
} else {
String newValue = null;
for (AttributeMod mod : attributableMod.getAttributesToBeUpdated()) {
if (schema.getName().equals(mod.getSchema())) {
newValue = mod.getValuesToBeAdded().get(0);
}
}
if (!schema.isUniqueConstraint() || (!attribute.getUniqueValue().getStringValue().equals(newValue))) {
attributable.removeAttribute(attribute);
attributeDAO.delete(attribute.getId(), attributableUtil.attributeClass());
}
}
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (schema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.intMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
if (mapping.isAccountid() && attribute != null && !attribute.getValuesAsStrings().isEmpty()) {
propByRes.addOldAccountId(mapping.getResource().getName(), attribute.getValuesAsStrings().
iterator().next());
}
}
}
}
}
LOG.debug("Attributes to be removed:\n{}", propByRes);
// 4. attributes to be updated
Set<Long> valuesToBeRemoved;
List<String> valuesToBeAdded;
for (AttributeMod attributeMod : attributableMod.getAttributesToBeUpdated()) {
schema = getSchema(attributeMod.getSchema(), attributableUtil.schemaClass());
if (schema != null) {
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (schema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.intMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
}
}
attribute = attributable.getAttribute(schema.getName());
if (attribute == null) {
attribute = attributableUtil.newAttribute();
attribute.setSchema(schema);
attribute.setOwner(attributable);
attributable.addAttribute(attribute);
}
// 1.1 remove values
valuesToBeRemoved = new HashSet<Long>();
for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {
if (attribute.getSchema().isUniqueConstraint()) {
if (attribute.getUniqueValue() != null
&& valueToBeRemoved.equals(attribute.getUniqueValue().getValueAsString())) {
valuesToBeRemoved.add(attribute.getUniqueValue().getId());
}
} else {
for (AbstractAttrValue mav : attribute.getValues()) {
if (valueToBeRemoved.equals(mav.getValueAsString())) {
valuesToBeRemoved.add(mav.getId());
}
}
}
}
for (Long attributeValueId : valuesToBeRemoved) {
attributeValueDAO.delete(attributeValueId, attributableUtil.attributeValueClass());
}
// 1.2 add values
valuesToBeAdded = attributeMod.getValuesToBeAdded();
if (valuesToBeAdded != null
&& !valuesToBeAdded.isEmpty()
&& (!schema.isUniqueConstraint() || attribute.getUniqueValue() == null || !valuesToBeAdded.
iterator().next().equals(attribute.getUniqueValue().getValueAsString()))) {
fillAttribute(attributeMod.getValuesToBeAdded(), attributableUtil, schema, attribute, invalidValues);
}
// if no values are in, the attribute can be safely removed
if (attribute.getValuesAsStrings().isEmpty()) {
attributeDAO.delete(attribute);
}
}
}
if (!invalidValues.isEmpty()) {
compositeErrorException.addException(invalidValues);
}
LOG.debug("Attributes to be updated:\n{}", propByRes);
// 5. derived attributes to be removed
for (String derivedAttributeToBeRemoved : attributableMod.getDerivedAttributesToBeRemoved()) {
derivedSchema = getDerivedSchema(derivedAttributeToBeRemoved, attributableUtil.derivedSchemaClass());
if (derivedSchema != null) {
derivedAttribute = attributable.getDerivedAttribute(derivedSchema.getName());
if (derivedAttribute == null) {
LOG.debug("No derived attribute found for schema {}", derivedSchema.getName());
} else {
derAttrDAO.delete(derivedAttribute);
}
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (derivedSchema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.derivedIntMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
if (mapping.isAccountid() && derivedAttribute != null
&& !derivedAttribute.getValue(attributable.getAttributes()).isEmpty()) {
propByRes.addOldAccountId(mapping.getResource().getName(),
derivedAttribute.getValue(attributable.getAttributes()));
}
}
}
}
}
LOG.debug("Derived attributes to be removed:\n{}", propByRes);
// 6. derived attributes to be added
for (String derivedAttributeToBeAdded : attributableMod.getDerivedAttributesToBeAdded()) {
derivedSchema = getDerivedSchema(derivedAttributeToBeAdded, attributableUtil.derivedSchemaClass());
if (derivedSchema != null) {
for (SchemaMapping mapping : resourceDAO.findAllMappings()) {
if (derivedSchema.getName().equals(mapping.getIntAttrName())
&& mapping.getIntMappingType() == attributableUtil.derivedIntMappingType()
&& mapping.getResource() != null
&& attributable.getResources().contains(mapping.getResource())) {
propByRes.add(PropagationOperation.UPDATE, mapping.getResource().getName());
}
}
derivedAttribute = attributableUtil.newDerivedAttribute();
derivedAttribute.setDerivedSchema(derivedSchema);
derivedAttribute.setOwner(attributable);
attributable.addDerivedAttribute(derivedAttribute);
}
}
LOG.debug("Derived attributes to be added:\n{}", propByRes);
// 7. virtual attributes: for users this is delegated to PropagationManager
if (AttributableType.USER != attributableUtil.getType()) {
fillVirtual(attributable, attributableMod.getVirtualAttributesToBeRemoved(), attributableMod.
getVirtualAttributesToBeUpdated(), attributableUtil);
}
// Finally, check if mandatory values are missing
SyncopeClientException requiredValuesMissing = checkMandatory(attributableUtil, attributable);
if (!requiredValuesMissing.isEmpty()) {
compositeErrorException.addException(requiredValuesMissing);
}
// Throw composite exception if there is at least one element set
// in the composing exceptions
if (compositeErrorException.hasExceptions()) {
throw compositeErrorException;
}
return propByRes;
}
/**
* Add virtual attributes and specify values to be propagated.
*
* @param attributable attributable.
* @param vAttrs virtual attributes to be added.
* @param attributableUtil attributable util.
*/
public void fillVirtual(final AbstractAttributable attributable, final List<AttributeTO> vAttrs,
final AttributableUtil attributableUtil) {
for (AttributeTO attributeTO : vAttrs) {
AbstractVirAttr virtualAttribute = attributable.getVirtualAttribute(attributeTO.getSchema());
if (virtualAttribute == null) {
AbstractVirSchema virtualSchema = getVirtualSchema(attributeTO.getSchema(), attributableUtil.
virtualSchemaClass());
if (virtualSchema != null) {
virtualAttribute = attributableUtil.newVirtualAttribute();
virtualAttribute.setVirtualSchema(virtualSchema);
virtualAttribute.setOwner(attributable);
attributable.addVirtualAttribute(virtualAttribute);
virtualAttribute.setValues(attributeTO.getValues());
}
} else {
virtualAttribute.setValues(attributeTO.getValues());
}
}
}
protected void fill(final AbstractAttributable attributable, final AbstractAttributableTO attributableTO,
final AttributableUtil attributableUtil, final SyncopeClientCompositeErrorException compositeErrorException)
throws SyncopeClientCompositeErrorException {
// 1. attributes
SyncopeClientException invalidValues = new SyncopeClientException(SyncopeClientExceptionType.InvalidValues);
AbstractSchema schema;
AbstractAttr attribute;
// Only consider attributeTO with values
for (AttributeTO attributeTO : attributableTO.getAttributes()) {
if (attributeTO.getValues() != null && !attributeTO.getValues().isEmpty()) {
schema = getSchema(attributeTO.getSchema(), attributableUtil.schemaClass());
if (schema != null) {
attribute = attributable.getAttribute(schema.getName());
if (attribute == null) {
attribute = attributableUtil.newAttribute();
attribute.setSchema(schema);
}
fillAttribute(attributeTO.getValues(), attributableUtil, schema, attribute, invalidValues);
if (!attribute.getValuesAsStrings().isEmpty()) {
attributable.addAttribute(attribute);
attribute.setOwner(attributable);
}
}
}
}
if (!invalidValues.isEmpty()) {
compositeErrorException.addException(invalidValues);
}
SyncopeClientException requiredValuesMissing = checkMandatory(attributableUtil, attributable);
if (!requiredValuesMissing.isEmpty()) {
compositeErrorException.addException(requiredValuesMissing);
}
// 2. derived attributes
AbstractDerSchema derivedSchema;
AbstractDerAttr derivedAttribute;
for (AttributeTO attributeTO : attributableTO.getDerivedAttributes()) {
derivedSchema = getDerivedSchema(attributeTO.getSchema(), attributableUtil.derivedSchemaClass());
if (derivedSchema != null) {
derivedAttribute = attributableUtil.newDerivedAttribute();
derivedAttribute.setDerivedSchema(derivedSchema);
derivedAttribute.setOwner(attributable);
attributable.addDerivedAttribute(derivedAttribute);
}
}
// 3. user virtual attributes will be valued by the propagation manager only (if needed).
if (AttributableType.USER == attributableUtil.getType()) {
for (AttributeTO vattrTO : attributableTO.getVirtualAttributes()) {
AbstractVirSchema uVirSchema = getVirtualSchema(vattrTO.getSchema(),
attributableUtil.virtualSchemaClass());
if (uVirSchema != null) {
AbstractVirAttr vattr = attributableUtil.newVirtualAttribute();
vattr.setVirtualSchema(uVirSchema);
vattr.setOwner(attributable);
attributable.addVirtualAttribute(vattr);
}
}
}
fillVirtual(attributable, attributableTO.getVirtualAttributes(), attributableUtil);
// 4. resources
ExternalResource resource;
for (String resourceName : attributableTO.getResources()) {
resource = getResource(resourceName);
if (resource != null) {
attributable.addResource(resource);
}
}
// Throw composite exception if there is at least one element set
// in the composing exceptions
if (compositeErrorException.hasExceptions()) {
throw compositeErrorException;
}
}
protected void fillTO(final AbstractAttributableTO abstractAttributableTO,
final Collection<? extends AbstractAttr> attributes,
final Collection<? extends AbstractDerAttr> derivedAttributes,
final Collection<? extends AbstractVirAttr> virtualAttributes, final Collection<ExternalResource> resources) {
AttributeTO attributeTO;
for (AbstractAttr attribute : attributes) {
attributeTO = new AttributeTO();
attributeTO.setSchema(attribute.getSchema().getName());
attributeTO.setValues(attribute.getValuesAsStrings());
attributeTO.setReadonly(attribute.getSchema().isReadonly());
abstractAttributableTO.addAttribute(attributeTO);
}
for (AbstractDerAttr derivedAttribute : derivedAttributes) {
attributeTO = new AttributeTO();
attributeTO.setSchema(derivedAttribute.getDerivedSchema().getName());
attributeTO.addValue(derivedAttribute.getValue(attributes));
attributeTO.setReadonly(true);
abstractAttributableTO.addDerivedAttribute(attributeTO);
}
for (AbstractVirAttr virtualAttribute : virtualAttributes) {
attributeTO = new AttributeTO();
attributeTO.setSchema(virtualAttribute.getVirtualSchema().getName());
attributeTO.setValues(virtualAttribute.getValues());
attributeTO.setReadonly(false);
abstractAttributableTO.addVirtualAttribute(attributeTO);
}
for (ExternalResource resource : resources) {
abstractAttributableTO.addResource(resource.getName());
}
}
}