Java tutorial
/* * #%L * Alfresco Repository * %% * Copyright (C) 2005 - 2016 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of * the paid license agreement will prevail. Otherwise, the software is * provided under the following open source license terms: * * Alfresco 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 3 of the License, or * (at your option) any later version. * * Alfresco 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 Alfresco. If not, see <http://www.gnu.org/licenses/>. * #L% */ package org.alfresco.repo.domain.node; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.util.List; import java.util.zip.CRC32; import org.alfresco.repo.domain.qname.QNameDAO; import org.alfresco.service.cmr.dictionary.AssociationDefinition; import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.QName; import org.alfresco.util.GUID; import org.alfresco.util.Pair; import org.alfresco.util.ParameterCheck; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Bean for <b>alf_child_assoc</b> table. * * @author Derek Hulley * @since 3.4 */ public class ChildAssocEntity implements Serializable { private static final long serialVersionUID = 1L; private static final Log logger = LogFactory.getLog(ChildAssocEntity.class); private Long id; private Long version; private NodeEntity parentNode; private NodeEntity childNode; private Long typeQNameId; private Long childNodeNameCrc; private String childNodeName; private Long qnameNamespaceId; private String qnameLocalName; private Long qnameCrc; private Boolean isPrimary; private int assocIndex; // Supplemental query-related parameters private List<Long> typeQNameIds; private List<Long> childNodeNameCrcs; private List<Long> childNodeTypeQNameIds; private Boolean sameStore; private boolean ordered; /** * Find a CRC value for the full QName using UTF-8 conversion. * * @param qname the association qname * @return Returns the CRC value (UTF-8 compatible) */ public static Long getQNameCrc(QName qname) { CRC32 crc = new CRC32(); try { crc.update(qname.getNamespaceURI().getBytes("UTF-8")); crc.update(qname.getLocalName().getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 encoding is not supported"); } return crc.getValue(); } /** * Find a CRC value for the association's child node name using UTF-8 conversion. * * @param childNodeName the child node name * @return Returns the CRC value (UTF-8 compatible) */ public static Long getChildNodeNameCrc(String childNodeName) { CRC32 crc = new CRC32(); try { // https://issues.alfresco.com/jira/browse/ALFCOM-1335 crc.update(childNodeName.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException("UTF-8 encoding is not supported"); } return crc.getValue(); } private static final String TRUNCATED_NAME_INDICATOR = "~~~"; /** * Truncates the association's child node name to 50 characters. * * @param childNodeName the child node name * @return Returns the potentially truncated value */ public static String getChildNodeNameShort(String childNodeName) { int length = childNodeName.length(); if (length <= 50) { return childNodeName; } else { StringBuilder ret = new StringBuilder(50); ret.append(childNodeName.substring(0, 47)).append(TRUNCATED_NAME_INDICATOR); return ret.toString(); } } /** * Apply the <b>cm:name</b> to the child association. If the child name is <tt>null</tt> then a GUID is generated as * a substitute. * <p> * Unknown associations or associations that do not require unique name checking will use a GUID for the child * name and the CRC value used <b>will be negative</b>. * * @param childName the <b>cm:name</b> applying to the association. */ public static Pair<String, Long> getChildNameUnique(DictionaryService dictionaryService, QName assocTypeQName, String childName) { if (childName == null) { throw new IllegalArgumentException("Child name may not be null. Use the Node ID ..."); } String childNameNewShort; // long childNameNewCrc = -1L; // By default, they don't compete AssociationDefinition assocDef = dictionaryService.getAssociation(assocTypeQName); if (assocDef == null || !assocDef.isChild()) { if (logger.isWarnEnabled()) { logger.warn("No child association of this type could be found: " + assocTypeQName); } childNameNewShort = GUID.generate(); childNameNewCrc = -1L * getChildNodeNameCrc(childNameNewShort); } else { ChildAssociationDefinition childAssocDef = (ChildAssociationDefinition) assocDef; if (childAssocDef.getDuplicateChildNamesAllowed()) { childNameNewShort = GUID.generate(); childNameNewCrc = -1L * getChildNodeNameCrc(childNameNewShort); } else { String childNameNewLower = childName.toLowerCase(); childNameNewShort = getChildNodeNameShort(childNameNewLower); childNameNewCrc = getChildNodeNameCrc(childNameNewLower); } } return new Pair<String, Long>(childNameNewShort, childNameNewCrc); } /** * Required default constructor */ public ChildAssocEntity() { ordered = false; } @Override public String toString() { StringBuilder sb = new StringBuilder(512); sb.append("ChildAssocEntity").append("[ ID=").append(id).append(", typeQNameId=").append(typeQNameId) .append(", childNodeNameCrc=").append(childNodeNameCrc).append(", childNodeName=") .append(childNodeName).append(", qnameNamespaceId=").append(qnameNamespaceId) .append(", qnameLocalName=").append(qnameLocalName).append(", qnameCrc=").append(qnameCrc) .append(", parentNode=").append(parentNode).append(", childNode=").append(childNode).append("]"); return sb.toString(); } public ChildAssociationRef getRef(QNameDAO qnameDAO) { QName typeQName = qnameDAO.getQName(typeQNameId).getSecond(); QName qname = QName.createQName(qnameDAO.getNamespace(qnameNamespaceId).getSecond(), qnameLocalName); return new ChildAssociationRef(typeQName, parentNode.getNodeRef(), qname, childNode.getNodeRef(), isPrimary, assocIndex); } public Pair<Long, ChildAssociationRef> getPair(QNameDAO qnameDAO) { return new Pair<Long, ChildAssociationRef>(id, getRef(qnameDAO)); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } public NodeEntity getParentNode() { return parentNode; } public void setParentNode(NodeEntity parentNode) { this.parentNode = parentNode; } public NodeEntity getChildNode() { return childNode; } public void setChildNode(NodeEntity childNode) { this.childNode = childNode; } /** * Helper method to set the {@link #setTypeQNameId(Long)}. * * @param qnameDAO the DAO to resolve the QName ID * @param typeQName the association type * @param forUpdate <tt>true</tt> if the QName must exist i.e. this * entity will be used for updates and the type * <code>QName</code> <b>must</b> exist. * @return <tt>true</tt> if the set worked otherwise <tt>false</tt> */ public boolean setTypeQNameAll(QNameDAO qnameDAO, QName typeQName, boolean forUpdate) { if (forUpdate) { typeQNameId = qnameDAO.getOrCreateQName(typeQName).getFirst(); return true; } else { Pair<Long, QName> qnamePair = qnameDAO.getQName(typeQName); if (qnamePair == null) { return false; } else { typeQNameId = qnamePair.getFirst(); return true; } } } public Long getTypeQNameId() { return typeQNameId; } /** * @deprecated For persistence use only */ public void setTypeQNameId(Long typeQNameId) { this.typeQNameId = typeQNameId; } /** * Helper method to set all values associated with the * {@link #setChildNodeName(String) child node name}. * * @param dictionaryService the service that determines how the CRC values are generated. * If this is <tt>null</tt> then the CRC values are generated * assuming that positive enforcement of the name constraint is * required. * @param childNodeName the child node name */ public void setChildNodeNameAll(DictionaryService dictionaryService, QName typeQName, String childNodeName) { ParameterCheck.mandatory("childNodeName", childNodeName); if (dictionaryService != null) { ParameterCheck.mandatory("typeQName", typeQName); Pair<String, Long> childNameUnique = ChildAssocEntity.getChildNameUnique(dictionaryService, typeQName, childNodeName); this.childNodeName = childNameUnique.getFirst(); this.childNodeNameCrc = childNameUnique.getSecond(); } else { String childNameNewLower = childNodeName.toLowerCase(); this.childNodeName = ChildAssocEntity.getChildNodeNameShort(childNameNewLower); this.childNodeNameCrc = ChildAssocEntity.getChildNodeNameCrc(childNameNewLower); } } public Long getChildNodeNameCrc() { return childNodeNameCrc; } /** * @deprecated For persistence use */ public void setChildNodeNameCrc(Long childNodeNameCrc) { this.childNodeNameCrc = childNodeNameCrc; } public String getChildNodeName() { return childNodeName; } /** * @deprecated For persistence use */ public void setChildNodeName(String childNodeName) { this.childNodeName = childNodeName; } /** * Set all required fields associated with the patch <code>QName</code>. * * @param forUpdate <tt>true</tt> if the entity is going to be used for a * data update i.e. the <code>QName</code> <b>must</b> exist. * @return Returns <tt>true</tt> if the <code>QName</code> namespace * exists. */ public boolean setQNameAll(QNameDAO qnameDAO, QName qname, boolean forUpdate) { String assocQNameNamespace = qname.getNamespaceURI(); String assocQNameLocalName = qname.getLocalName(); Long assocQNameNamespaceId = null; if (forUpdate) { assocQNameNamespaceId = qnameDAO.getOrCreateNamespace(assocQNameNamespace).getFirst(); } else { Pair<Long, String> nsPair = qnameDAO.getNamespace(assocQNameNamespace); if (nsPair == null) { // We can't set anything return false; } else { assocQNameNamespaceId = nsPair.getFirst(); } } Long assocQNameCrc = getQNameCrc(qname); this.qnameNamespaceId = assocQNameNamespaceId; this.qnameLocalName = assocQNameLocalName; this.qnameCrc = assocQNameCrc; // All set correctly return true; } public Long getQnameNamespaceId() { return qnameNamespaceId; } /** * @deprecated For persistence use */ public void setQnameNamespaceId(Long qnameNamespaceId) { this.qnameNamespaceId = qnameNamespaceId; } public String getQnameLocalName() { return qnameLocalName; } /** * @deprecated For persistence use */ public void setQnameLocalName(String qnameLocalName) { this.qnameLocalName = qnameLocalName; } public Long getQnameCrc() { return qnameCrc; } /** * @deprecated For persistence use */ public void setQnameCrc(Long qnameCrc) { this.qnameCrc = qnameCrc; } public Boolean isPrimary() { return isPrimary; } public void setPrimary(Boolean isPrimary) { this.isPrimary = isPrimary; } public int getAssocIndex() { return assocIndex; } public void setAssocIndex(int assocIndex) { this.assocIndex = assocIndex; } public List<Long> getTypeQNameIds() { return typeQNameIds; } public void setTypeQNameIds(List<Long> typeQNameIds) { this.typeQNameIds = typeQNameIds; } public List<Long> getChildNodeNameCrcs() { return childNodeNameCrcs; } public void setChildNodeNameCrcs(List<Long> childNodeNameCrcs) { this.childNodeNameCrcs = childNodeNameCrcs; } public List<Long> getChildNodeTypeQNameIds() { return childNodeTypeQNameIds; } public void setChildNodeTypeQNameIds(List<Long> childNodeTypeQNameIds) { this.childNodeTypeQNameIds = childNodeTypeQNameIds; } public Boolean getSameStore() { return sameStore; } public void setSameStore(Boolean sameStore) { this.sameStore = sameStore; } public boolean isOrdered() { return ordered; } public void setOrdered(boolean ordered) { this.ordered = ordered; } }