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}