/* * (C) Copyright 2006-2012 Nuxeo SA (http://nuxeo.com/) and others. * * 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. * * Contributors: * Bogdan Stefanescu * Florent Guillaume */ package org.nuxeo.ecm.core.schema.types; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.nuxeo.ecm.core.schema.types.constraints.Constraint; /** * The implementation for a List type. */ public class ListTypeImpl extends AbstractType implements ListType { private static final long serialVersionUID = 1L; protected static final String DEFAULT_VALUE_SEPARATOR = " "; protected final Type type; protected final Field field; // TODO: should be removed. use field.defaultvalue instead protected String defaultValue; protected int minOccurs; protected int maxOccurs; protected boolean isArray = false; public ListTypeImpl(String schema, String name, Type type, String fieldName, String defaultValue, int flags, Set<Constraint> constraints, int minOccurs, int maxOccurs) { super(null, schema, name); if (fieldName == null) { isArray = true; fieldName = "item"; } this.type = type; // if the list is an array, there's no field constraint (notnull) Collection<Constraint> computedConstraints = isArray ? type.getConstraints() : constraints; field = new FieldImpl(QName.valueOf(fieldName), this, type, defaultValue, flags, computedConstraints); this.minOccurs = minOccurs; this.maxOccurs = maxOccurs; this.defaultValue = defaultValue; } public ListTypeImpl(String schema, String name, Type type, String fieldName, String defaultValue, int minOccurs, int maxOccurs) { this(schema, name, type, fieldName, defaultValue, 0, new HashSet<Constraint>(), minOccurs, maxOccurs); } public ListTypeImpl(String schema, String name, Type type) { this(schema, name, type, null, null, 0, -1); } @Override public void setLimits(int minOccurs, int maxOccurs) { this.minOccurs = minOccurs; this.maxOccurs = maxOccurs; } @Override public void setDefaultValue(String value) { defaultValue = value; } @Override public String getFieldName() { return field.getName().getLocalName(); } @Override public Type getFieldType() { return field.getType(); } @Override public Field getField() { return field; } @Override public Object getDefaultValue() { return type.decode(defaultValue); } public Type getType() { return type; } @Override public int getMinCount() { return minOccurs; } @Override public int getMaxCount() { return maxOccurs; } @Override public boolean isListType() { return true; } @Override public Object decode(String string) { if (StringUtils.isBlank(string)) { return null; } String[] split = string.split(DEFAULT_VALUE_SEPARATOR); List<Object> decoded = new ArrayList<>(split.length); Class<?> klass = null; for (String s : split) { Object o = type.decode(s); if (klass == null && o != null) { klass = o.getClass(); } decoded.add(o); } if (klass == null) { klass = Object.class; } // turn the list into a properly-typed array for the elements Object[] array = (Object[]) Array.newInstance(klass, decoded.size()); return decoded.toArray(array); } @Override @SuppressWarnings("rawtypes") public boolean validate(Object object) throws TypeException { if (object == null) { return true; } if (object instanceof Collection) { return validateCollection((Collection) object); } else if (object.getClass().isArray()) { return validateArray((Object[]) object); } return false; } protected boolean validateArray(Object[] array) { return true; // TODO } @SuppressWarnings("rawtypes") protected boolean validateCollection(Collection col) { return true; // TODO } @Override public Object newInstance() { Object defaultValue = this.defaultValue; if (defaultValue != null) { return defaultValue; } else { // XXX AT: maybe use the type to be more specific on list elements return new ArrayList<Object>(); } } @Override @SuppressWarnings("unchecked") public Object convert(Object object) throws TypeException { if (object instanceof List) { List<Object> list = (List<Object>) object; for (int i = 0, len = list.size(); i < len; i++) { Object value = list.get(i); list.set(i, type.convert(value)); } return object; } throw new TypeException("Incompatible object: " + object.getClass() + " for type " + getName()); } @Override public boolean isArray() { return isArray; } @Override public boolean isScalarList() { return field.getType().isSimpleType(); } }