001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.doctype.service.impl; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.jdom.Element; 020import org.kuali.rice.core.api.impex.ExportDataSet; 021import org.kuali.rice.kew.doctype.bo.DocumentType; 022import org.kuali.rice.kew.doctype.dao.DocumentTypeDAO; 023import org.kuali.rice.kew.doctype.service.DocumentTypeService; 024import org.kuali.rice.kew.exception.WorkflowServiceErrorException; 025import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl; 026import org.kuali.rice.kew.xml.DocumentTypeXmlParser; 027import org.kuali.rice.kew.xml.export.DocumentTypeXmlExporter; 028import org.kuali.rice.krad.util.ObjectUtils; 029 030import java.io.InputStream; 031import java.util.ArrayList; 032import java.util.Collection; 033import java.util.Iterator; 034import java.util.List; 035 036 037/** 038 * The standard implementation of the DocumentTypeService. 039 * 040 * @author Kuali Rice Team (rice.collab@kuali.org) 041 * This class does not support KEW REMOTE mode. 042 * KULRICE-7770 added an expicit check for this class in GlobalResourceDelegatingSpringCreator.java 043 */ 044public class DocumentTypeServiceImpl implements DocumentTypeService { 045 046 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentTypeServiceImpl.class); 047 protected static final String XML_FILE_PARSE_ERROR = "general.error.parsexml"; 048 049 private DocumentTypeDAO documentTypeDAO; 050 051 public Collection<DocumentType> find(DocumentType documentType, String docTypeParentName, boolean climbHierarchy) { 052 DocumentType docTypeParent = this.findByName(docTypeParentName); 053 return getDocumentTypeDAO().find(documentType, docTypeParent, climbHierarchy); 054 } 055 056 public DocumentType findById(String documentTypeId) { 057 if (documentTypeId == null) { 058 return null; 059 } 060 061 return getDocumentTypeDAO().findById(documentTypeId); 062 } 063 064 public DocumentType findByDocumentId(String documentId) { 065 if (documentId == null) { 066 return null; 067 } 068 String documentTypeId = getDocumentTypeDAO().findDocumentTypeIdByDocumentId(documentId); 069 return findById(documentTypeId); 070 } 071 072 public DocumentType findByName(String name) { 073 return this.findByName(name, true); 074 } 075 076 public DocumentType findByNameCaseInsensitive(String name) { 077 return this.findByName(name, false); 078 } 079 080 /** 081 * 082 * This method seaches for a DocumentType by document name. 083 * 084 * @param name 085 * @param caseSensitive 086 * @return 087 */ 088 private DocumentType findByName(String name, boolean caseSensitive) { 089 if (name == null) { 090 return null; 091 } 092 return getDocumentTypeDAO().findByName(name, caseSensitive); 093 } 094 095 public void versionAndSave(DocumentType documentType) { 096 // at this point this save is designed to version the document type by creating an entire new record if this is going to be an update and 097 // not a create just throw and exception to be on the safe side 098 if (documentType.getDocumentTypeId() != null && documentType.getVersionNumber() != null) { 099 throw new RuntimeException("DocumentType configured for update and not versioning which we support"); 100 } 101 102 // grab the old document. Don't Use Cached Version! 103 DocumentType oldDocumentType = findByName(documentType.getName()); 104 // reset the children on the oldDocumentType 105 //oldDocumentType.resetChildren(); 106 String existingDocTypeId = null; 107 if (oldDocumentType != null) { 108 existingDocTypeId = oldDocumentType.getDocumentTypeId(); 109 // set version number on the new doc type using the max version from the database 110 Integer maxVersionNumber = documentTypeDAO.getMaxVersionNumber(documentType.getName()); 111 documentType.setVersion((maxVersionNumber != null) ? new Integer(maxVersionNumber.intValue() + 1) : new Integer(0)); 112 oldDocumentType.setCurrentInd(Boolean.FALSE); 113 if ( LOG.isInfoEnabled() ) { 114 LOG.info("Saving old document type Id " + oldDocumentType.getDocumentTypeId() + " name '" + oldDocumentType.getName() + "' (current = " + oldDocumentType.getCurrentInd() + ")"); 115 } 116 save(oldDocumentType); 117 } 118 // check to see that no current documents exist in database 119 if (!CollectionUtils.isEmpty(documentTypeDAO.findAllCurrentByName(documentType.getName()))) { 120 String errorMsg = "Found invalid 'current' document with name '" + documentType.getName() + "'. None should exist."; 121 LOG.error(errorMsg); 122 throw new RuntimeException(errorMsg); 123 } 124 // set up the previous current doc type on the new doc type 125 documentType.setPreviousVersionId(existingDocTypeId); 126 documentType.setCurrentInd(Boolean.TRUE); 127 save(documentType); 128 if ( LOG.isInfoEnabled() ) { 129 LOG.info("Saved current document type Id " + documentType.getDocumentTypeId() + " name '" + documentType.getName() + "' (current = " + documentType.getCurrentInd() + ")"); 130 } 131 //attach the children to this new parent. cloning the children would probably be a better way to go here... 132 if (ObjectUtils.isNotNull(existingDocTypeId)) { 133 // documentType.getPreviousVersion() should not be null at this point 134 for (Iterator iterator = getChildDocumentTypes(existingDocTypeId).iterator(); iterator.hasNext();) { 135// for (Iterator iterator = oldDocumentType.getChildrenDocTypes().iterator(); iterator.hasNext();) { 136 DocumentType child = (DocumentType) iterator.next(); 137 child.setDocTypeParentId(documentType.getDocumentTypeId()); 138 save(child); 139 if ( LOG.isInfoEnabled() ) { 140 LOG.info("Saved child document type Id " + child.getDocumentTypeId() + " name '" + child.getName() + "' (parent = " + child.getDocTypeParentId() + ", current = " + child.getCurrentInd() + ")"); 141 } 142 } 143 } 144 // initiate a save of this document type's parent document type, this will force a 145 // version check which should reveal (via an optimistic lock exception) whether or 146 // not there is a concurrent transaction 147 // which has modified the parent (and therefore made it non-current) 148 // be sure to get the parent doc type directly from the db and not from the cache 149 if (documentType.getDocTypeParentId() != null) { 150 DocumentType parent = getDocumentTypeDAO().findById(documentType.getDocTypeParentId()); 151 save(parent); 152 if ( LOG.isInfoEnabled() ) { 153 LOG.info("Saved parent document type Id " + parent.getDocumentTypeId() + " name '" + parent.getName() + "' (current = " + parent.getCurrentInd() + ")"); 154 } 155 } 156 } 157 158 public void save(DocumentType documentType) { 159 getDocumentTypeDAO().save(documentType); 160 } 161 162 public DocumentTypeDAO getDocumentTypeDAO() { 163 return documentTypeDAO; 164 } 165 166 public void setDocumentTypeDAO(DocumentTypeDAO documentTypeDAO) { 167 this.documentTypeDAO = documentTypeDAO; 168 } 169 170 public synchronized List findAllCurrentRootDocuments() { 171 return getDocumentTypeDAO().findAllCurrentRootDocuments(); 172 } 173 174 public List findAllCurrent() { 175 return getDocumentTypeDAO().findAllCurrent(); 176 } 177 178 public List<DocumentType> findPreviousInstances(String documentTypeName) { 179 return getDocumentTypeDAO().findPreviousInstances(documentTypeName); 180 } 181 182 public DocumentType findRootDocumentType(DocumentType docType) { 183 if (docType.getParentDocType() != null) { 184 return findRootDocumentType(docType.getParentDocType()); 185 } else { 186 return docType; 187 } 188 } 189 190 public void loadXml(InputStream inputStream, String principalId) { 191 DocumentTypeXmlParser parser = new DocumentTypeXmlParser(); 192 try { 193 parser.parseDocumentTypes(inputStream); 194 } catch (Exception e) { 195 WorkflowServiceErrorException wsee = new WorkflowServiceErrorException("Error parsing documentType XML file", new WorkflowServiceErrorImpl("Error parsing documentType XML file", XML_FILE_PARSE_ERROR)); 196 wsee.initCause(e); 197 throw wsee; 198 } 199 } 200 201 public Element export(ExportDataSet dataSet) { 202 DocumentTypeXmlExporter exporter = new DocumentTypeXmlExporter(); 203 return exporter.export(dataSet); 204 } 205 206 @Override 207 public boolean supportPrettyPrint() { 208 return true; 209 } 210 211 public List getChildDocumentTypes(String documentTypeId) { 212 List childDocumentTypes = new ArrayList(); 213 List childIds = getDocumentTypeDAO().getChildDocumentTypeIds(documentTypeId); 214 for (Iterator iter = childIds.iterator(); iter.hasNext();) { 215 String childDocumentTypeId = (String) iter.next(); 216 childDocumentTypes.add(findById(childDocumentTypeId)); 217 } 218 return childDocumentTypes; 219 } 220 221}