Java tutorial
/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (C) Alkacon Software (http://www.alkacon.com) * * This library 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 library 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. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.acacia.shared; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.common.collect.Lists; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.SimpleEventBus; /** * Serializable entity implementation.<p> */ public class CmsEntity implements HasValueChangeHandlers<CmsEntity>, Serializable { /** * Handles child entity changes.<p> */ protected class EntityChangeHandler implements ValueChangeHandler<CmsEntity> { /** * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent) */ public void onValueChange(ValueChangeEvent<CmsEntity> event) { fireChange(); } } /** The serial version id. */ private static final long serialVersionUID = -6933931178070025267L; /** The entity attribute values. */ private Map<String, List<CmsEntity>> m_entityAttributes; /** The entity id. */ private String m_id; /** The simple attribute values. */ private Map<String, List<String>> m_simpleAttributes; /** The type name. */ private String m_typeName; /** The event bus. */ private transient SimpleEventBus m_eventBus; /** The child entites change handler. */ private transient EntityChangeHandler m_childChangeHandler = new EntityChangeHandler(); /** The handler registrations. */ private transient Map<String, HandlerRegistration> m_changeHandlerRegistry; /** * Constructor.<p> * * @param id the entity id/URI * @param typeName the entity type name */ public CmsEntity(String id, String typeName) { this(); m_id = id; m_typeName = typeName; } /** * Constructor. For serialization only.<p> */ protected CmsEntity() { m_simpleAttributes = new HashMap<String, List<String>>(); m_entityAttributes = new HashMap<String, List<CmsEntity>>(); m_changeHandlerRegistry = new HashMap<String, HandlerRegistration>(); } /** * Returns the value of a simple attribute for the given path or <code>null</code>, if the value does not exist.<p> * * @param entity the entity to get the value from * @param pathElements the path elements * * @return the value */ public static String getValueForPath(CmsEntity entity, String[] pathElements) { String result = null; if ((pathElements != null) && (pathElements.length >= 1)) { String attributeName = pathElements[0]; int index = CmsContentDefinition.extractIndex(attributeName); if (index > 0) { index--; } attributeName = entity.getTypeName() + "/" + CmsContentDefinition.removeIndex(attributeName); CmsEntityAttribute attribute = entity.getAttribute(attributeName); if (!((attribute == null) || (attribute.isComplexValue() && (pathElements.length == 1)))) { if (attribute.isSimpleValue()) { if ((pathElements.length == 1) && (attribute.getValueCount() > 0)) { List<String> values = attribute.getSimpleValues(); result = values.get(index); } } else if (attribute.getValueCount() > (index)) { String[] childPathElements = new String[pathElements.length - 1]; for (int i = 1; i < pathElements.length; i++) { childPathElements[i - 1] = pathElements[i]; } List<CmsEntity> values = attribute.getComplexValues(); result = getValueForPath(values.get(index), childPathElements); } } } return result; } /** * Gets the list of values reachable from the given base object with the given path.<p> * * @param baseObject the base object (a CmsEntity or a string) * @param pathComponents the path components * @return the list of values for the given path (either of type String or CmsEntity) */ public static List<Object> getValuesForPath(Object baseObject, String[] pathComponents) { List<Object> currentList = Lists.newArrayList(); currentList.add(baseObject); for (String pathComponent : pathComponents) { List<Object> newList = Lists.newArrayList(); for (Object element : currentList) { newList.addAll(getValuesForPathComponent(element, pathComponent)); } currentList = newList; } return currentList; } /** * Gets the values reachable from a given object (an entity or a string) with a single XPath component.<p> * * If entityOrString is a string, and pathComponent is "VALUE", a list containing only entityOrString is returned. * Otherwise, entityOrString is assumed to be an entity, and the pathComponent is interpreted as a field of the entity * (possibly with an index). * * @param entityOrString the entity or string from which to get the values for the given path component * @param pathComponent the path component * @return the list of reachable values */ public static List<Object> getValuesForPathComponent(Object entityOrString, String pathComponent) { List<Object> result = Lists.newArrayList(); if (pathComponent.equals("VALUE")) { result.add(entityOrString); } else { if (entityOrString instanceof CmsEntity) { CmsEntity entity = (CmsEntity) entityOrString; boolean hasIndex = CmsContentDefinition.hasIndex(pathComponent); int index = CmsContentDefinition.extractIndex(pathComponent); if (index > 0) { index--; } String attributeName = entity.getTypeName() + "/" + CmsContentDefinition.removeIndex(pathComponent); CmsEntityAttribute attribute = entity.getAttribute(attributeName); if (attribute != null) { if (hasIndex) { if (index < attribute.getValueCount()) { if (attribute.isSimpleValue()) { result.add(attribute.getSimpleValues().get(index)); } else { result.add(attribute.getComplexValues().get(index)); } } } else { if (attribute.isSimpleValue()) { result.addAll(attribute.getSimpleValues()); } else { result.addAll(attribute.getComplexValues()); } } } } } return result; } /** * Adds the given attribute value.<p> * * @param attributeName the attribute name * @param value the attribute value */ public void addAttributeValue(String attributeName, CmsEntity value) { if (m_simpleAttributes.containsKey(attributeName)) { throw new RuntimeException("Attribute already exists with a simple type value."); } if (m_entityAttributes.containsKey(attributeName)) { m_entityAttributes.get(attributeName).add(value); } else { List<CmsEntity> values = new ArrayList<CmsEntity>(); values.add(value); m_entityAttributes.put(attributeName, values); } registerChangeHandler(value); fireChange(); } /** * Adds the given attribute value.<p> * * @param attributeName the attribute name * @param value the attribute value */ public void addAttributeValue(String attributeName, String value) { if (m_entityAttributes.containsKey(attributeName)) { throw new RuntimeException("Attribute already exists with a entity type value."); } if (m_simpleAttributes.containsKey(attributeName)) { m_simpleAttributes.get(attributeName).add(value); } else { List<String> values = new ArrayList<String>(); values.add(value); m_simpleAttributes.put(attributeName, values); } fireChange(); } /** * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) */ public HandlerRegistration addValueChangeHandler(ValueChangeHandler<CmsEntity> handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * Clones the given entity keeping all entity ids.<p> * * @return returns the cloned instance */ public CmsEntity cloneEntity() { CmsEntity clone = new CmsEntity(getId(), getTypeName()); for (CmsEntityAttribute attribute : getAttributes()) { if (attribute.isSimpleValue()) { List<String> values = attribute.getSimpleValues(); for (String value : values) { clone.addAttributeValue(attribute.getAttributeName(), value); } } else { List<CmsEntity> values = attribute.getComplexValues(); for (CmsEntity value : values) { clone.addAttributeValue(attribute.getAttributeName(), value.cloneEntity()); } } } return clone; } /** * Creates a deep copy of this entity.<p> * * @param entityId the id of the new entity, if <code>null</code> a generic id will be used * * @return the entity copy */ public CmsEntity createDeepCopy(String entityId) { CmsEntity result = new CmsEntity(entityId, getTypeName()); for (CmsEntityAttribute attribute : getAttributes()) { if (attribute.isSimpleValue()) { List<String> values = attribute.getSimpleValues(); for (String value : values) { result.addAttributeValue(attribute.getAttributeName(), value); } } else { List<CmsEntity> values = attribute.getComplexValues(); for (CmsEntity value : values) { result.addAttributeValue(attribute.getAttributeName(), value.createDeepCopy(null)); } } } return result; } /** * Ensures that the change event is also fired on child entity change.<p> */ public void ensureChangeHandlers() { if (!m_changeHandlerRegistry.isEmpty()) { for (HandlerRegistration reg : m_changeHandlerRegistry.values()) { reg.removeHandler(); } m_changeHandlerRegistry.clear(); } for (List<CmsEntity> attr : m_entityAttributes.values()) { for (CmsEntity child : attr) { registerChangeHandler(child); child.ensureChangeHandlers(); } } } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { boolean result = false; if (obj instanceof CmsEntity) { CmsEntity test = (CmsEntity) obj; if (m_simpleAttributes.keySet().equals(test.m_simpleAttributes.keySet()) && m_entityAttributes.keySet().equals(test.m_entityAttributes.keySet())) { result = true; for (String attributeName : m_simpleAttributes.keySet()) { if (!m_simpleAttributes.get(attributeName).equals(test.m_simpleAttributes.get(attributeName))) { result = false; break; } } if (result) { for (String attributeName : m_entityAttributes.keySet()) { if (!m_entityAttributes.get(attributeName) .equals(test.m_entityAttributes.get(attributeName))) { result = false; break; } } } } } return result; } /** * @see com.google.gwt.event.shared.HasHandlers#fireEvent(com.google.gwt.event.shared.GwtEvent) */ public void fireEvent(GwtEvent<?> event) { ensureHandlers().fireEventFromSource(event, this); } /** * Returns an attribute.<p> * * @param attributeName the attribute name * * @return the attribute value */ public CmsEntityAttribute getAttribute(String attributeName) { if (m_simpleAttributes.containsKey(attributeName)) { return CmsEntityAttribute.createSimpleAttribute(attributeName, m_simpleAttributes.get(attributeName)); } if (m_entityAttributes.containsKey(attributeName)) { return CmsEntityAttribute.createEntityAttribute(attributeName, m_entityAttributes.get(attributeName)); } return null; } /** * Returns all entity attributes.<p> * * @return the entity attributes */ public List<CmsEntityAttribute> getAttributes() { List<CmsEntityAttribute> result = new ArrayList<CmsEntityAttribute>(); for (String name : m_simpleAttributes.keySet()) { result.add(getAttribute(name)); } for (String name : m_entityAttributes.keySet()) { result.add(getAttribute(name)); } return result; } /** * Returns this or a child entity with the given id.<p> * Will return <code>null</code> if no entity with the given id is present.<p> * * @param entityId the entity id * * @return the entity */ public CmsEntity getEntityById(String entityId) { CmsEntity result = null; if (m_id.equals(entityId)) { result = this; } else { for (List<CmsEntity> children : m_entityAttributes.values()) { for (CmsEntity child : children) { result = child.getEntityById(entityId); if (result != null) { break; } } if (result != null) { break; } } } return result; } /** * Returns the entity id.<p> * * @return the id */ public String getId() { return m_id; } /** * Returns the entity type name.<p> * * @return the entity type name */ public String getTypeName() { return m_typeName; } /** * Returns if the entity has the given attribute.<p> * * @param attributeName the attribute name * * @return <code>true</code> if the entity has the given attribute */ public boolean hasAttribute(String attributeName) { return m_simpleAttributes.containsKey(attributeName) || m_entityAttributes.containsKey(attributeName); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Inserts a new attribute value at the given index.<p> * * @param attributeName the attribute name * @param value the attribute value * @param index the value index */ public void insertAttributeValue(String attributeName, CmsEntity value, int index) { if (m_entityAttributes.containsKey(attributeName)) { m_entityAttributes.get(attributeName).add(index, value); } else { setAttributeValue(attributeName, value); } registerChangeHandler(value); fireChange(); } /** * Inserts a new attribute value at the given index.<p> * * @param attributeName the attribute name * @param value the attribute value * @param index the value index */ public void insertAttributeValue(String attributeName, String value, int index) { if (m_simpleAttributes.containsKey(attributeName)) { m_simpleAttributes.get(attributeName).add(index, value); } else { setAttributeValue(attributeName, value); } fireChange(); } /** * Removes the given attribute.<p> * * @param attributeName the attribute name */ public void removeAttribute(String attributeName) { removeAttributeSilent(attributeName); fireChange(); } /** * Removes the attribute without triggering any change events.<p> * * @param attributeName the attribute name */ public void removeAttributeSilent(String attributeName) { CmsEntityAttribute attr = getAttribute(attributeName); if (attr != null) { if (attr.isSimpleValue()) { m_simpleAttributes.remove(attributeName); } else { for (CmsEntity child : attr.getComplexValues()) { removeChildChangeHandler(child); } m_entityAttributes.remove(attributeName); } } } /** * Removes a specific attribute value.<p> * * @param attributeName the attribute name * @param index the value index */ public void removeAttributeValue(String attributeName, int index) { if (m_simpleAttributes.containsKey(attributeName)) { List<String> values = m_simpleAttributes.get(attributeName); if ((values.size() == 1) && (index == 0)) { removeAttributeSilent(attributeName); } else { values.remove(index); } } else if (m_entityAttributes.containsKey(attributeName)) { List<CmsEntity> values = m_entityAttributes.get(attributeName); if ((values.size() == 1) && (index == 0)) { removeAttributeSilent(attributeName); } else { CmsEntity child = values.remove(index); removeChildChangeHandler(child); } } fireChange(); } /** * Sets the given attribute value. Will remove all previous attribute values.<p> * * @param attributeName the attribute name * @param value the attribute value */ public void setAttributeValue(String attributeName, CmsEntity value) { // make sure there is no attribute value set removeAttributeSilent(attributeName); addAttributeValue(attributeName, value); } /** * Sets the given attribute value at the given index.<p> * * @param attributeName the attribute name * @param value the attribute value * @param index the value index */ public void setAttributeValue(String attributeName, CmsEntity value, int index) { if (m_simpleAttributes.containsKey(attributeName)) { throw new RuntimeException("Attribute already exists with a simple type value."); } if (!m_entityAttributes.containsKey(attributeName)) { if (index != 0) { throw new IndexOutOfBoundsException(); } else { addAttributeValue(attributeName, value); } } else { if (m_entityAttributes.get(attributeName).size() > index) { CmsEntity child = m_entityAttributes.get(attributeName).remove(index); removeChildChangeHandler(child); } m_entityAttributes.get(attributeName).add(index, value); fireChange(); } } /** * Sets the given attribute value. Will remove all previous attribute values.<p> * * @param attributeName the attribute name * @param value the attribute value */ public void setAttributeValue(String attributeName, String value) { m_entityAttributes.remove(attributeName); List<String> values = new ArrayList<String>(); values.add(value); m_simpleAttributes.put(attributeName, values); fireChange(); } /** * Sets the given attribute value at the given index.<p> * * @param attributeName the attribute name * @param value the attribute value * @param index the value index */ public void setAttributeValue(String attributeName, String value, int index) { if (m_entityAttributes.containsKey(attributeName)) { throw new RuntimeException("Attribute already exists with a simple type value."); } if (!m_simpleAttributes.containsKey(attributeName)) { if (index != 0) { throw new IndexOutOfBoundsException(); } else { addAttributeValue(attributeName, value); } } else { if (m_simpleAttributes.get(attributeName).size() > index) { m_simpleAttributes.get(attributeName).remove(index); } m_simpleAttributes.get(attributeName).add(index, value); fireChange(); } } /** * Returns the JSON string representation of this entity.<p> * * @return the JSON string representation of this entity */ public String toJSON() { StringBuffer result = new StringBuffer(); result.append("{\n"); for (Entry<String, List<String>> simpleEntry : m_simpleAttributes.entrySet()) { result.append("\"").append(simpleEntry.getKey()).append("\"").append(": [\n"); boolean firstValue = true; for (String value : simpleEntry.getValue()) { if (firstValue) { firstValue = false; } else { result.append(",\n"); } result.append("\"").append(value).append("\""); } result.append("],\n"); } for (Entry<String, List<CmsEntity>> entityEntry : m_entityAttributes.entrySet()) { result.append("\"").append(entityEntry.getKey()).append("\"").append(": [\n"); boolean firstValue = true; for (CmsEntity value : entityEntry.getValue()) { if (firstValue) { firstValue = false; } else { result.append(",\n"); } result.append(value.toJSON()); } result.append("],\n"); } result.append("\"id\": \"").append(m_id).append("\""); result.append("}"); return result.toString(); } /** * @see java.lang.Object#toString() */ @Override public String toString() { return toJSON(); } /** * Adds this handler to the widget. * * @param <H> the type of handler to add * @param type the event type * @param handler the handler * @return {@link HandlerRegistration} used to remove the handler */ protected final <H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type) { return ensureHandlers().addHandlerToSource(type, this, handler); } /** * Fires the change event for this entity.<p> */ void fireChange() { ValueChangeEvent.fire(this, this); } /** * Lazy initializing the handler manager.<p> * * @return the handler manager */ private SimpleEventBus ensureHandlers() { if (m_eventBus == null) { m_eventBus = new SimpleEventBus(); } return m_eventBus; } /** * Adds the value change handler to the given entity.<p> * * @param child the child entity */ private void registerChangeHandler(CmsEntity child) { HandlerRegistration reg = child.addValueChangeHandler(m_childChangeHandler); m_changeHandlerRegistry.put(child.getId(), reg); } /** * Removes the child entity change handler.<p> * * @param child the child entity */ private void removeChildChangeHandler(CmsEntity child) { HandlerRegistration reg = m_changeHandlerRegistry.remove(child.getId()); if (reg != null) { reg.removeHandler(); } } }