001: /*
002: * Copyright 2005-2007 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.workgroup;
018:
019: import java.io.InputStream;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024:
025: import org.jdom.Element;
026: import org.kuali.workflow.attribute.Extension;
027: import org.kuali.workflow.workgroup.BaseWorkgroupExtension;
028:
029: import edu.iu.uis.eden.KEWServiceLocator;
030: import edu.iu.uis.eden.clientapp.vo.WorkflowGroupIdVO;
031: import edu.iu.uis.eden.clientapp.vo.WorkgroupIdVO;
032: import edu.iu.uis.eden.clientapp.vo.WorkgroupNameIdVO;
033: import edu.iu.uis.eden.exception.EdenUserNotFoundException;
034: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
035: import edu.iu.uis.eden.export.ExportDataSet;
036: import edu.iu.uis.eden.user.WorkflowUser;
037: import edu.iu.uis.eden.workgroup.dao.BaseWorkgroupDAO;
038: import edu.iu.uis.eden.workgroup.dao.BaseWorkgroupMemberDAO;
039: import edu.iu.uis.eden.xml.WorkgroupXmlHandler;
040: import edu.iu.uis.eden.xml.export.WorkgroupXmlExporter;
041:
042: /**
043: * The standard implementation of the WorkgroupService which is backed by a database.
044: *
045: * This implementation utilizes caching of workgroups which is safe in a clustered environment.
046: *
047: * @author Eric Westfall
048: */
049: public class BaseWorkgroupService implements WorkgroupService {
050:
051: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
052: .getLogger(BaseWorkgroupService.class);
053:
054: protected BaseWorkgroupDAO workgroupDAO;
055: protected BaseWorkgroupMemberDAO workgroupMemberDAO;
056: protected WorkgroupCapabilities capabilities = WorkgroupCapabilities
057: .getAll();
058:
059: public static final String WORKGROUP_ID_CACHE_GROUP = "WorkgroupId";
060: public static final String WORKGROUP_NAME_CACHE_GROUP = "WorkgroupName";
061:
062: // WorkgroupService methods
063:
064: public WorkgroupCapabilities getCapabilities() {
065: return capabilities;
066: }
067:
068: public Workgroup getBlankWorkgroup() {
069: return new BaseWorkgroup();
070: }
071:
072: public Extension getBlankWorkgroupExtension() {
073: return new BaseWorkgroupExtension();
074: }
075:
076: public boolean isUserMemberOfGroup(GroupId groupId,
077: WorkflowUser user) throws EdenUserNotFoundException {
078: Workgroup workgroup = this .getWorkgroup(groupId);
079: return workgroup == null ? false : workgroup.hasMember(user);
080: }
081:
082: public List search(Workgroup workgroup,
083: Map<String, String> extensionValues, boolean useWildCards) {
084: List workgroups = getWorkgroupDAO().search(workgroup,
085: extensionValues);
086: try {
087: materializeMembers(workgroups);
088: } catch (EdenUserNotFoundException e) {
089: throw new WorkflowRuntimeException(
090: "A problem was encountered when searching for workgroup.",
091: e);
092: }
093: return workgroups;
094: }
095:
096: public List search(Workgroup workgroup,
097: Map<String, String> extensionValues, WorkflowUser user)
098: throws EdenUserNotFoundException {
099: List workgroups = getWorkgroupDAO().find(workgroup,
100: extensionValues, user);
101: materializeMembers(workgroups);
102: return workgroups;
103: }
104:
105: public Workgroup getWorkgroup(WorkgroupIdVO groupIdVO) {
106: GroupId groupId = null;
107: if (groupIdVO instanceof WorkflowGroupIdVO) {
108: groupId = new WorkflowGroupId(
109: ((WorkflowGroupIdVO) groupIdVO).getWorkgroupId());
110: } else if (groupIdVO instanceof WorkgroupNameIdVO) {
111: groupId = new GroupNameId(((WorkgroupNameIdVO) groupIdVO)
112: .getWorkgroupName());
113: } else {
114: throw new IllegalArgumentException(
115: "Attempting to find workgroup with invalid id type: "
116: + groupIdVO);
117: }
118: return getWorkgroup(groupId);
119: }
120:
121: public Workgroup getWorkgroup(GroupId groupId) {
122: return getWorkgroup(groupId, false);
123: }
124:
125: public Workgroup getWorkgroup(GroupId groupId,
126: boolean loadWorkgroupExtensions) {
127: BaseWorkgroup workgroup = null;
128: try {
129: if (groupId instanceof WorkflowGroupId) {
130: LOG.debug("Loading workgoup by id " + groupId);
131: WorkflowGroupId workflowGroupId = (WorkflowGroupId) groupId;
132: workgroup = fetchFromCache(groupId);
133: if (workgroup == null) {
134: workgroup = getWorkgroupDAO().findByWorkgroupId(
135: workflowGroupId.getGroupId());
136: if (workgroup != null) {
137: workgroup = initializeLoadedWorkgroup(workgroup);
138: addToCache(workgroup);
139: }
140: }
141: } else if (groupId instanceof GroupNameId) {
142: LOG.debug("Loading workgroup from name " + groupId);
143: GroupNameId groupNameId = (GroupNameId) groupId;
144: workgroup = fetchFromCache(groupNameId);
145: if (workgroup == null) {
146: workgroup = getWorkgroupDAO().findByName(
147: groupNameId.getNameId());
148: if (workgroup != null) {
149: workgroup = initializeLoadedWorkgroup(workgroup);
150: addToCache(workgroup);
151: }
152: }
153: }
154: // if we can't find it in the database, ask subclasses if they have an extension workgroup to load
155: if (workgroup == null) {
156: workgroup = getExternalWorkgroup(groupId,
157: loadWorkgroupExtensions);
158: }
159: } catch (EdenUserNotFoundException e) {
160: throw new WorkflowRuntimeException(
161: "Error locating user in workgroup.", e);
162: }
163: return workgroup;
164: }
165:
166: /**
167: * Initializes the Workgroup after being loaded from the database. This method can be
168: * overriden by subclasses to perform institution specific functions (such as wrapping
169: * the workgroup in a custom implementation prior to it being cached).
170: *
171: * The default behavior of this method is to materialize the members of the SimpleWorkgroup
172: * from the OJB data bean using the <code>materializeMembers()</code> method.
173: * Overridders of this method should be sure to perform this step as well if desired,
174: * preferably by invoking super.initializeLoadedWorkgroup.
175: *
176: * @param the workgroup to initialize
177: * @return the initialized workgroup, does not have to be the exact same instance as the workgroup
178: * passed in
179: */
180: protected BaseWorkgroup initializeLoadedWorkgroup(
181: BaseWorkgroup workgroup) throws EdenUserNotFoundException {
182: workgroup.materializeMembers();
183: return workgroup;
184: }
185:
186: protected BaseWorkgroup getExternalWorkgroup(GroupId groupId,
187: boolean loadWorkgroupExtensions) {
188: return null;
189: }
190:
191: public List<Workgroup> getUsersGroups(WorkflowUser user)
192: throws EdenUserNotFoundException {
193: List workgroupMembers = getWorkgroupMemberDAO()
194: .findByWorkflowId(
195: user.getWorkflowUserId().getWorkflowId());
196: List<Workgroup> workgroups = new ArrayList<Workgroup>();
197: for (Iterator iter = workgroupMembers.iterator(); iter
198: .hasNext();) {
199: BaseWorkgroupMember member = (BaseWorkgroupMember) iter
200: .next();
201: Workgroup workgroup = getWorkgroup(new WorkflowGroupId(
202: member.getWorkgroupId()));
203: if (workgroup == null) {
204: LOG
205: .warn("Attempted to find workgroup for workgroup Id:"
206: + member.getWorkgroupId()
207: + " for member:"
208: + member.getWorkflowId()
209: + " but null was returned");
210: } else {
211: List<Workgroup> workgroupsGroups = getWorkgroupsGroups(workgroup);
212: if (workgroupsGroups != null) {
213: workgroups.addAll(workgroupsGroups);
214: }
215: workgroups.add(workgroup);
216: }
217: }
218: return workgroups;
219: }
220:
221: public List<Workgroup> getWorkgroupsGroups(Workgroup workgroup) {
222: List<Workgroup> parentWorkgroups = new ArrayList<Workgroup>();
223: List<Long> immediateWorkgroupsGroupsIds = getWorkgroupDAO()
224: .getImmediateWorkgroupsGroupIds(
225: workgroup.getWorkflowGroupId().getGroupId());
226: for (Long workgroupId : immediateWorkgroupsGroupsIds) {
227: Workgroup parentWorkgroup = getWorkgroup(new WorkflowGroupId(
228: workgroupId));
229: parentWorkgroups.add(parentWorkgroup);
230: parentWorkgroups
231: .addAll(getWorkgroupsGroups(parentWorkgroup));
232: }
233: return parentWorkgroups;
234: }
235:
236: public Workgroup copy(Workgroup workgroup) {
237: if (workgroup == null) {
238: return null;
239: }
240: if (!(workgroup instanceof BaseWorkgroup)) {
241: throw new IllegalArgumentException(
242: "Can only copy instances of SimpleWorkgroups, given class was: "
243: + workgroup.getClass().getName());
244: }
245: BaseWorkgroup simpleWorkgroup = (BaseWorkgroup) workgroup;
246: BaseWorkgroup copyWorkgroup = new BaseWorkgroup();
247: copyWorkgroup.setActiveInd(simpleWorkgroup.getActiveInd());
248: copyWorkgroup.setDescription(simpleWorkgroup.getDescription());
249: copyWorkgroup.setGroupNameId(simpleWorkgroup.getGroupNameId());
250: copyWorkgroup.setMembers(simpleWorkgroup.getMembers());
251: copyWorkgroup.setWorkgroupMembers(simpleWorkgroup
252: .getWorkgroupMembers());
253: copyWorkgroup.setWorkflowGroupId(simpleWorkgroup
254: .getWorkflowGroupId());
255: copyWorkgroup.setWorkgroupType(simpleWorkgroup
256: .getWorkgroupType());
257: return copyWorkgroup;
258: }
259:
260: protected BaseWorkgroup fetchFromCache(GroupId groupId) {
261: return (BaseWorkgroup) KEWServiceLocator
262: .getCacheAdministrator().getFromCache(
263: generateCacheKey(groupId));
264: }
265:
266: protected String generateCacheKey(GroupId groupId) {
267: if (groupId == null) {
268: throw new IllegalArgumentException(
269: "The GroupId is null when attempting to generate cache key.");
270: } else if (groupId instanceof WorkflowGroupId) {
271: return WORKGROUP_ID_CACHE_GROUP + ":"
272: + ((WorkflowGroupId) groupId);
273: } else if (groupId instanceof GroupNameId) {
274: return WORKGROUP_NAME_CACHE_GROUP + ":"
275: + ((GroupNameId) groupId);
276: } else {
277: throw new IllegalArgumentException(
278: "The given GroupId type is invalid: "
279: + groupId.getClass().getName());
280: }
281: }
282:
283: protected void addToCache(BaseWorkgroup workgroup) {
284: if (workgroup != null) {
285: WorkflowGroupId groupId = workgroup.getWorkflowGroupId();
286: GroupNameId nameId = workgroup.getGroupNameId();
287: if (groupId != null && !groupId.isEmpty()) {
288: KEWServiceLocator.getCacheAdministrator().putInCache(
289: generateCacheKey(groupId), workgroup,
290: WORKGROUP_ID_CACHE_GROUP);
291: LOG
292: .debug("Caching workgroup by id="
293: + groupId.getGroupId()
294: + " with name '"
295: + (nameId != null ? nameId.getNameId()
296: : "null") + "'");
297: }
298: if (nameId != null && !nameId.isEmpty()) {
299: KEWServiceLocator.getCacheAdministrator().putInCache(
300: generateCacheKey(nameId), workgroup,
301: WORKGROUP_NAME_CACHE_GROUP);
302: LOG.debug("Caching workgroup by name='"
303: + nameId.getNameId()
304: + "' with id "
305: + (groupId != null ? groupId.getGroupId()
306: .toString() : "null"));
307: }
308:
309: }
310: }
311:
312: public void removeNameFromCache(GroupNameId name) {
313: KEWServiceLocator.getCacheAdministrator().flushEntry(
314: generateCacheKey(name));
315: }
316:
317: public void removeFromCacheById(WorkflowGroupId id) {
318: KEWServiceLocator.getCacheAdministrator().flushEntry(
319: generateCacheKey(id));
320: }
321:
322: // XMLLoader methods
323:
324: /**
325: * Loads workgroups from the given XML.
326: */
327: public void loadXml(InputStream stream, WorkflowUser user) {
328: try {
329: new WorkgroupXmlHandler().parseWorkgroupEntries(stream);
330: } catch (Exception e) {
331: if (e instanceof RuntimeException) {
332: throw (RuntimeException) e;
333: }
334: throw new RuntimeException(
335: "Caught Exception parsing workgroup xml", e);
336: }
337: }
338:
339: // XMLExporter methods
340:
341: public Element export(ExportDataSet dataSet) {
342: WorkgroupXmlExporter exporter = new WorkgroupXmlExporter();
343: return exporter.export(dataSet);
344: }
345:
346: // helper methods
347:
348: protected void materializeMembers(List workgroups)
349: throws EdenUserNotFoundException {
350: for (Iterator iterator = workgroups.iterator(); iterator
351: .hasNext();) {
352: ((BaseWorkgroup) iterator.next()).materializeMembers();
353: }
354: }
355:
356: public void save(Workgroup workgroup) {
357: // workgroup ids are always the same so lets remove any existing workgroups with this id from the cache
358: if (workgroup.getWorkflowGroupId() != null) {
359: Workgroup original = getWorkgroup(workgroup
360: .getWorkflowGroupId());
361: if (original != null) {
362: removeFromCache(original);
363: }
364: }
365: getWorkgroupDAO().save(workgroup);
366: }
367:
368: protected void removeFromCache(Workgroup workgroup) {
369: removeFromCacheById(workgroup.getWorkflowGroupId());
370: removeNameFromCache(workgroup.getGroupNameId());
371: }
372:
373: public void setWorkgroupDAO(BaseWorkgroupDAO workgroupDAO) {
374: this .workgroupDAO = workgroupDAO;
375: }
376:
377: protected BaseWorkgroupDAO getWorkgroupDAO() {
378: return workgroupDAO;
379: }
380:
381: protected BaseWorkgroupMemberDAO getWorkgroupMemberDAO() {
382: return workgroupMemberDAO;
383: }
384:
385: public void setWorkgroupMemberDAO(
386: BaseWorkgroupMemberDAO workgroupMemberDAO) {
387: this.workgroupMemberDAO = workgroupMemberDAO;
388: }
389:
390: }
|