KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > workflow > WorkflowManager


1 /*
2  * WorkflowManager.java
3  *
4  * Version: $Revision: 1.34 $
5  *
6  * Date: $Date: 2006/05/26 14:23:17 $
7  *
8  * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
9  * Institute of Technology. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * - Neither the name of the Hewlett-Packard Company nor the name of the
23  * Massachusetts Institute of Technology nor the names of their
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  */

40 package org.dspace.workflow;
41
42 import java.io.IOException JavaDoc;
43 import java.sql.SQLException JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.HashMap JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.Map JavaDoc;
48
49 import javax.mail.MessagingException JavaDoc;
50 import org.apache.log4j.Logger;
51 import org.dspace.authorize.AuthorizeException;
52 import org.dspace.authorize.AuthorizeManager;
53 import org.dspace.content.Bitstream;
54 import org.dspace.content.Collection;
55 import org.dspace.content.DCDate;
56 import org.dspace.content.DCValue;
57 import org.dspace.content.InstallItem;
58 import org.dspace.content.Item;
59 import org.dspace.content.WorkspaceItem;
60 import org.dspace.core.ConfigurationManager;
61 import org.dspace.core.Context;
62 import org.dspace.core.Email;
63 import org.dspace.core.I18N;
64 import org.dspace.core.LogManager;
65 import org.dspace.eperson.EPerson;
66 import org.dspace.eperson.Group;
67 import org.dspace.handle.HandleManager;
68 import org.dspace.history.HistoryManager;
69 import org.dspace.storage.rdbms.DatabaseManager;
70 import org.dspace.storage.rdbms.TableRow;
71 import org.dspace.storage.rdbms.TableRowIterator;
72
73 /**
74  * Workflow state machine
75  *
76  * Notes:
77  *
78  * Determining item status from the database:
79  *
80  * When an item has not been submitted yet, it is in the user's personal
81  * workspace (there is a row in PersonalWorkspace pointing to it.)
82  *
83  * When an item is submitted and is somewhere in a workflow, it has a row in the
84  * WorkflowItem table pointing to it. The state of the workflow can be
85  * determined by looking at WorkflowItem.getState()
86  *
87  * When a submission is complete, the WorkflowItem pointing to the item is
88  * destroyed and SubmitServlet.insertItem() is called, which hooks the item up
89  * to the archive.
90  *
91  * Notification: When an item enters a state that requires notification,
92  * (WFSTATE_STEP1POOL, WFSTATE_STEP2POOL, WFSTATE_STEP3POOL,) the workflow needs
93  * to notify the appropriate groups that they have a pending task to claim.
94  *
95  * Revealing lists of approvers, editors, and reviewers. A method could be added
96  * to do this, but it isn't strictly necessary. (say public List
97  * getStateEPeople( WorkflowItem wi, int state ) could return people affected by
98  * the item's current state.
99  */

