Java tutorial
/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package com.xpn.xwiki.objects.classes; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.ecs.xhtml.option; import org.apache.ecs.xhtml.select; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.dom.DOMElement; import org.dom4j.io.SAXReader; import org.xwiki.model.EntityType; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.DocumentReferenceResolver; import org.xwiki.model.reference.EntityReference; import org.xwiki.model.reference.EntityReferenceResolver; import org.xwiki.model.reference.EntityReferenceSerializer; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.doc.merge.CollisionException; import com.xpn.xwiki.doc.merge.MergeConfiguration; import com.xpn.xwiki.doc.merge.MergeResult; import com.xpn.xwiki.objects.BaseCollection; import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.objects.BaseProperty; import com.xpn.xwiki.objects.ElementInterface; import com.xpn.xwiki.objects.ObjectDiff; import com.xpn.xwiki.objects.PropertyInterface; import com.xpn.xwiki.objects.meta.MetaClass; import com.xpn.xwiki.objects.meta.PropertyMetaClass; import com.xpn.xwiki.plugin.query.OrderClause; import com.xpn.xwiki.plugin.query.XWikiCriteria; import com.xpn.xwiki.plugin.query.XWikiQuery; import com.xpn.xwiki.validation.XWikiValidationInterface; import com.xpn.xwiki.validation.XWikiValidationStatus; import com.xpn.xwiki.web.Utils; /** * Represents an XClass, and contains XClass properties. Each field from {@link BaseCollection} is of type * {@link PropertyClass} and defines a single XClass property. * * @version $Id: cf56ac6835de029b84958811d9b0f06dffeddefa $ */ public class BaseClass extends BaseCollection<DocumentReference> implements ClassInterface { private String customMapping; private String customClass; private String defaultWeb; private String defaultViewSheet; private String defaultEditSheet; private String validationScript; private String nameField; @SuppressWarnings("unchecked") private EntityReferenceSerializer<EntityReference> localReferenceEntityReferenceSerializer = Utils .getComponent(EntityReferenceSerializer.class, "local/reference"); /** * Used to resolve a string into a proper Document Reference using the current document's reference to fill the * blanks, except for the page name for which the default page name is used instead and for the wiki name for which * the current wiki is used instead of the current document reference's wiki. */ private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver = Utils .getComponent(DocumentReferenceResolver.class, "currentmixed"); /** * Used here to merge setName() and setWiki() calls into the DocumentReference. */ private EntityReferenceResolver<String> relativeEntityReferenceResolver = Utils .getComponent(EntityReferenceResolver.class, "relative"); /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseElement#getReference() */ @Override public DocumentReference getReference() { return getDocumentReference(); } /** * {@inheritDoc} * <p> * Note: This method is overridden to add the deprecation warning so that code using is can see it's deprecated. * * @deprecated since 2.2M2 use {@link #getDocumentReference()} */ @Deprecated @Override public String getName() { return super.getName(); } /** * {@inheritDoc} * <p> * Note: BaseElement#setName() does not support setting reference anymore since 2.4M2. This was broken and has been * replaced by this overridden method. See XWIKI-5285 * * @deprecated since 2.2M2 use {@link #setDocumentReference(org.xwiki.model.reference.DocumentReference)} */ @Deprecated @Override public void setName(String name) { if (this instanceof MetaClass || this instanceof PropertyMetaClass) { super.setName(name); } else { DocumentReference reference = getDocumentReference(); if (reference != null) { EntityReference relativeReference = this.relativeEntityReferenceResolver.resolve(name, EntityType.DOCUMENT); reference.getLastSpaceReference() .setName(relativeReference.extractReference(EntityType.SPACE).getName()); reference.setName(relativeReference.extractReference(EntityType.DOCUMENT).getName()); } else { reference = this.currentMixedDocumentReferenceResolver.resolve(name); } setDocumentReference(reference); } } /** * {@inheritDoc} * <p> * This insures natural ordering between properties. * * @see com.xpn.xwiki.objects.BaseCollection#addField(java.lang.String, com.xpn.xwiki.objects.PropertyInterface) */ @Override public void addField(String name, PropertyInterface element) { Set<String> properties = getPropertyList(); if (!properties.contains(name)) { if (((BaseCollection) element).getNumber() == 0) { ((BaseCollection) element).setNumber(properties.size() + 1); } } super.addField(name, element); } /** * Mark a property as disabled. A disabled property should not be editable, but existing object values are still * kept in the database. * * @param name the name of the property to disable * @since 2.4M2 */ public void disableField(String name) { PropertyClass pclass = (PropertyClass) safeget(name); if (pclass != null) { pclass.setDisabled(true); } } /** * Re-enable a property. This field will appear again in object instances. * * @param name the name of the property to enable * @since 2.4M2 */ public void enableField(String name) { PropertyClass pclass = (PropertyClass) safeget(name); if (pclass != null) { pclass.setDisabled(false); } } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#get(java.lang.String) */ @Override public PropertyInterface get(String name) { return safeget(name); } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#put(java.lang.String, com.xpn.xwiki.objects.PropertyInterface) */ @Override public void put(String name, PropertyInterface property) { safeput(name, property); } /** * Get the list of enabled (the default, normal state) property definitions that exist in this class. The resulting * list is unmodifiable, but the contained elements are live. * * @return an unmodifiable list containing the enabled properties of the class * @see PropertyClass#isDisabled() * @since 2.4M2 */ public List<PropertyClass> getEnabledProperties() { @SuppressWarnings("unchecked") Collection<PropertyClass> allProperties = getFieldList(); if (allProperties == null) { return Collections.emptyList(); } List<PropertyClass> enabledProperties = new ArrayList<PropertyClass>(allProperties.size()); for (PropertyClass property : allProperties) { if (property != null && !property.isDisabled()) { enabledProperties.add(property); } } Collections.sort(enabledProperties); return Collections.unmodifiableList(enabledProperties); } /** * Get the list of disabled property definitions that exist in this class. The resulting list is unmodifiable, but * the contained elements are live. * * @return an unmodifiable list containing the disabled properties of the class * @see PropertyClass#isDisabled() * @since 2.4M2 */ public List<PropertyClass> getDisabledProperties() { @SuppressWarnings("unchecked") Collection<PropertyClass> allProperties = getFieldList(); if (allProperties == null) { return Collections.emptyList(); } List<PropertyClass> disabledProperties = new ArrayList<PropertyClass>(); for (PropertyClass property : allProperties) { if (property != null && property.isDisabled()) { disabledProperties.add(property); } } Collections.sort(disabledProperties); return Collections.unmodifiableList(disabledProperties); } /** * Get the list of disabled properties that exist in a given object. This list is a subset of all the disabled * properties in a class, since the object could have been created and stored before some of the class properties * were added. The resulting list is unmodifiable, but the contained elements are live. * * @param object the instance of this class where the disabled properties must exist * @return an unmodifiable list containing the disabled properties of the given object * @see PropertyClass#isDisabled() * @since 2.4M2 */ public List<PropertyClass> getDisabledObjectProperties(BaseObject object) { List<PropertyClass> disabledProperties = getDisabledProperties(); if (disabledProperties == null) { return Collections.emptyList(); } List<PropertyClass> disabledObjectProperties = new ArrayList<PropertyClass>(disabledProperties.size()); for (PropertyClass property : disabledProperties) { try { if (object.get(property.getName()) != null) { disabledObjectProperties.add(property); } } catch (XWikiException ex) { // Not really gonna happen } } return Collections.unmodifiableList(disabledObjectProperties); } /** * Retrieves deprecated properties of the given object compared to the class. A deprecated property is a property * which exists in the Object but doesn't exist anymore in the Class, or which has the wrong data type. This is used * for synchronization of existing or imported Objects with respect to the modifications of their associated Class. * * @param object the instance of this class where to look for undefined properties * @return an unmodifiable list containing the properties of the object which don't exist in the class * @since 2.4M2 */ public List<BaseProperty> getDeprecatedObjectProperties(BaseObject object) { @SuppressWarnings("unchecked") Collection<BaseProperty> objectProperties = object.getFieldList(); if (objectProperties == null) { return Collections.emptyList(); } List<BaseProperty> deprecatedObjectProperties = new ArrayList<BaseProperty>(); for (BaseProperty property : objectProperties) { if (safeget(property.getName()) == null) { deprecatedObjectProperties.add(property); } else { String propertyClass = ((PropertyClass) safeget(property.getName())).newProperty().getClassType(); String objectPropertyClass = property.getClassType(); if (!propertyClass.equals(objectPropertyClass)) { deprecatedObjectProperties.add(property); } } } return Collections.unmodifiableList(deprecatedObjectProperties); } public BaseProperty fromString(String value) { return null; // To change body of implemented methods use Options | File Templates. } /** * @deprecated since 2.2.3 use {@link com.xpn.xwiki.doc.XWikiDocument#newXObject} */ @Deprecated public BaseCollection newObject(XWikiContext context) throws XWikiException { BaseObject bobj = newCustomClassInstance(context); bobj.setXClassReference(this.localReferenceEntityReferenceSerializer.serialize(getDocumentReference())); return bobj; } /** * @deprecated since 2.2.3 use {@link #fromMap(java.util.Map, com.xpn.xwiki.objects.BaseCollection)} */ @Deprecated public BaseCollection fromMap(Map<String, ?> map, XWikiContext context) throws XWikiException { BaseCollection object = newObject(context); return fromMap(map, object); } public BaseCollection fromMap(Map<String, ?> map, BaseCollection object) { for (PropertyClass property : (Collection<PropertyClass>) getFieldList()) { String name = property.getName(); Object formvalues = map.get(name); if (formvalues != null) { BaseProperty objprop; if (formvalues instanceof String[]) { objprop = property.fromStringArray(((String[]) formvalues)); } else { objprop = property.fromString(formvalues.toString()); } if (objprop != null) { objprop.setObject(object); object.safeput(name, objprop); } } } return object; } public BaseCollection fromValueMap(Map<String, ?> map, BaseCollection object) { for (PropertyClass property : (Collection<PropertyClass>) getFieldList()) { String name = property.getName(); Object formvalue = map.get(name); if (formvalue != null) { BaseProperty objprop; objprop = property.fromValue(formvalue); if (objprop != null) { objprop.setObject(object); object.safeput(name, objprop); } } } return object; } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#clone() */ @Override public BaseClass clone() { BaseClass bclass = (BaseClass) super.clone(); bclass.setCustomClass(getCustomClass()); bclass.setCustomMapping(getCustomMapping()); bclass.setDefaultWeb(getDefaultWeb()); bclass.setDefaultViewSheet(getDefaultViewSheet()); bclass.setDefaultEditSheet(getDefaultEditSheet()); bclass.setNameField(getNameField()); return bclass; } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { // Same Java object, they sure are equal if (this == obj) { return true; } if (!super.equals(obj)) { return false; } BaseClass bclass = (BaseClass) obj; if (!getCustomClass().equals(bclass.getCustomClass())) { return false; } if (!getCustomMapping().equals(bclass.getCustomMapping())) { return false; } if (!getDefaultViewSheet().equals(bclass.getDefaultViewSheet())) { return false; } if (!getDefaultEditSheet().equals(bclass.getDefaultEditSheet())) { return false; } if (!getDefaultWeb().equals(bclass.getDefaultWeb())) { return false; } if (!getValidationScript().equals(bclass.getValidationScript())) { return false; } if (!getNameField().equals(bclass.getNameField())) { return false; } return true; } public void merge(BaseClass bclass) { } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#toXML(com.xpn.xwiki.objects.classes.BaseClass) */ @Override public Element toXML(BaseClass bclass) { return toXML(); } public Element toXML() { Element cel = new DOMElement("class"); Element el = new DOMElement("name"); el.addText((getName() == null) ? "" : getName()); cel.add(el); el = new DOMElement("customClass"); el.addText((getCustomClass() == null) ? "" : getCustomClass()); cel.add(el); el = new DOMElement("customMapping"); el.addText((getCustomMapping() == null) ? "" : getCustomMapping()); cel.add(el); el = new DOMElement("defaultViewSheet"); el.addText((getDefaultViewSheet() == null) ? "" : getDefaultViewSheet()); cel.add(el); el = new DOMElement("defaultEditSheet"); el.addText((getDefaultEditSheet() == null) ? "" : getDefaultEditSheet()); cel.add(el); el = new DOMElement("defaultWeb"); el.addText((getDefaultWeb() == null) ? "" : getDefaultWeb()); cel.add(el); el = new DOMElement("nameField"); el.addText((getNameField() == null) ? "" : getNameField()); cel.add(el); el = new DOMElement("validationScript"); el.addText((getValidationScript() == null) ? "" : getValidationScript()); cel.add(el); // Iterate over values sorted by field name so that the values are // exported to XML in a consistent order. Iterator it = getSortedIterator(); while (it.hasNext()) { PropertyClass bprop = (PropertyClass) it.next(); cel.add(bprop.toXML()); } return cel; } public void fromXML(Element cel) throws XWikiException { try { int j = 1; setName(cel.element("name").getText()); Element cclel = cel.element("customClass"); if (cclel != null) { setCustomClass(cclel.getText()); j++; } Element cmapel = cel.element("customMapping"); if (cmapel != null) { setCustomMapping(cmapel.getText()); j++; } Element cdvsel = cel.element("defaultViewSheet"); if (cdvsel != null) { setDefaultViewSheet(cdvsel.getText()); j++; } Element cdesel = cel.element("defaultEditSheet"); if (cdesel != null) { setDefaultViewSheet(cdesel.getText()); j++; } Element cdwel = cel.element("defaultWeb"); if (cdwel != null) { setDefaultWeb(cdwel.getText()); j++; } Element cnfel = cel.element("nameField"); if (cnfel != null) { setNameField(cnfel.getText()); j++; } Element valel = cel.element("validationScript"); if (valel != null) { setValidationScript(valel.getText()); j++; } @SuppressWarnings("unchecked") List<Element> list = cel.elements(); for (int i = j; i < list.size(); i++) { Element pcel = list.get(i); String name = pcel.getName(); String classType = pcel.element("classType").getText(); PropertyClass property = (PropertyClass) Class.forName(classType).newInstance(); property.setName(name); property.setObject(this); property.fromXML(pcel); safeput(name, property); } } catch (Exception e) { throw new XWikiException(XWikiException.MODULE_XWIKI_CLASSES, XWikiException.ERROR_XWIKI_CLASSES_PROPERTY_CLASS_INSTANCIATION, "Error instanciating property class", e, null); } } public void fromXML(String xml) throws XWikiException { SAXReader reader = new SAXReader(); Document domdoc; if ((xml == null) || (xml.trim().equals(""))) { return; } xml = xml.replaceAll("<>", "<unknown>"); xml = xml.replaceAll("</>", "</unknown>"); try { StringReader in = new StringReader(xml); domdoc = reader.read(in); } catch (DocumentException e) { Object[] args = { xml }; throw new XWikiException(XWikiException.MODULE_XWIKI_DOC, XWikiException.ERROR_DOC_XML_PARSING, "Error parsing xml {0}", e, args); } Element docel = domdoc.getRootElement(); if (docel != null) { fromXML(docel); } } public boolean addTextField(String fieldName, String fieldPrettyName, int size) { if (get(fieldName) == null) { StringClass text_class = new StringClass(); text_class.setName(fieldName); text_class.setPrettyName(fieldPrettyName); text_class.setSize(size); text_class.setObject(this); put(fieldName, text_class); return true; } return false; } public boolean addPasswordField(String fieldName, String fieldPrettyName, int size) { if (get(fieldName) == null) { PasswordClass text_class = new PasswordClass(); text_class.setName(fieldName); text_class.setPrettyName(fieldPrettyName); text_class.setSize(size); text_class.setObject(this); put(fieldName, text_class); return true; } return false; } public boolean addBooleanField(String fieldName, String fieldPrettyName, String displayType) { if (get(fieldName) == null) { BooleanClass boolean_class = new BooleanClass(); boolean_class.setName(fieldName); boolean_class.setPrettyName(fieldPrettyName); boolean_class.setDisplayType(displayType); boolean_class.setObject(this); put(fieldName, boolean_class); return true; } return false; } public boolean addUsersField(String fieldName, String fieldPrettyName) { return addUsersField(fieldName, fieldPrettyName, true); } /** * @since XWiki Core 1.1.2, XWiki Core 1.2M2 */ public boolean addUsersField(String fieldName, String fieldPrettyName, boolean multiSelect) { return addUsersField(fieldName, fieldPrettyName, 5, multiSelect); } public boolean addUsersField(String fieldName, String fieldPrettyName, int size) { return addUsersField(fieldName, fieldPrettyName, size, true); } /** * @since XWiki Core 1.1.2, XWiki Core 1.2M2 */ public boolean addUsersField(String fieldName, String fieldPrettyName, int size, boolean multiSelect) { if (get(fieldName) == null) { UsersClass users_class = new UsersClass(); users_class.setName(fieldName); users_class.setPrettyName(fieldPrettyName); users_class.setSize(size); users_class.setMultiSelect(multiSelect); users_class.setObject(this); put(fieldName, users_class); return true; } return false; } public boolean addLevelsField(String fieldName, String fieldPrettyName) { return addLevelsField(fieldName, fieldPrettyName, 3); } public boolean addLevelsField(String fieldName, String fieldPrettyName, int size) { if (get(fieldName) == null) { LevelsClass levels_class = new LevelsClass(); levels_class.setName(fieldName); levels_class.setPrettyName(fieldPrettyName); levels_class.setSize(size); levels_class.setMultiSelect(true); levels_class.setObject(this); put(fieldName, levels_class); return true; } return false; } public boolean addGroupsField(String fieldName, String fieldPrettyName) { return addGroupsField(fieldName, fieldPrettyName, 5); } public boolean addGroupsField(String fieldName, String fieldPrettyName, int size) { if (get(fieldName) == null) { GroupsClass groups_class = new GroupsClass(); groups_class.setName(fieldName); groups_class.setPrettyName(fieldPrettyName); groups_class.setSize(size); groups_class.setMultiSelect(true); groups_class.setObject(this); put(fieldName, groups_class); return true; } return false; } public boolean addTemplateField(String fieldName, String fieldPrettyName) { return addTextAreaField(fieldName, fieldPrettyName, 80, 15); } public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows) { if (get(fieldName) == null) { TextAreaClass template_class = new TextAreaClass(); template_class.setName(fieldName); template_class.setPrettyName(fieldPrettyName); template_class.setSize(cols); template_class.setRows(rows); template_class.setObject(this); put(fieldName, template_class); return true; } return false; } public boolean addStaticListField(String fieldName, String fieldPrettyName, String values) { return addStaticListField(fieldName, fieldPrettyName, 1, false, values); } public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String values) { return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, values, null); } public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String values, String displayType) { return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, values, displayType, null); } /** * @since XWiki Core 1.1.2, XWiki Core 1.2M2 */ public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String values, String displayType, String separators) { return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, false, values, displayType, separators); } /** * @since 1.8M1 */ public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, boolean relationalStorage, String values, String displayType, String separators) { if (get(fieldName) == null) { StaticListClass list_class = new StaticListClass(); list_class.setName(fieldName); list_class.setPrettyName(fieldPrettyName); list_class.setSize(size); list_class.setMultiSelect(multiSelect); list_class.setRelationalStorage(relationalStorage); list_class.setValues(values); if (displayType != null) { list_class.setDisplayType(displayType); } if (separators != null) { list_class.setSeparators(separators); list_class.setSeparator(separators.substring(0, 1)); } list_class.setObject(this); put(fieldName, list_class); return true; } return false; } public boolean addNumberField(String fieldName, String fieldPrettyName, int size, String type) { if (get(fieldName) == null) { NumberClass number_class = new NumberClass(); number_class.setName(fieldName); number_class.setPrettyName(fieldPrettyName); number_class.setSize(size); number_class.setNumberType(type); number_class.setObject(this); put(fieldName, number_class); return true; } return false; } public boolean addDateField(String fieldName, String fieldPrettyName) { return addDateField(fieldName, fieldPrettyName, null, 1); } public boolean addDateField(String fieldName, String fieldPrettyName, String dformat) { return addDateField(fieldName, fieldPrettyName, dformat, 1); } public boolean addDateField(String fieldName, String fieldPrettyName, String dformat, int emptyIsToday) { if (get(fieldName) == null) { DateClass date_class = new DateClass(); date_class.setName(fieldName); date_class.setPrettyName(fieldPrettyName); if (dformat != null) { date_class.setDateFormat(dformat); } date_class.setObject(this); date_class.setEmptyIsToday(emptyIsToday); put(fieldName, date_class); return true; } return false; } public boolean addDBListField(String fieldName, String fieldPrettyName, String sql) { return addDBListField(fieldName, fieldPrettyName, 1, false, sql); } public boolean addDBListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String sql) { return addDBListField(fieldName, fieldPrettyName, size, multiSelect, multiSelect, sql); } /** * @since 1.8M1 */ public boolean addDBListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, boolean relationalStorage, String sql) { if (get(fieldName) == null) { DBListClass list_class = new DBListClass(); list_class.setName(fieldName); list_class.setPrettyName(fieldPrettyName); list_class.setSize(size); list_class.setMultiSelect(multiSelect); list_class.setRelationalStorage(relationalStorage); list_class.setSql(sql); list_class.setObject(this); put(fieldName, list_class); return true; } return false; } public boolean addDBTreeListField(String fieldName, String fieldPrettyName, String sql) { return addDBTreeListField(fieldName, fieldPrettyName, 1, false, sql); } public boolean addDBTreeListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String sql) { return addDBTreeListField(fieldName, fieldPrettyName, size, multiSelect, multiSelect, sql); } /** * @since 1.8M1 */ public boolean addDBTreeListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, boolean relationalStorage, String sql) { if (get(fieldName) == null) { DBTreeListClass list_class = new DBTreeListClass(); list_class.setName(fieldName); list_class.setPrettyName(fieldPrettyName); list_class.setSize(size); list_class.setMultiSelect(multiSelect); list_class.setRelationalStorage(relationalStorage); list_class.setSql(sql); list_class.setObject(this); put(fieldName, list_class); return true; } return false; } public void setCustomMapping(String customMapping) { this.customMapping = customMapping; } public String getCustomMapping() { if ("XWiki.XWikiPreferences".equals(getName())) { return "internal"; } if (this.customMapping == null) { return ""; } return this.customMapping; } public boolean hasCustomMapping() { String cMapping = getCustomMapping(); return (cMapping != null) && (!"".equals(cMapping)); } public boolean hasExternalCustomMapping() { String cMapping = getCustomMapping(); return (cMapping != null) && (!"".equals(cMapping)) && (!"internal".equals(cMapping)); } public boolean hasInternalCustomMapping() { return "internal".equals(this.customMapping); } public boolean isCustomMappingValid(XWikiContext context) throws XWikiException { return isCustomMappingValid(getCustomMapping(), context); } public boolean isCustomMappingValid(String custommapping, XWikiContext context) throws XWikiException { if ((custommapping != null) && (custommapping.trim().length() > 0)) { return context.getWiki().getStore().isCustomMappingValid(this, custommapping, context); } else { return true; } } public List<String> getCustomMappingPropertyList(XWikiContext context) { String custommapping1 = getCustomMapping(); if ((custommapping1 != null) && (custommapping1.trim().length() > 0)) { return context.getWiki().getStore().getCustomMappingPropertyList(this); } else { return new ArrayList<String>(); } } public void setCustomClass(String customClass) { this.customClass = customClass; } public String getCustomClass() { if (this.customClass == null) { return ""; } return this.customClass; } public BaseObject newCustomClassInstance(XWikiContext context) throws XWikiException { String customClass = getCustomClass(); try { if ((customClass == null) || (customClass.equals(""))) { return new BaseObject(); } else { return (BaseObject) Class.forName(getCustomClass()).newInstance(); } } catch (Exception e) { Object[] args = { customClass }; throw new XWikiException(XWikiException.MODULE_XWIKI_CLASSES, XWikiException.ERROR_XWIKI_CLASSES_CUSTOMCLASSINVOCATIONERROR, "Cannot instanciate custom class {0}", e, args); } } /** * @since 2.2.3 */ public static BaseObject newCustomClassInstance(DocumentReference classReference, XWikiContext context) throws XWikiException { BaseClass bclass = context.getWiki().getXClass(classReference, context); BaseObject object = (bclass == null) ? new BaseObject() : bclass.newCustomClassInstance(context); return object; } /** * @deprecated since 2.2.3 use {@link #newCustomClassInstance(DocumentReference classReference, * com.xpn.xwiki.XWikiContext)} */ @Deprecated public static BaseObject newCustomClassInstance(String className, XWikiContext context) throws XWikiException { BaseClass bclass = context.getWiki().getClass(className, context); BaseObject object = (bclass == null) ? new BaseObject() : bclass.newCustomClassInstance(context); return object; } public String getDefaultWeb() { if (this.defaultWeb == null) { return ""; } return this.defaultWeb; } public void setDefaultWeb(String defaultWeb) { this.defaultWeb = defaultWeb; } public String getDefaultViewSheet() { if (this.defaultViewSheet == null) { return ""; } return this.defaultViewSheet; } public void setDefaultViewSheet(String defaultViewSheet) { this.defaultViewSheet = defaultViewSheet; } public String getDefaultEditSheet() { if (this.defaultEditSheet == null) { return ""; } return this.defaultEditSheet; } public void setDefaultEditSheet(String defaultEditSheet) { this.defaultEditSheet = defaultEditSheet; } public String getNameField() { if (this.nameField == null) { return ""; } return this.nameField; } public void setNameField(String nameField) { this.nameField = nameField; } public String makeQuery(XWikiCriteria query) { List<String> criteriaList = new ArrayList<String>(); for (PropertyClass property : (Collection<PropertyClass>) getFieldList()) { String name = property.getName(); Map<String, Object> map = query.getParameters(getName() + "_" + name); if (map.size() > 0) { property.makeQuery(map, "", query, criteriaList); } } return StringUtils.join(criteriaList.toArray(), " and "); } public String displaySearchColumns(String prefix, XWikiQuery query, XWikiContext context) { select select = new select(prefix + "searchcolumns", 5); select.setMultiple(true); select.setName(prefix + "searchcolumns"); select.setID(prefix + "searchcolumns"); List<String> list = Arrays.asList(getPropertyNames()); Map<String, String> prettynamesmap = new HashMap<String, String>(); for (int i = 0; i < list.size(); i++) { String propname = list.get(i); list.set(i, prefix + propname); prettynamesmap.put(prefix + propname, ((PropertyClass) get(propname)).getPrettyName()); } List<String> selectlist = query.getDisplayProperties(); // Add options from Set for (Iterator<String> it = list.iterator(); it.hasNext();) { String value = it.next().toString(); String displayValue = prettynamesmap.get(value); option option = new option(displayValue, displayValue); option.addElement(displayValue); option.setValue(value); if (selectlist.contains(value)) { option.setSelected(true); } select.addElement(option); } return select.toString(); } public String displaySearchOrder(String prefix, XWikiQuery query, XWikiContext context) { select select = new select(prefix + "searchorder", 5); select.setMultiple(true); select.setName(prefix + "searchorder"); select.setID(prefix + "searchorder"); List<String> list = Arrays.asList(getPropertyNames()); Map<String, String> prettynamesmap = new HashMap<String, String>(); for (int i = 0; i < list.size(); i++) { String propname = list.get(i); list.set(i, prefix + propname); prettynamesmap.put(prefix + propname, ((PropertyClass) get(propname)).getPrettyName()); } OrderClause order = null; if ((query != null) && (query.getOrderProperties() != null) && (query.getOrderProperties().size() > 0)) { order = query.getOrderProperties().get(0); } // Add options from Set for (Iterator<String> it = list.iterator(); it.hasNext();) { String value = it.next().toString(); String displayValue = prettynamesmap.get(value); option option = new option(displayValue, displayValue); option.addElement(displayValue); option.setValue(value); if ((order != null) && (value.equals(order.getProperty()))) { option.setSelected(true); } select.addElement(option); } return select.toString(); } public void setValidationScript(String validationScript) { this.validationScript = validationScript; } public String getValidationScript() { if (this.validationScript == null) { return ""; } else { return this.validationScript; } } public boolean validateObject(BaseObject obj, XWikiContext context) throws XWikiException { boolean isValid = true; Object[] props = getPropertyNames(); for (int i = 0; i < props.length; i++) { String propname = (String) props[i]; BaseProperty property = (BaseProperty) obj.get(propname); PropertyClass propclass = (PropertyClass) get(propname); isValid &= propclass.validateProperty(property, context); } String validSript = getValidationScript(); if ((validSript != null) && (!validSript.trim().equals(""))) { isValid &= executeValidationScript(obj, validSript, context); } return isValid; } private boolean executeValidationScript(BaseObject obj, String validationScript, XWikiContext context) throws XWikiException { try { XWikiValidationInterface validObject = (XWikiValidationInterface) context.getWiki() .parseGroovyFromPage(validationScript, context); return validObject.validateObject(obj, context); } catch (Throwable e) { XWikiValidationStatus.addExceptionToContext(getName(), "", e, context); return false; } } public void flushCache() { Object[] props = getPropertyNames(); for (int i = 0; i < props.length; i++) { String propname = (String) props[i]; PropertyClass propclass = (PropertyClass) get(propname); if (propclass != null) { propclass.flushCache(); } } } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#getDiff(java.lang.Object, com.xpn.xwiki.XWikiContext) */ @Override public List<ObjectDiff> getDiff(Object oldObject, XWikiContext context) { ArrayList<ObjectDiff> difflist = new ArrayList<ObjectDiff>(); BaseClass oldClass = (BaseClass) oldObject; for (PropertyClass newProperty : (Collection<PropertyClass>) getFieldList()) { String propertyName = newProperty.getName(); PropertyClass oldProperty = (PropertyClass) oldClass.get(propertyName); String propertyType = StringUtils.substringAfterLast(newProperty.getClassType(), "."); if (oldProperty == null) { difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYADDED, propertyName, propertyType, "", "")); } else if (!oldProperty.equals(newProperty)) { difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYCHANGED, propertyName, propertyType, "", "")); } } for (PropertyClass oldProperty : (Collection<PropertyClass>) oldClass.getFieldList()) { String propertyName = oldProperty.getName(); PropertyClass newProperty = (PropertyClass) get(propertyName); String propertyType = StringUtils.substringAfterLast(oldProperty.getClassType(), "."); if (newProperty == null) { difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYREMOVED, propertyName, propertyType, "", "")); } } return difflist; } /** * {@inheritDoc} * * @see com.xpn.xwiki.objects.BaseCollection#merge(com.xpn.xwiki.objects.ElementInterface, * com.xpn.xwiki.objects.ElementInterface, com.xpn.xwiki.doc.merge.MergeConfiguration, * com.xpn.xwiki.XWikiContext, com.xpn.xwiki.doc.merge.MergeResult) */ public void merge(ElementInterface previousElement, ElementInterface newElement, MergeConfiguration configuration, XWikiContext context, MergeResult mergeResult) { BaseClass previousClass = (BaseClass) previousElement; BaseClass newClass = (BaseClass) newElement; List<ObjectDiff> classDiff = previousClass.getDiff(newClass, context); for (ObjectDiff diff : classDiff) { PropertyClass propertyResult = (PropertyClass) getField(diff.getPropName()); PropertyClass previousProperty = (PropertyClass) previousClass.getField(diff.getPropName()); PropertyClass newProperty = (PropertyClass) newClass.getField(diff.getPropName()); if (diff.getAction() == ObjectDiff.ACTION_PROPERTYADDED) { if (propertyResult == null) { // Add if none has been added by user already addField(diff.getPropName(), configuration.isProvidedVersionsModifiables() ? newClass.getField(diff.getPropName()) : newClass.getField(diff.getPropName()).clone()); mergeResult.setModified(true); } else if (!propertyResult.equals(newProperty)) { // XXX: collision between DB and new: property to add but already exists in the DB mergeResult.getErrors().add(new CollisionException( "Collision found on class property [" + newProperty.getReference() + "]")); } } else if (diff.getAction() == ObjectDiff.ACTION_PROPERTYREMOVED) { if (propertyResult != null) { if (propertyResult.equals(previousProperty)) { // Delete if it's the same as previous one removeField(diff.getPropName()); mergeResult.setModified(true); } else { // XXX: collision between DB and new: property to remove but not the same as previous // version mergeResult.getErrors().add(new CollisionException( "Collision found on class property [" + previousProperty.getReference() + "]")); } } else { // Already removed from DB, lets assume the user is prescient mergeResult.getWarnings().add(new CollisionException( "Object property [" + previousProperty.getReference() + "] already removed")); } } else if (diff.getAction() == ObjectDiff.ACTION_PROPERTYCHANGED) { if (propertyResult != null) { if (propertyResult.equals(previousProperty)) { // Let some automatic migration take care of that modification between DB and new addField(diff.getPropName(), newClass.getField(diff.getPropName())); mergeResult.setModified(true); } else if (!propertyResult.equals(newProperty)) { propertyResult.merge(previousProperty, newProperty, configuration, context, mergeResult); } } else { // XXX: collision between DB and new: property to modify but does not exists in DB // Lets assume it's a mistake to fix mergeResult.getWarnings().add(new CollisionException( "Collision found on class property [" + newProperty.getReference() + "]")); addField(diff.getPropName(), newClass.getField(diff.getPropName())); mergeResult.setModified(true); } } } } }