/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.administer; import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.UUID; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; import org.apache.commons.collections.CollectionUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Community; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; /** * A command-line tool for setting/removing community/sub-community * relationships. Takes community DB Id or handle arguments as inputs. * * @author rrodgers * @version $Revision$ */ public class CommunityFiliator { protected CommunityService communityService; protected HandleService handleService; public CommunityFiliator() { communityService = ContentServiceFactory.getInstance().getCommunityService(); handleService = HandleServiceFactory.getInstance().getHandleService(); } /** * * @param argv the command line arguments given * @throws Exception if error */ public static void main(String[] argv) throws Exception { // create an options object and populate it CommandLineParser parser = new PosixParser(); Options options = new Options(); options.addOption("s", "set", false, "set a parent/child relationship"); options.addOption("r", "remove", false, "remove a parent/child relationship"); options.addOption("p", "parent", true, "parent community (handle or database ID)"); options.addOption("c", "child", true, "child community (handle or databaseID)"); options.addOption("h", "help", false, "help"); CommandLine line = parser.parse(options, argv); String command = null; // set or remove String parentID = null; String childID = null; if (line.hasOption('h')) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("CommunityFiliator\n", options); System.out .println("\nestablish a relationship: CommunityFiliator -s -p parentID -c childID"); System.out .println("remove a relationship: CommunityFiliator -r -p parentID -c childID"); System.exit(0); } if (line.hasOption('s')) { command = "set"; } if (line.hasOption('r')) { command = "remove"; } if (line.hasOption('p')) // parent { parentID = line.getOptionValue('p'); } if (line.hasOption('c')) // child { childID = line.getOptionValue('c'); } // now validate // must have a command set if (command == null) { System.out .println("Error - must run with either set or remove (run with -h flag for details)"); System.exit(1); } if ("set".equals(command) || "remove".equals(command)) { if (parentID == null) { System.out.println("Error - a parentID must be specified (run with -h flag for details)"); System.exit(1); } if (childID == null) { System.out.println("Error - a childID must be specified (run with -h flag for details)"); System.exit(1); } } CommunityFiliator filiator = new CommunityFiliator(); Context c = new Context(); // we are superuser! c.turnOffAuthorisationSystem(); try { // validate and resolve the parent and child IDs into commmunities Community parent = filiator.resolveCommunity(c, parentID); Community child = filiator.resolveCommunity(c, childID); if (parent == null) { System.out.println("Error, parent community cannot be found: " + parentID); System.exit(1); } if (child == null) { System.out.println("Error, child community cannot be found: " + childID); System.exit(1); } if ("set".equals(command)) { filiator.filiate(c, parent, child); } else { filiator.defiliate(c, parent, child); } } catch (SQLException sqlE) { System.out.println("Error - SQL exception: " + sqlE.toString()); } catch (AuthorizeException authE) { System.out.println("Error - Authorize exception: " + authE.toString()); } catch (IOException ioE) { System.out.println("Error - IO exception: " + ioE.toString()); } } /** * * @param c context * @param parent parent Community * @param child child community * @throws SQLException if database error * @throws AuthorizeException if authorize error * @throws IOException if IO error */ public void filiate(Context c, Community parent, Community child) throws SQLException, AuthorizeException, IOException { // check that a valid filiation would be established // first test - proposed child must currently be an orphan (i.e. // top-level) Community childDad = CollectionUtils.isNotEmpty(child.getParentCommunities()) ? child.getParentCommunities().iterator().next() : null; if (childDad != null) { System.out.println("Error, child community: " + child.getID() + " already a child of: " + childDad.getID()); System.exit(1); } // second test - circularity: parent's parents can't include proposed // child List<Community> parentDads = parent.getParentCommunities(); for (int i = 0; i < parentDads.size(); i++) { if (parentDads.get(i).getID().equals(child.getID())) { System.out .println("Error, circular parentage - child is parent of parent"); System.exit(1); } } // everthing's OK communityService.addSubcommunity(c, parent, child); // complete the pending transaction c.complete(); System.out.println("Filiation complete. Community: '" + parent.getID() + "' is parent of community: '" + child.getID() + "'"); } /** * * @param c context * @param parent parent Community * @param child child community * @throws SQLException if database error * @throws AuthorizeException if authorize error * @throws IOException if IO error */ public void defiliate(Context c, Community parent, Community child) throws SQLException, AuthorizeException, IOException { // verify that child is indeed a child of parent List<Community> parentKids = parent.getSubcommunities(); boolean isChild = false; for (int i = 0; i < parentKids.size(); i++) { if (parentKids.get(i).getID().equals(child.getID())) { isChild = true; break; } } if (!isChild) { System.out .println("Error, child community not a child of parent community"); System.exit(1); } // OK remove the mappings - but leave the community, which will become // top-level child.getParentCommunities().remove(parent); parent.getSubcommunities().remove(child); communityService.update(c, child); communityService.update(c, parent); // complete the pending transaction c.complete(); System.out.println("Defiliation complete. Community: '" + child.getID() + "' is no longer a child of community: '" + parent.getID() + "'"); } /** * Find a community by ID * @param c context * @param communityID community ID * @return Community object * @throws SQLException if database error */ protected Community resolveCommunity(Context c, String communityID) throws SQLException { Community community = null; if (communityID.indexOf('/') != -1) { // has a / must be a handle community = (Community) handleService.resolveToObject(c, communityID); // ensure it's a community if ((community == null) || (community.getType() != Constants.COMMUNITY)) { community = null; } } else { community = communityService.find(c, UUID.fromString(communityID)); } return community; } }