100 public class WorkflowManager
101 {
102     // states to store in WorkflowItem for the GUI to report on
103
// fits our current set of workflow states (stored in WorkflowItem.state)
104
public static final int WFSTATE_SUBMIT = 0; // hmm, probably don't need
105

106     public static final int WFSTATE_STEP1POOL = 1; // waiting for a reviewer to
107
// claim it
108

109     public static final int WFSTATE_STEP1 = 2; // task - reviewer has claimed it
110

111     public static final int WFSTATE_STEP2POOL = 3; // waiting for an admin to
112
// claim it
113

114     public static final int WFSTATE_STEP2 = 4; // task - admin has claimed item
115

116     public static final int WFSTATE_STEP3POOL = 5; // waiting for an editor to
117
// claim it
118

119     public static final int WFSTATE_STEP3 = 6; // task - editor has claimed the
120
// item
121

122     public static final int WFSTATE_ARCHIVE = 7; // probably don't need this one
123
// either
124

125     /** Symbolic names of workflow steps. */
126     public static final String JavaDoc workflowText[] =
127     {
128         "SUBMIT", // 0
129
"STEP1POOL", // 1
130
"STEP1", // 2
131
"STEP2POOL", // 3
132
"STEP2", // 4
133
"STEP3POOL", // 5
134
"STEP3", // 6
135
"ARCHIVE" // 7
136
};
137
138     /* support for 'no notification' */
139     private static Map JavaDoc noEMail = new HashMap JavaDoc();
140
141     /** log4j logger */
142     private static Logger log = Logger.getLogger(WorkflowManager.class);
143
144     /**
145      * Translate symbolic name of workflow state into number.
146      * The name is case-insensitive. Returns -1 when name cannot
147      * be matched.
148      * @param state symbolic name of workflow state, must be one of
149      * the elements of workflowText array.
150      * @return numeric workflow state or -1 for error.
151      */

152     public static int getWorkflowID(String JavaDoc state)
153     {
154         for (int i = 0; i < workflowText.length; ++i)
155             if (state.equalsIgnoreCase(workflowText[i]))
156                 return i;
157         return -1;
158     }
159
160     /**
161      * startWorkflow() begins a workflow - in a single transaction do away with
162      * the PersonalWorkspace entry and turn it into a WorkflowItem.
163      *
164      * @param c
165      * Context
166      * @param wsi
167      * The WorkspaceItem to convert to a workflow item
168      * @return The resulting workflow item
169      */

170     public static WorkflowItem start(Context c, WorkspaceItem wsi)
171             throws SQLException JavaDoc, AuthorizeException, IOException JavaDoc
172     {
173         // FIXME Check auth
174
Item myitem = wsi.getItem();
175         Collection collection = wsi.getCollection();
176
177         log.info(LogManager.getHeader(c, "start_workflow", "workspace_item_id="
178                 + wsi.getID() + "item_id=" + myitem.getID() + "collection_id="
179                 + collection.getID()));
180
181         // record the start of the workflow w/provenance message
182
recordStart(c, myitem);
183
184         // create the WorkflowItem
185
TableRow row = DatabaseManager.create(c, "workflowitem");
186         row.setColumn("item_id", myitem.getID());
187         row.setColumn("collection_id", wsi.getCollection().getID());
188
189         WorkflowItem wfi = new WorkflowItem(c, row);
190
191         wfi.setMultipleFiles(wsi.hasMultipleFiles());
192         wfi.setMultipleTitles(wsi.hasMultipleTitles());
193         wfi.setPublishedBefore(wsi.isPublishedBefore());
194
195         // Write history creation event
196
HistoryManager.saveHistory(c, wfi, HistoryManager.CREATE, c
197                 .getCurrentUser(), c.getExtraLogInfo());
198
199         // remove the WorkspaceItem
200
wsi.deleteWrapper();
201
202         // now get the worflow started
203
doState(c, wfi, WFSTATE_STEP1POOL, null);
204
205         // Return the workflow item
206
return wfi;
207     }
208
209     /**
210      * startWithoutNotify() starts the workflow normally, but disables
211      * notifications (useful for large imports,) for the first workflow step -
212      * subsequent notifications happen normally
213      */

214     public static WorkflowItem startWithoutNotify(Context c, WorkspaceItem wsi)
215             throws SQLException JavaDoc, AuthorizeException, IOException JavaDoc
216     {
217         // make a hash table entry with item ID for no notify
218
// notify code checks no notify hash for item id
219
noEMail.put(new Integer JavaDoc(wsi.getItem().getID()), new Boolean JavaDoc(true));
220
221         return start(c, wsi);
222     }
223
224     /**
225      * getOwnedTasks() returns a List of WorkflowItems containing the tasks
226      * claimed and owned by an EPerson. The GUI displays this info on the
227      * MyDSpace page.
228      *
229      * @param e
230      * The EPerson we want to fetch owned tasks for.
231      */

232     public static List JavaDoc getOwnedTasks(Context c, EPerson e)
233             throws java.sql.SQLException JavaDoc
234     {
235         ArrayList JavaDoc mylist = new ArrayList JavaDoc();
236
237         String JavaDoc myquery = "SELECT * FROM WorkflowItem WHERE owner= ? ";
238
239         TableRowIterator tri = DatabaseManager.queryTable(c,
240                 "workflowitem", myquery,e.getID());
241
242         while (tri.hasNext())
243         {
244             mylist.add(new WorkflowItem(c, tri.next()));
245         }
246         
247         tri.close();
248
249         return mylist;
250     }
251
252     /**
253      * getPooledTasks() returns a List of WorkflowItems an EPerson could claim
254      * (as a reviewer, etc.) for display on a user's MyDSpace page.
255      *
256      * @param e
257      * The Eperson we want to fetch the pooled tasks for.
258      */

259     public static List JavaDoc getPooledTasks(Context c, EPerson e) throws SQLException JavaDoc
260     {
261         ArrayList JavaDoc mylist = new ArrayList JavaDoc();
262
263         String JavaDoc myquery = "SELECT workflowitem.* FROM workflowitem, TaskListItem" +
264                 " WHERE tasklistitem.eperson_id= ? " +
265                 " AND tasklistitem.workflow_id=workflowitem.workflow_id";
266
267         TableRowIterator tri = DatabaseManager
268                 .queryTable(c, "workflowitem", myquery, e.getID());
269
270         while (tri.hasNext())
271         {
272             mylist.add(new WorkflowItem(c, tri.next()));
273         }
274
275         tri.close();
276         
277         return mylist;
278     }
279
280     /**
281      * claim() claims a workflow task for an EPerson
282      *
283      * @param wi
284      * WorkflowItem to do the claim on
285      * @param e
286      * The EPerson doing the claim
287      */

288     public static void claim(Context c, WorkflowItem wi, EPerson e)
289             throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
290     {
291         int taskstate = wi.getState();
292
293         switch (taskstate)
294         {
295         case WFSTATE_STEP1POOL:
296
297             // authorize DSpaceActions.SUBMIT_REVIEW
298
doState(c, wi, WFSTATE_STEP1, e);
299
300             break;
301
302         case WFSTATE_STEP2POOL:
303
304             // authorize DSpaceActions.SUBMIT_STEP2
305
doState(c, wi, WFSTATE_STEP2, e);
306
307             break;
308
309         case WFSTATE_STEP3POOL:
310
311             // authorize DSpaceActions.SUBMIT_STEP3
312
doState(c, wi, WFSTATE_STEP3, e);
313
314             break;
315
316         // if we got here, we weren't pooled... error?
317
// FIXME - log the error?
318
}
319
320         log.info(LogManager.getHeader(c, "claim_task", "workflow_item_id="
321                 + wi.getID() + "item_id=" + wi.getItem().getID()
322                 + "collection_id=" + wi.getCollection().getID()
323                 + "newowner_id=" + wi.getOwner().getID() + "old_state="
324                 + taskstate + "new_state=" + wi.getState()));
325     }
326
327     /**
328      * approveAction() sends an item forward in the workflow (reviewers,
329      * approvers, and editors all do an 'approve' to move the item forward) if
330      * the item arrives at the submit state, then remove the WorkflowItem and
331      * call SubmitServlet.insertItem() to put it in the archive, and email
332      * notify the submitter of a successful submission
333      *
334      * @param c
335      * Context
336      * @param wi
337      * WorkflowItem do do the approval on
338      * @param e
339      * EPerson doing the approval
340      */

341     public static void advance(Context c, WorkflowItem wi, EPerson e)
342             throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
343     {
344         int taskstate = wi.getState();
345
346         switch (taskstate)
347         {
348         case WFSTATE_STEP1:
349
350             // authorize DSpaceActions.SUBMIT_REVIEW
351
// Record provenance
352
recordApproval(c, wi, e);
353             doState(c, wi, WFSTATE_STEP2POOL, e);
354
355             break;
356
357         case WFSTATE_STEP2:
358
359             // authorize DSpaceActions.SUBMIT_STEP2
360
// Record provenance
361
recordApproval(c, wi, e);
362             doState(c, wi, WFSTATE_STEP3POOL, e);
363
364             break;
365
366         case WFSTATE_STEP3:
367
368             // authorize DSpaceActions.SUBMIT_STEP3
369
// We don't record approval for editors, since they can't reject,
370
// and thus didn't actually make a decision
371
doState(c, wi, WFSTATE_ARCHIVE, e);
372
373             break;
374
375         // error handling? shouldn't get here
376
}
377
378         log.info(LogManager.getHeader(c, "advance_workflow",
379                 "workflow_item_id=" + wi.getID() + ",item_id="
380                         + wi.getItem().getID() + ",collection_id="
381                         + wi.getCollection().getID() + ",old_state="
382                         + taskstate + ",new_state=" + wi.getState()));
383     }
384
385     /**
386      * unclaim() returns an owned task/item to the pool
387      *
388      * @param c
389      * Context
390      * @param wi
391      * WorkflowItem to operate on
392      * @param e
393      * EPerson doing the operation
394      */

395     public static void unclaim(Context c, WorkflowItem wi, EPerson e)
396             throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
397     {
398         int taskstate = wi.getState();
399
400         switch (taskstate)
401         {
402         case WFSTATE_STEP1:
403
404             // authorize DSpaceActions.STEP1
405
doState(c, wi, WFSTATE_STEP1POOL, e);
406
407             break;
408
409         case WFSTATE_STEP2:
410
411             // authorize DSpaceActions.APPROVE
412
doState(c, wi, WFSTATE_STEP2POOL, e);
413
414             break;
415
416         case WFSTATE_STEP3:
417
418             // authorize DSpaceActions.STEP3
419
doState(c, wi, WFSTATE_STEP3POOL, e);
420
421             break;
422
423         // error handling? shouldn't get here
424
// FIXME - what to do with error - log it?
425
}
426
427         log.info(LogManager.getHeader(c, "unclaim_workflow",
428                 "workflow_item_id=" + wi.getID() + ",item_id="
429                         + wi.getItem().getID() + ",collection_id="
430                         + wi.getCollection().getID() + ",old_state="
431                         + taskstate + ",new_state=" + wi.getState()));
432     }
433
434     /**
435      * abort() aborts a workflow, completely deleting it (administrator do this)
436      * (it will basically do a reject from any state - the item ends up back in
437      * the user's PersonalWorkspace
438      *
439      * @param c
440      * Context
441      * @param wi
442      * WorkflowItem to operate on
443      * @param e
444      * EPerson doing the operation
445      */

446     public static void abort(Context c, WorkflowItem wi, EPerson e)
447             throws SQLException JavaDoc, AuthorizeException, IOException JavaDoc
448     {
449         // authorize a DSpaceActions.ABORT
450
if (!AuthorizeManager.isAdmin(c))
451         {
452             throw new AuthorizeException(
453                     "You must be an admin to abort a workflow");
454         }
455
456         // stop workflow regardless of its state
457
deleteTasks(c, wi);
458
459         log.info(LogManager.getHeader(c, "abort_workflow", "workflow_item_id="
460                 + wi.getID() + "item_id=" + wi.getItem().getID()
461                 + "collection_id=" + wi.getCollection().getID() + "eperson_id="
462                 + e.getID()));
463
464         // convert into personal workspace
465
WorkspaceItem wsi = returnToWorkspace(c, wi);
466     }
467
468     // returns true if archived
469
private static boolean doState(Context c, WorkflowItem wi, int newstate,
470             EPerson newowner) throws SQLException JavaDoc, IOException JavaDoc,
471             AuthorizeException
472     {
473         Collection mycollection = wi.getCollection();
474         Group mygroup = null;
475         boolean archived = false;
476
477         wi.setState(newstate);
478
479         switch (newstate)
480         {
481         case WFSTATE_STEP1POOL:
482
483             // any reviewers?
484
// if so, add them to the tasklist
485
wi.setOwner(null);
486
487             // get reviewers (group 1 )
488
mygroup = mycollection.getWorkflowGroup(1);
489
490             if ((mygroup != null) && !(mygroup.isEmpty()))
491             {
492                 // get a list of all epeople in group (or any subgroups)
493
EPerson[] epa = Group.allMembers(c, mygroup);
494                 
495                 // there were reviewers, change the state
496
// and add them to the list
497
createTasks(c, wi, epa);
498                 wi.update();
499
500                 // email notification
501
notifyGroupOfTask(c, wi, mygroup, epa);
502             }
503             else
504             {
505                 // no reviewers, skip ahead
506
archived = doState(c, wi, WFSTATE_STEP2POOL, null);
507             }
508
509             break;
510
511         case WFSTATE_STEP1:
512
513             // remove reviewers from tasklist
514
// assign owner
515
deleteTasks(c, wi);
516             wi.setOwner(newowner);
517
518             break;
519
520         case WFSTATE_STEP2POOL:
521
522             // clear owner
523
// any approvers?
524
// if so, add them to tasklist
525
// if not, skip to next state
526
wi.setOwner(null);
527
528             // get approvers (group 2)
529
mygroup = mycollection.getWorkflowGroup(2);
530
531             if ((mygroup != null) && !(mygroup.isEmpty()))
532             {
533                 //get a list of all epeople in group (or any subgroups)
534
EPerson[] epa = Group.allMembers(c, mygroup);
535                 
536                 // there were approvers, change the state
537
// timestamp, and add them to the list
538
createTasks(c, wi, epa);
539
540                 // email notification
541
notifyGroupOfTask(c, wi, mygroup, epa);
542             }
543             else
544             {
545                 // no reviewers, skip ahead
546
archived = doState(c, wi, WFSTATE_STEP3POOL, null);
547             }
548
549             break;
550
551         case WFSTATE_STEP2:
552
553             // remove admins from tasklist
554
// assign owner
555
deleteTasks(c, wi);
556             wi.setOwner(newowner);
557
558             break;
559
560         case WFSTATE_STEP3POOL:
561
562             // any editors?
563
// if so, add them to tasklist
564
wi.setOwner(null);
565             mygroup = mycollection.getWorkflowGroup(3);
566
567             if ((mygroup != null) && !(mygroup.isEmpty()))
568             {
569                 // get a list of all epeople in group (or any subgroups)
570
EPerson[] epa = Group.allMembers(c, mygroup);
571                 
572                 // there were editors, change the state
573
// timestamp, and add them to the list
574
createTasks(c, wi, epa);
575
576                 // email notification
577
notifyGroupOfTask(c, wi, mygroup, epa);
578             }
579             else
580             {
581                 // no editors, skip ahead
582
archived = doState(c, wi, WFSTATE_ARCHIVE, newowner);
583             }
584
585             break;
586
587         case WFSTATE_STEP3:
588
589             // remove editors from tasklist
590
// assign owner
591
deleteTasks(c, wi);
592             wi.setOwner(newowner);
593
594             break;
595
596         case WFSTATE_ARCHIVE:
597
598             // put in archive in one transaction
599
try
600             {
601                 // remove workflow tasks
602
deleteTasks(c, wi);
603
604                 mycollection = wi.getCollection();
605
606                 Item myitem = archive(c, wi);
607
608                 // now email notification
609
notifyOfArchive(c, myitem, mycollection);
610                 archived = true;
611             }
612             catch (IOException JavaDoc e)
613             {
614                 // indexer causes this
615
throw e;
616             }
617             catch (SQLException JavaDoc e)
618             {
619                 // problem starting workflow
620
throw e;
621             }
622
623             break;
624         }
625
626         if ((wi != null) && !archived)
627         {
628             wi.update();
629         }
630
631         return archived;
632     }
633
634     /**
635      * Commit the contained item to the main archive. The item is associated
636      * with the relevant collection, added to the search index, and any other
637      * tasks such as assigning dates are performed.
638      *
639      * @return the fully archived item.
640      */

641     private static Item archive(Context c, WorkflowItem wfi)
642             throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
643     {
644         // FIXME: Check auth
645
Item item = wfi.getItem();
646         Collection collection = wfi.getCollection();
647
648         log.info(LogManager.getHeader(c, "archive_item", "workflow_item_id="
649                 + wfi.getID() + "item_id=" + item.getID() + "collection_id="
650                 + collection.getID()));
651
652         InstallItem.installItem(c, wfi);
653
654         // Log the event
655
log.info(LogManager.getHeader(c, "install_item", "workflow_id="
656                 + wfi.getID() + ", item_id=" + item.getID() + "handle=FIXME"));
657
658         return item;
659     }
660
661     /**
662      * notify the submitter that the item is archived
663      */

664     private static void notifyOfArchive(Context c, Item i, Collection coll)
665             throws SQLException JavaDoc, IOException JavaDoc
666     {
667         try
668         {
669             // Get the item handle to email to user
670
String JavaDoc handle = HandleManager.findHandle(c, i);
671
672             // Get title
673
DCValue[] titles = i.getDC("title", null, Item.ANY);
674             String JavaDoc title = I18N.message("untitled", WorkflowManager.class);
675
676             if (titles.length > 0)
677             {
678                 title = titles[0].value;
679             }
680
681             // Get submitter
682
EPerson ep = i.getSubmitter();
683
684             Email email = ConfigurationManager.getEmail("submit_archive");
685
686             email.addRecipient(ep.getEmail());
687
688             email.addArgument(title);
689             email.addArgument(coll.getMetadata("name"));
690             email.addArgument(HandleManager.getCanonicalForm(handle));
691
692             email.send();
693         }
694         catch (MessagingException JavaDoc e)
695         {
696             log.warn(LogManager.getHeader(c, "notifyOfArchive",
697                     "cannot email user" + " item_id=" + i.getID()));
698         }
699     }
700
701     /**
702      * Return the workflow item to the workspace of the submitter. The workflow
703      * item is removed, and a workspace item created.
704      *
705      * @param c
706      * Context
707      * @param wfi
708      * WorkflowItem to be 'dismantled'
709      * @return the workspace item
710      */

711     private static WorkspaceItem returnToWorkspace(Context c, WorkflowItem wfi)
712             throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
713     {
714         Item myitem = wfi.getItem();
715         Collection mycollection = wfi.getCollection();
716
717         // FIXME: How should this interact with the workflow system?
718
// FIXME: Remove license
719
// FIXME: Provenance statement?
720
// Create the new workspace item row
721
TableRow row = DatabaseManager.create(c, "workspaceitem");
722         row.setColumn("item_id", myitem.getID());
723         row.setColumn("collection_id", mycollection.getID());
724         DatabaseManager.update(c, row);
725
726         int wsi_id = row.getIntColumn("workspace_item_id");
727         WorkspaceItem wi = WorkspaceItem.find(c, wsi_id);
728         wi.setMultipleFiles(wfi.hasMultipleFiles());
729         wi.setMultipleTitles(wfi.hasMultipleTitles());
730         wi.setPublishedBefore(wfi.isPublishedBefore());
731         wi.update();
732
733         // remove any licenses that the item may have been given
734
myitem.removeLicenses();
735
736         //myitem.update();
737
log.info(LogManager.getHeader(c, "return_to_workspace",
738                 "workflow_item_id=" + wfi.getID() + "workspace_item_id="
739                         + wi.getID()));
740
741         // Now remove the workflow object manually from the database
742
DatabaseManager.updateQuery(c,
743                 "DELETE FROM WorkflowItem WHERE workflow_id=" + wfi.getID());
744
745         return wi;
746     }
747
748     /**
749      * rejects an item - rejection means undoing a submit - WorkspaceItem is
750      * created, and the WorkflowItem is removed, user is emailed
751      * rejection_message.
752      *
753      * @param c
754      * Context
755      * @param wi
756      * WorkflowItem to operate on
757      * @param e
758      * EPerson doing the operation
759      * @param rejection_message
760      * message to email to user
761      */

762     public static WorkspaceItem reject(Context c, WorkflowItem wi, EPerson e,
763             String JavaDoc rejection_message) throws SQLException JavaDoc, AuthorizeException,
764             IOException JavaDoc
765     {
766         // authorize a DSpaceActions.REJECT
767
// stop workflow
768
deleteTasks(c, wi);
769
770         // rejection provenance
771
Item myitem = wi.getItem();
772
773         // Get current date
774
String JavaDoc now = DCDate.getCurrent().toString();
775
776         // Get user's name + email address
777
String JavaDoc usersName = getEPersonName(e);
778
779         // Here's what happened
780
String JavaDoc provDescription = "Rejected by " + usersName + ", reason: "
781                 + rejection_message + " on " + now + " (GMT) ";
782
783         // Add to item as a DC field
784
myitem.addDC("description", "provenance", "en", provDescription);
785         myitem.update();
786
787         // convert into personal workspace
788
WorkspaceItem wsi = returnToWorkspace(c, wi);
789
790         // notify that it's been rejected
791
notifyOfReject(c, wi, e, rejection_message);
792
793         log.info(LogManager.getHeader(c, "reject_workflow", "workflow_item_id="
794                 + wi.getID() + "item_id=" + wi.getItem().getID()
795                 + "collection_id=" + wi.getCollection().getID() + "eperson_id="
796                 + e.getID()));
797
798         return wsi;
799     }
800
801     // creates workflow tasklist entries for a workflow
802
// for all the given EPeople
803
private static void createTasks(Context c, WorkflowItem wi, EPerson[] epa)
804             throws SQLException JavaDoc
805     {
806         // create a tasklist entry for each eperson
807
for (int i = 0; i < epa.length; i++)
808         {
809             // can we get away without creating a tasklistitem class?
810
// do we want to?
811
TableRow tr = DatabaseManager.create(c, "tasklistitem");
812             tr.setColumn("eperson_id", epa[i].getID());
813             tr.setColumn("workflow_id", wi.getID());
814             DatabaseManager.update(c, tr);
815         }
816     }
817
818     // deletes all tasks associated with a workflowitem
819
static void deleteTasks(Context c, WorkflowItem wi) throws SQLException JavaDoc
820     {
821         String JavaDoc myrequest = "DELETE FROM TaskListItem WHERE workflow_id= ? ";
822        
823         DatabaseManager.updateQuery(c, myrequest, wi.getID());
824     }
825
826     private static void notifyGroupOfTask(Context c, WorkflowItem wi,
827             Group mygroup, EPerson[] epa) throws SQLException JavaDoc, IOException JavaDoc
828     {
829         // check to see if notification is turned off
830
// and only do it once - delete key after notification has
831
// been suppressed for the first time
832
Integer JavaDoc myID = new Integer JavaDoc(wi.getItem().getID());
833
834         if (noEMail.containsKey(myID))
835         {
836             // suppress email, and delete key
837
noEMail.remove(myID);
838         }
839         else
840         {
841             try
842             {
843                 // Get the item title
844
String JavaDoc title = getItemTitle(wi);
845
846                 // Get the submitter's name
847
String JavaDoc submitter = getSubmitterName(wi);
848
849                 // Get the collection
850
Collection coll = wi.getCollection();
851
852                 String JavaDoc message = "";
853
854                 switch (wi.getState())
855                 {
856                 case WFSTATE_STEP1POOL:
857                     message = I18N.message("step1", WorkflowManager.class);
858                     break;
859
860                 case WFSTATE_STEP2POOL:
861                     message = I18N.message("step2", WorkflowManager.class);
862                     break;
863
864                 case WFSTATE_STEP3POOL:
865                     message = I18N.message("step3", WorkflowManager.class);
866                     break;
867                 }
868
869                 Email email = ConfigurationManager.getEmail("submit_task");
870
871                 email.addArgument(title);
872                 email.addArgument(coll.getMetadata("name"));
873                 email.addArgument(submitter);
874                 email.addArgument(message);
875                 email.addArgument(getMyDSpaceLink());
876
877                 emailRecipients(c, epa, email);
878             }
879             catch (MessagingException JavaDoc e)
880             {
881                 log.warn(LogManager.getHeader(c, "notifyGroupofTask",
882                         "cannot email user" + " group_id" + mygroup.getID()
883                                 + " workflow_item_id" + wi.getID()));
884             }
885         }
886     }
887
888     /**
889      * Add all the specified people to the list of email recipients,
890      * and send it
891      *
892      * @param c
893      * Context
894      * @param epeople
895      * Eperson[] of recipients
896      * @param email
897      * Email object containing the message
898      */

899     private static void emailRecipients(Context c, EPerson[] epa, Email email)
900             throws SQLException JavaDoc, MessagingException JavaDoc
901     {
902         for (int i = 0; i < epa.length; i++)
903         {
904             email.addRecipient(epa[i].getEmail());
905         }
906
907         email.send();
908     }
909
910     private static String JavaDoc getMyDSpaceLink()
911     {
912         return ConfigurationManager.getProperty("dspace.url") + "/mydspace";
913     }
914
915     private static void notifyOfReject(Context c, WorkflowItem wi, EPerson e,
916             String JavaDoc reason)
917     {
918         try
919         {
920             // Get the item title
921
String JavaDoc title = getItemTitle(wi);
922
923             // Get the collection
924
Collection coll = wi.getCollection();
925
926             // Get rejector's name
927
String JavaDoc rejector = getEPersonName(e);
928
929             Email email = ConfigurationManager.getEmail("submit_reject");
930
931             email.addRecipient(getSubmitterEPerson(wi).getEmail());
932             email.addArgument(title);
933             email.addArgument(coll.getMetadata("name"));
934             email.addArgument(rejector);
935             email.addArgument(reason);
936             email.addArgument(getMyDSpaceLink());
937
938             email.send();
939         }
940         catch (Exception JavaDoc ex)
941         {
942             // log this email error
943
log.warn(LogManager.getHeader(c, "notify_of_reject",
944                     "cannot email user" + " eperson_id" + e.getID()
945                             + " eperson_email" + e.getEmail()
946                             + " workflow_item_id" + wi.getID()));
947         }
948     }
949
950     // FIXME - are the following methods still needed?
951
private static EPerson getSubmitterEPerson(WorkflowItem wi)
952             throws SQLException JavaDoc
953     {
954         EPerson e = wi.getSubmitter();
955
956         return e;
957     }
958
959     /**
960      * get the title of the item in this workflow
961      *
962      * @param wi the workflow item object
963      */

964     public static String JavaDoc getItemTitle(WorkflowItem wi) throws SQLException JavaDoc
965     {
966         Item myitem = wi.getItem();
967         DCValue[] titles = myitem.getDC("title", null, Item.ANY);
968
969         // only return the first element, or "Untitled"
970
if (titles.length > 0)
971         {
972             return titles[0].value;
973         }
974         else
975         {
976             return I18N.message("untitled", WorkflowManager.class);
977         }
978     }
979
980     /**
981      * get the name of the eperson who started this workflow
982      *
983      * @param wi the workflow item
984      */

985     public static String JavaDoc getSubmitterName(WorkflowItem wi) throws SQLException JavaDoc
986     {
987         EPerson e = wi.getSubmitter();
988
989         return getEPersonName(e);
990     }
991
992     private static String JavaDoc getEPersonName(EPerson e) throws SQLException JavaDoc
993     {
994         String JavaDoc submitter = e.getFullName();
995
996         submitter = submitter + "(" + e.getEmail() + ")";
997
998         return submitter;
999     }
1000
1001    // Record approval provenance statement
1002
private static void recordApproval(Context c, WorkflowItem wi, EPerson e)
1003            throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
1004    {
1005        Item item = wi.getItem();
1006
1007        // Get user's name + email address
1008
String JavaDoc usersName = getEPersonName(e);
1009
1010        // Get current date
1011
String JavaDoc now = DCDate.getCurrent().toString();
1012
1013        // Here's what happened
1014
String JavaDoc provDescription = "Approved for entry into archive by "
1015                + usersName + " on " + now + " (GMT) ";
1016
1017        // add bitstream descriptions (name, size, checksums)
1018
provDescription += InstallItem.getBitstreamProvenanceMessage(item);
1019
1020        // Add to item as a DC field
1021
item.addDC("description", "provenance", "en", provDescription);
1022        item.update();
1023    }
1024
1025    // Create workflow start provenance message
1026
private static void recordStart(Context c, Item myitem)
1027            throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException
1028    {
1029        // Get non-internal format bitstreams
1030
Bitstream[] bitstreams = myitem.getNonInternalBitstreams();
1031
1032        // get date
1033
DCDate now = DCDate.getCurrent();
1034
1035        // Create provenance description
1036
String JavaDoc provmessage = "";
1037
1038        if (myitem.getSubmitter() != null)
1039        {
1040            provmessage = "Submitted by " + myitem.getSubmitter().getFullName()
1041                    + " (" + myitem.getSubmitter().getEmail() + ") on "
1042                    + now.toString() + "\n";
1043        }
1044        else
1045        // null submitter
1046
{
1047            provmessage = "Submitted by unknown (probably automated) on"
1048                    + now.toString() + "\n";
1049        }
1050
1051        // add sizes and checksums of bitstreams
1052
provmessage += InstallItem.getBitstreamProvenanceMessage(myitem);
1053
1054        // Add message to the DC
1055
myitem.addDC("description", "provenance", "en", provmessage);
1056        myitem.update();
1057    }
1058}
1059
Popular Tags