1 40 package org.dspace.workflow; 41 42 import java.io.IOException ; 43 import java.sql.SQLException ; 44 import java.util.ArrayList ; 45 import java.util.HashMap ; 46 import java.util.List ; 47 import java.util.Map ; 48 49 import javax.mail.MessagingException ; 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 100 public class WorkflowManager 101 { 102 public static final int WFSTATE_SUBMIT = 0; 106 public static final int WFSTATE_STEP1POOL = 1; 109 public static final int WFSTATE_STEP1 = 2; 111 public static final int WFSTATE_STEP2POOL = 3; 114 public static final int WFSTATE_STEP2 = 4; 116 public static final int WFSTATE_STEP3POOL = 5; 119 public static final int WFSTATE_STEP3 = 6; 122 public static final int WFSTATE_ARCHIVE = 7; 125 126 public static final String workflowText[] = 127 { 128 "SUBMIT", "STEP1POOL", "STEP1", "STEP2POOL", "STEP2", "STEP3POOL", "STEP3", "ARCHIVE" }; 137 138 139 private static Map noEMail = new HashMap (); 140 141 142 private static Logger log = Logger.getLogger(WorkflowManager.class); 143 144 152 public static int getWorkflowID(String 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 170 public static WorkflowItem start(Context c, WorkspaceItem wsi) 171 throws SQLException , AuthorizeException, IOException 172 { 173 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 recordStart(c, myitem); 183 184 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 HistoryManager.saveHistory(c, wfi, HistoryManager.CREATE, c 197 .getCurrentUser(), c.getExtraLogInfo()); 198 199 wsi.deleteWrapper(); 201 202 doState(c, wfi, WFSTATE_STEP1POOL, null); 204 205 return wfi; 207 } 208 209 214 public static WorkflowItem startWithoutNotify(Context c, WorkspaceItem wsi) 215 throws SQLException , AuthorizeException, IOException 216 { 217 noEMail.put(new Integer (wsi.getItem().getID()), new Boolean (true)); 220 221 return start(c, wsi); 222 } 223 224 232 public static List getOwnedTasks(Context c, EPerson e) 233 throws java.sql.SQLException 234 { 235 ArrayList mylist = new ArrayList (); 236 237 String 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 259 public static List getPooledTasks(Context c, EPerson e) throws SQLException 260 { 261 ArrayList mylist = new ArrayList (); 262 263 String 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 288 public static void claim(Context c, WorkflowItem wi, EPerson e) 289 throws SQLException , IOException , AuthorizeException 290 { 291 int taskstate = wi.getState(); 292 293 switch (taskstate) 294 { 295 case WFSTATE_STEP1POOL: 296 297 doState(c, wi, WFSTATE_STEP1, e); 299 300 break; 301 302 case WFSTATE_STEP2POOL: 303 304 doState(c, wi, WFSTATE_STEP2, e); 306 307 break; 308 309 case WFSTATE_STEP3POOL: 310 311 doState(c, wi, WFSTATE_STEP3, e); 313 314 break; 315 316 } 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 341 public static void advance(Context c, WorkflowItem wi, EPerson e) 342 throws SQLException , IOException , AuthorizeException 343 { 344 int taskstate = wi.getState(); 345 346 switch (taskstate) 347 { 348 case WFSTATE_STEP1: 349 350 recordApproval(c, wi, e); 353 doState(c, wi, WFSTATE_STEP2POOL, e); 354 355 break; 356 357 case WFSTATE_STEP2: 358 359 recordApproval(c, wi, e); 362 doState(c, wi, WFSTATE_STEP3POOL, e); 363 364 break; 365 366 case WFSTATE_STEP3: 367 368 doState(c, wi, WFSTATE_ARCHIVE, e); 372 373 break; 374 375 } 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 395 public static void unclaim(Context c, WorkflowItem wi, EPerson e) 396 throws SQLException , IOException , AuthorizeException 397 { 398 int taskstate = wi.getState(); 399 400 switch (taskstate) 401 { 402 case WFSTATE_STEP1: 403 404 doState(c, wi, WFSTATE_STEP1POOL, e); 406 407 break; 408 409 case WFSTATE_STEP2: 410 411 doState(c, wi, WFSTATE_STEP2POOL, e); 413 414 break; 415 416 case WFSTATE_STEP3: 417 418 doState(c, wi, WFSTATE_STEP3POOL, e); 420 421 break; 422 423 } 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 446 public static void abort(Context c, WorkflowItem wi, EPerson e) 447 throws SQLException , AuthorizeException, IOException 448 { 449 if (!AuthorizeManager.isAdmin(c)) 451 { 452 throw new AuthorizeException( 453 "You must be an admin to abort a workflow"); 454 } 455 456 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 WorkspaceItem wsi = returnToWorkspace(c, wi); 466 } 467 468 private static boolean doState(Context c, WorkflowItem wi, int newstate, 470 EPerson newowner) throws SQLException , IOException , 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 wi.setOwner(null); 486 487 mygroup = mycollection.getWorkflowGroup(1); 489 490 if ((mygroup != null) && !(mygroup.isEmpty())) 491 { 492 EPerson[] epa = Group.allMembers(c, mygroup); 494 495 createTasks(c, wi, epa); 498 wi.update(); 499 500 notifyGroupOfTask(c, wi, mygroup, epa); 502 } 503 else 504 { 505 archived = doState(c, wi, WFSTATE_STEP2POOL, null); 507 } 508 509 break; 510 511 case WFSTATE_STEP1: 512 513 deleteTasks(c, wi); 516 wi.setOwner(newowner); 517 518 break; 519 520 case WFSTATE_STEP2POOL: 521 522 wi.setOwner(null); 527 528 mygroup = mycollection.getWorkflowGroup(2); 530 531 if ((mygroup != null) && !(mygroup.isEmpty())) 532 { 533 EPerson[] epa = Group.allMembers(c, mygroup); 535 536 createTasks(c, wi, epa); 539 540 notifyGroupOfTask(c, wi, mygroup, epa); 542 } 543 else 544 { 545 archived = doState(c, wi, WFSTATE_STEP3POOL, null); 547 } 548 549 break; 550 551 case WFSTATE_STEP2: 552 553 deleteTasks(c, wi); 556 wi.setOwner(newowner); 557 558 break; 559 560 case WFSTATE_STEP3POOL: 561 562 wi.setOwner(null); 565 mygroup = mycollection.getWorkflowGroup(3); 566 567 if ((mygroup != null) && !(mygroup.isEmpty())) 568 { 569 EPerson[] epa = Group.allMembers(c, mygroup); 571 572 createTasks(c, wi, epa); 575 576 notifyGroupOfTask(c, wi, mygroup, epa); 578 } 579 else 580 { 581 archived = doState(c, wi, WFSTATE_ARCHIVE, newowner); 583 } 584 585 break; 586 587 case WFSTATE_STEP3: 588 589 deleteTasks(c, wi); 592 wi.setOwner(newowner); 593 594 break; 595 596 case WFSTATE_ARCHIVE: 597 598 try 600 { 601 deleteTasks(c, wi); 603 604 mycollection = wi.getCollection(); 605 606 Item myitem = archive(c, wi); 607 608 notifyOfArchive(c, myitem, mycollection); 610 archived = true; 611 } 612 catch (IOException e) 613 { 614 throw e; 616 } 617 catch (SQLException e) 618 { 619 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 641 private static Item archive(Context c, WorkflowItem wfi) 642 throws SQLException , IOException , AuthorizeException 643 { 644 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.info(LogManager.getHeader(c, "install_item", "workflow_id=" 656 + wfi.getID() + ", item_id=" + item.getID() + "handle=FIXME")); 657 658 return item; 659 } 660 661 664 private static void notifyOfArchive(Context c, Item i, Collection coll) 665 throws SQLException , IOException 666 { 667 try 668 { 669 String handle = HandleManager.findHandle(c, i); 671 672 DCValue[] titles = i.getDC("title", null, Item.ANY); 674 String title = I18N.message("untitled", WorkflowManager.class); 675 676 if (titles.length > 0) 677 { 678 title = titles[0].value; 679 } 680 681 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 e) 695 { 696 log.warn(LogManager.getHeader(c, "notifyOfArchive", 697 "cannot email user" + " item_id=" + i.getID())); 698 } 699 } 700 701 711 private static WorkspaceItem returnToWorkspace(Context c, WorkflowItem wfi) 712 throws SQLException , IOException , AuthorizeException 713 { 714 Item myitem = wfi.getItem(); 715 Collection mycollection = wfi.getCollection(); 716 717 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 myitem.removeLicenses(); 735 736 log.info(LogManager.getHeader(c, "return_to_workspace", 738 "workflow_item_id=" + wfi.getID() + "workspace_item_id=" 739 + wi.getID())); 740 741 DatabaseManager.updateQuery(c, 743 "DELETE FROM WorkflowItem WHERE workflow_id=" + wfi.getID()); 744 745 return wi; 746 } 747 748 762 public static WorkspaceItem reject(Context c, WorkflowItem wi, EPerson e, 763 String rejection_message) throws SQLException , AuthorizeException, 764 IOException 765 { 766 deleteTasks(c, wi); 769 770 Item myitem = wi.getItem(); 772 773 String now = DCDate.getCurrent().toString(); 775 776 String usersName = getEPersonName(e); 778 779 String provDescription = "Rejected by " + usersName + ", reason: " 781 + rejection_message + " on " + now + " (GMT) "; 782 783 myitem.addDC("description", "provenance", "en", provDescription); 785 myitem.update(); 786 787 WorkspaceItem wsi = returnToWorkspace(c, wi); 789 790 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 private static void createTasks(Context c, WorkflowItem wi, EPerson[] epa) 804 throws SQLException 805 { 806 for (int i = 0; i < epa.length; i++) 808 { 809 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 static void deleteTasks(Context c, WorkflowItem wi) throws SQLException 820 { 821 String 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 , IOException 828 { 829 Integer myID = new Integer (wi.getItem().getID()); 833 834 if (noEMail.containsKey(myID)) 835 { 836 noEMail.remove(myID); 838 } 839 else 840 { 841 try 842 { 843 String title = getItemTitle(wi); 845 846 String submitter = getSubmitterName(wi); 848 849 Collection coll = wi.getCollection(); 851 852 String 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 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 899 private static void emailRecipients(Context c, EPerson[] epa, Email email) 900 throws SQLException , MessagingException 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 getMyDSpaceLink() 911 { 912 return ConfigurationManager.getProperty("dspace.url") + "/mydspace"; 913 } 914 915 private static void notifyOfReject(Context c, WorkflowItem wi, EPerson e, 916 String reason) 917 { 918 try 919 { 920 String title = getItemTitle(wi); 922 923 Collection coll = wi.getCollection(); 925 926 String 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 ex) 941 { 942 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 private static EPerson getSubmitterEPerson(WorkflowItem wi) 952 throws SQLException 953 { 954 EPerson e = wi.getSubmitter(); 955 956 return e; 957 } 958 959 964 public static String getItemTitle(WorkflowItem wi) throws SQLException 965 { 966 Item myitem = wi.getItem(); 967 DCValue[] titles = myitem.getDC("title", null, Item.ANY); 968 969 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 985 public static String getSubmitterName(WorkflowItem wi) throws SQLException 986 { 987 EPerson e = wi.getSubmitter(); 988 989 return getEPersonName(e); 990 } 991 992 private static String getEPersonName(EPerson e) throws SQLException 993 { 994 String submitter = e.getFullName(); 995 996 submitter = submitter + "(" + e.getEmail() + ")"; 997 998 return submitter; 999 } 1000 1001 private static void recordApproval(Context c, WorkflowItem wi, EPerson e) 1003 throws SQLException , IOException , AuthorizeException 1004 { 1005 Item item = wi.getItem(); 1006 1007 String usersName = getEPersonName(e); 1009 1010 String now = DCDate.getCurrent().toString(); 1012 1013 String provDescription = "Approved for entry into archive by " 1015 + usersName + " on " + now + " (GMT) "; 1016 1017 provDescription += InstallItem.getBitstreamProvenanceMessage(item); 1019 1020 item.addDC("description", "provenance", "en", provDescription); 1022 item.update(); 1023 } 1024 1025 private static void recordStart(Context c, Item myitem) 1027 throws SQLException , IOException , AuthorizeException 1028 { 1029 Bitstream[] bitstreams = myitem.getNonInternalBitstreams(); 1031 1032 DCDate now = DCDate.getCurrent(); 1034 1035 String 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 { 1047 provmessage = "Submitted by unknown (probably automated) on" 1048 + now.toString() + "\n"; 1049 } 1050 1051 provmessage += InstallItem.getBitstreamProvenanceMessage(myitem); 1053 1054 myitem.addDC("description", "provenance", "en", provmessage); 1056 myitem.update(); 1057 } 1058} 1059 | Popular Tags |