View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.api;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.config.ConfigurationException;
20  import org.kuali.rice.core.api.util.ClassLoaderUtils;
21  import org.kuali.rice.kew.api.action.InvalidActionTakenException;
22  import org.kuali.rice.kew.api.doctype.IllegalDocumentTypeException;
23  import org.kuali.rice.kew.api.document.DocumentContentUpdate;
24  import org.kuali.rice.kew.api.document.DocumentUpdate;
25  
26  import java.io.BufferedReader;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.InputStreamReader;
30  import java.lang.reflect.InvocationTargetException;
31  import java.lang.reflect.Method;
32  
33  /**
34   * TODO ..
35   *
36   */
37  public final class WorkflowDocumentFactory {
38  
39  	private static final String CREATE_METHOD_NAME = "createDocument";
40  	private static final String LOAD_METHOD_NAME = "loadDocument";
41  	
42  	/**
43  	 * A lazy initialization holder class for the Provider.  Allows for
44  	 * thread-safe initialization of shared resource.
45  	 */
46  	private static final class ProviderHolder {
47  	    static final Object provider;
48  	    static final Method createMethod;
49  	    static final Method loadMethod;
50  	    static {
51  	        provider = loadProvider();
52  	        createMethod = locateCreateMethod(provider);
53  	        loadMethod = locateLoadMethod(provider);
54  	    }
55  	}
56  	
57      /**
58       * TODO 
59       * 
60       * @param principalId TODO
61       * @param documentTypeName TODO
62       * 
63       * @return TODO
64       * 
65       * @throws IllegalArgumentException if principalId is null or blank
66       * @throws IllegalArgumentException if documentTypeName is null or blank
67       * @throws IllegalDocumentTypeException if the document type does not allow for creation of a document,
68       * this can occur when the given document type is used only as a parent and has no route path configured
69       * @throws InvalidActionTakenException if the caller is not allowed to execute this action
70       */
71      public static WorkflowDocument createDocument(String principalId, String documentTypeName) {
72      	return createDocument(principalId, documentTypeName, null, null);
73      }
74      
75      /**
76       * TODO
77       * 
78       * @param principalId TODO
79       * @param documentTypeName TODO
80       * @param title TODO
81       * 
82       * @return TODO
83       * 
84       * @throws IllegalArgumentException if principalId is null or blank
85       * @throws IllegalArgumentException if documentTypeName is null or blank
86       * @throws IllegalDocumentTypeException if documentTypeName does not represent a valid document type
87       */
88      public static WorkflowDocument createDocument(String principalId, String documentTypeName, String title) {
89      	DocumentUpdate.Builder builder = DocumentUpdate.Builder.create();
90      	builder.setTitle(title);
91      	return createDocument(principalId, documentTypeName, builder.build(), null);
92      }
93      
94      /**
95       * TODO
96       * 
97       * @param principalId TODO
98       * @param documentTypeName TODO
99       * @param documentUpdate TODO
100      * @param documentContentUpdate TODO
101      * 
102      * @return TODO
103      * 
104      * @throws IllegalArgumentException if principalId is null or blank
105      * @throws IllegalArgumentException if documentTypeName is null or blank
106      * @throws IllegalDocumentTypeException if documentTypeName does not represent a valid document type
107      */
108 	public static WorkflowDocument createDocument(String principalId, String documentTypeName, DocumentUpdate documentUpdate, DocumentContentUpdate documentContentUpdate) {
109 		if (StringUtils.isBlank(principalId)) {
110 			throw new IllegalArgumentException("principalId was null or blank");
111 		}
112 		if (StringUtils.isBlank(documentTypeName)) {
113 			throw new IllegalArgumentException("documentTypeName was null or blank");
114 		}
115 		
116 		Object workflowDocument = null;
117 		
118 		try {
119 			workflowDocument = ProviderHolder.createMethod.invoke(ProviderHolder.provider, principalId, documentTypeName, documentUpdate, documentContentUpdate);
120 		} catch (IllegalAccessException e) {
121 			throw new ConfigurationException("Failed to invoke " + CREATE_METHOD_NAME, e);
122 		} catch (InvocationTargetException e) {
123 			if (e.getCause() instanceof RuntimeException) {
124 				throw (RuntimeException)e.getCause();
125 			}
126 			throw new ConfigurationException("Failed to invoke " + CREATE_METHOD_NAME, e);
127 		}
128 
129 		if (!(workflowDocument instanceof WorkflowDocument)) {
130 			throw new ConfigurationException("Created document is not a proper instance of " + WorkflowDocument.class + ", was instead " + workflowDocument.getClass());
131 		}
132 		return (WorkflowDocument)workflowDocument;
133 	}
134 	
135 	public static WorkflowDocument loadDocument(String principalId, String documentId) {
136 		if (StringUtils.isBlank(principalId)) {
137 			throw new IllegalArgumentException("principalId was null or blank");
138 		}
139 		if (StringUtils.isBlank(documentId)) {
140 			throw new IllegalArgumentException("documentId was null or blank");
141 		}
142 				
143 		Object workflowDocument = null;
144 		
145 		try {
146 			workflowDocument = ProviderHolder.loadMethod.invoke(ProviderHolder.provider, principalId, documentId);
147 		} catch (IllegalAccessException e) {
148 			throw new ConfigurationException("Failed to invoke " + LOAD_METHOD_NAME, e);
149 		} catch (InvocationTargetException e) {
150 			if (e.getCause() instanceof RuntimeException) {
151 				throw (RuntimeException)e.getCause();
152 			}
153 			throw new ConfigurationException("Failed to invoke " + LOAD_METHOD_NAME, e);
154 		}
155 
156 		if (!(workflowDocument instanceof WorkflowDocument)) {
157 			throw new ConfigurationException("Loaded document is not a proper instance of " + WorkflowDocument.class + ", was instead " + workflowDocument.getClass());
158 		}
159 		return (WorkflowDocument)workflowDocument;
160 	}
161 	
162 	private static Object loadProvider() {
163 		String providerClassName = null;
164 		String resource = null;
165 		try {
166             resource = new StringBuilder().append("META-INF/services/").append(WorkflowDocument.class.getName()).toString();
167             final InputStream resourceStream = ClassLoaderUtils.getDefaultClassLoader().getResourceAsStream(resource.toString());
168             if (resourceStream != null) {
169                 BufferedReader reader = new BufferedReader(new InputStreamReader(resourceStream, "UTF-8"));
170                 providerClassName = reader.readLine().trim();
171                 reader.close();
172                 Class<?> providerClass = Class.forName(providerClassName);
173                 return newInstance(providerClass);
174             } else {
175                 throw new ConfigurationException("Failed to locate a services definition file at " + resource);
176             }
177         } catch (IOException e) {
178             throw new ConfigurationException("Failure processing services definition file at " + resource, e);
179         } catch (ClassNotFoundException e) {
180         	throw new ConfigurationException("Failed to load provider class: " + providerClassName, e);
181         }
182 	}
183 	
184 	private static Object newInstance(Class<?> providerClass) {
185 		try {
186 			return providerClass.newInstance();
187 		} catch (InstantiationException e) {
188 			throw new ConfigurationException("Failed to instantiate provider class: " + providerClass.getName(), e);
189 		} catch (IllegalAccessException e) {
190 			throw new ConfigurationException("Failed to instantiate provider class: " + providerClass.getName(), e);
191 		}
192 	}
193 	
194 	private static Method locateCreateMethod(Object provider) {
195         try {
196             return provider.getClass().getMethod(CREATE_METHOD_NAME, String.class, String.class, DocumentUpdate.class, DocumentContentUpdate.class);
197         } catch (NoSuchMethodException e) {
198             throw new ConfigurationException("Failed to locate valid createDocument method signature on provider class: " + provider.getClass().getName(), e);
199         } catch (SecurityException e) {
200             throw new ConfigurationException("Encountered security issue when attempting to access createDocument method on provider class: " + provider.getClass().getName(), e);
201         }
202 	}
203 	
204 	private static Method locateLoadMethod(Object provider) {
205         try {
206             return provider.getClass().getMethod(LOAD_METHOD_NAME, String.class, String.class);
207         } catch (NoSuchMethodException e) {
208             throw new ConfigurationException("Failed to locate valid createDocument method signature on provider class: " + provider.getClass().getName(), e);
209         } catch (SecurityException e) {
210             throw new ConfigurationException("Encountered security issue when attempting to access createDocument method on provider class: " + provider.getClass().getName(), e);
211         }
212 	}
213 
214 }