001: /*
002: * Community.java
003: *
004: * Version: $Revision: 2339 $
005: *
006: * Date: $Date: 2007-11-12 17:39:13 -0600 (Mon, 12 Nov 2007) $
007: *
008: * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
009: * Institute of Technology. All rights reserved.
010: *
011: * Redistribution and use in source and binary forms, with or without
012: * modification, are permitted provided that the following conditions are
013: * met:
014: *
015: * - Redistributions of source code must retain the above copyright
016: * notice, this list of conditions and the following disclaimer.
017: *
018: * - Redistributions in binary form must reproduce the above copyright
019: * notice, this list of conditions and the following disclaimer in the
020: * documentation and/or other materials provided with the distribution.
021: *
022: * - Neither the name of the Hewlett-Packard Company nor the name of the
023: * Massachusetts Institute of Technology nor the names of their
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038: * DAMAGE.
039: */
040: package org.dspace.content;
041:
042: import java.io.IOException;
043: import java.io.InputStream;
044: import java.sql.SQLException;
045: import java.util.ArrayList;
046: import java.util.List;
047: import java.util.MissingResourceException;
048:
049: import org.apache.log4j.Logger;
050: import org.dspace.authorize.AuthorizeException;
051: import org.dspace.authorize.AuthorizeManager;
052: import org.dspace.authorize.ResourcePolicy;
053: import org.dspace.browse.ItemCounter;
054: import org.dspace.browse.ItemCountException;
055: import org.dspace.core.Constants;
056: import org.dspace.core.Context;
057: import org.dspace.core.I18nUtil;
058: import org.dspace.core.LogManager;
059: import org.dspace.eperson.Group;
060: import org.dspace.event.Event;
061: import org.dspace.handle.HandleManager;
062: import org.dspace.storage.rdbms.DatabaseManager;
063: import org.dspace.storage.rdbms.TableRow;
064: import org.dspace.storage.rdbms.TableRowIterator;
065:
066: /**
067: * Class representing a community
068: * <P>
069: * The community's metadata (name, introductory text etc.) is loaded into'
070: * memory. Changes to this metadata are only reflected in the database after
071: * <code>update</code> is called.
072: *
073: * @author Robert Tansley
074: * @version $Revision: 2339 $
075: */
076: public class Community extends DSpaceObject {
077: /** log4j category */
078: private static Logger log = Logger.getLogger(Community.class);
079:
080: /** Our context */
081: private Context ourContext;
082:
083: /** The table row corresponding to this item */
084: private TableRow communityRow;
085:
086: /** The logo bitstream */
087: private Bitstream logo;
088:
089: /** Handle, if any */
090: private String handle;
091:
092: /** Flag set when data is modified, for events */
093: private boolean modified;
094:
095: /** Flag set when metadata is modified, for events */
096: private boolean modifiedMetadata;
097:
098: /**
099: * Construct a community object from a database row.
100: *
101: * @param context
102: * the context this object exists in
103: * @param row
104: * the corresponding row in the table
105: */
106: Community(Context context, TableRow row) throws SQLException {
107: ourContext = context;
108: communityRow = row;
109:
110: // Get the logo bitstream
111: if (communityRow.isColumnNull("logo_bitstream_id")) {
112: logo = null;
113: } else {
114: logo = Bitstream.find(ourContext, communityRow
115: .getIntColumn("logo_bitstream_id"));
116: }
117:
118: // Get our Handle if any
119: handle = HandleManager.findHandle(context, this );
120:
121: // Cache ourselves
122: context.cache(this , row.getIntColumn("community_id"));
123:
124: modified = modifiedMetadata = false;
125: clearDetails();
126: }
127:
128: /**
129: * Get a community from the database. Loads in the metadata
130: *
131: * @param context
132: * DSpace context object
133: * @param id
134: * ID of the community
135: *
136: * @return the community, or null if the ID is invalid.
137: */
138: public static Community find(Context context, int id)
139: throws SQLException {
140: // First check the cache
141: Community fromCache = (Community) context.fromCache(
142: Community.class, id);
143:
144: if (fromCache != null) {
145: return fromCache;
146: }
147:
148: TableRow row = DatabaseManager.find(context, "community", id);
149:
150: if (row == null) {
151: if (log.isDebugEnabled()) {
152: log.debug(LogManager.getHeader(context,
153: "find_community", "not_found,community_id="
154: + id));
155: }
156:
157: return null;
158: } else {
159: if (log.isDebugEnabled()) {
160: log.debug(LogManager.getHeader(context,
161: "find_community", "community_id=" + id));
162: }
163:
164: return new Community(context, row);
165: }
166: }
167:
168: /**
169: * Create a new community, with a new ID.
170: *
171: * @param context
172: * DSpace context object
173: *
174: * @return the newly created community
175: */
176: public static Community create(Community parent, Context context)
177: throws SQLException, AuthorizeException {
178: // Only administrators and adders can create communities
179: if (!(AuthorizeManager.isAdmin(context) || AuthorizeManager
180: .authorizeActionBoolean(context, parent, Constants.ADD))) {
181: throw new AuthorizeException(
182: "Only administrators can create communities");
183: }
184:
185: TableRow row = DatabaseManager.create(context, "community");
186: Community c = new Community(context, row);
187: c.handle = HandleManager.createHandle(context, c);
188:
189: // create the default authorization policy for communities
190: // of 'anonymous' READ
191: Group anonymousGroup = Group.find(context, 0);
192:
193: ResourcePolicy myPolicy = ResourcePolicy.create(context);
194: myPolicy.setResource(c);
195: myPolicy.setAction(Constants.READ);
196: myPolicy.setGroup(anonymousGroup);
197: myPolicy.update();
198:
199: context.addEvent(new Event(Event.CREATE, Constants.COMMUNITY, c
200: .getID(), c.handle));
201:
202: // if creating a top-level Community, simulate an ADD event at the Site.
203: if (parent == null)
204: context.addEvent(new Event(Event.ADD, Constants.SITE,
205: Site.SITE_ID, Constants.COMMUNITY, c.getID(),
206: c.handle));
207:
208: log.info(LogManager.getHeader(context, "create_community",
209: "community_id=" + row.getIntColumn("community_id"))
210: + ",handle=" + c.handle);
211:
212: return c;
213: }
214:
215: /**
216: * Get a list of all communities in the system. These are alphabetically
217: * sorted by community name.
218: *
219: * @param context
220: * DSpace context object
221: *
222: * @return the communities in the system
223: */
224: public static Community[] findAll(Context context)
225: throws SQLException {
226: TableRowIterator tri = DatabaseManager.queryTable(context,
227: "community", "SELECT * FROM community ORDER BY name");
228:
229: List<Community> communities = new ArrayList<Community>();
230:
231: while (tri.hasNext()) {
232: TableRow row = tri.next();
233:
234: // First check the cache
235: Community fromCache = (Community) context.fromCache(
236: Community.class, row.getIntColumn("community_id"));
237:
238: if (fromCache != null) {
239: communities.add(fromCache);
240: } else {
241: communities.add(new Community(context, row));
242: }
243: }
244: // close the TableRowIterator to free up resources
245: tri.close();
246:
247: Community[] communityArray = new Community[communities.size()];
248: communityArray = (Community[]) communities
249: .toArray(communityArray);
250:
251: return communityArray;
252: }
253:
254: /**
255: * Get a list of all top-level communities in the system. These are
256: * alphabetically sorted by community name. A top-level community is one
257: * without a parent community.
258: *
259: * @param context
260: * DSpace context object
261: *
262: * @return the top-level communities in the system
263: */
264: public static Community[] findAllTop(Context context)
265: throws SQLException {
266: // get all communities that are not children
267: TableRowIterator tri = DatabaseManager
268: .queryTable(
269: context,
270: "community",
271: "SELECT * FROM community WHERE NOT community_id IN "
272: + "(SELECT child_comm_id FROM community2community) "
273: + "ORDER BY name");
274:
275: List<Community> topCommunities = new ArrayList<Community>();
276:
277: while (tri.hasNext()) {
278: TableRow row = tri.next();
279:
280: // First check the cache
281: Community fromCache = (Community) context.fromCache(
282: Community.class, row.getIntColumn("community_id"));
283:
284: if (fromCache != null) {
285: topCommunities.add(fromCache);
286: } else {
287: topCommunities.add(new Community(context, row));
288: }
289: }
290: // close the TableRowIterator to free up resources
291: tri.close();
292:
293: Community[] communityArray = new Community[topCommunities
294: .size()];
295: communityArray = (Community[]) topCommunities
296: .toArray(communityArray);
297:
298: return communityArray;
299: }
300:
301: /**
302: * Get the internal ID of this collection
303: *
304: * @return the internal identifier
305: */
306: public int getID() {
307: return communityRow.getIntColumn("community_id");
308: }
309:
310: /**
311: * @see org.dspace.content.DSpaceObject#getHandle()
312: */
313: public String getHandle() {
314: if (handle == null) {
315: try {
316: handle = HandleManager
317: .findHandle(this .ourContext, this );
318: } catch (SQLException e) {
319: // TODO Auto-generated catch block
320: //e.printStackTrace();
321: }
322: }
323: return handle;
324: }
325:
326: /**
327: * Get the value of a metadata field
328: *
329: * @param field
330: * the name of the metadata field to get
331: *
332: * @return the value of the metadata field
333: *
334: * @exception IllegalArgumentException
335: * if the requested metadata field doesn't exist
336: */
337: public String getMetadata(String field) {
338: String metadata = communityRow.getStringColumn(field);
339: return (metadata == null) ? "" : metadata;
340: }
341:
342: /**
343: * Set a metadata value
344: *
345: * @param field
346: * the name of the metadata field to get
347: * @param value
348: * value to set the field to
349: *
350: * @exception IllegalArgumentException
351: * if the requested metadata field doesn't exist
352: * @exception MissingResourceException
353: */
354: public void setMetadata(String field, String value)
355: throws MissingResourceException {
356: if ((field.trim()).equals("name") && (value.trim()).equals("")) {
357: try {
358: value = I18nUtil
359: .getMessage("org.dspace.workflow.WorkflowManager.untitled");
360: } catch (MissingResourceException e) {
361: value = "Untitled";
362: }
363: }
364: communityRow.setColumn(field, value);
365: modifiedMetadata = true;
366: addDetails(field);
367: }
368:
369: public String getName() {
370: return getMetadata("name");
371: }
372:
373: /**
374: * Get the logo for the community. <code>null</code> is return if the
375: * community does not have a logo.
376: *
377: * @return the logo of the community, or <code>null</code>
378: */
379: public Bitstream getLogo() {
380: return logo;
381: }
382:
383: /**
384: * Give the community a logo. Passing in <code>null</code> removes any
385: * existing logo. You will need to set the format of the new logo bitstream
386: * before it will work, for example to "JPEG". Note that
387: * <code>update(/code> will need to be called for the change to take
388: * effect. Setting a logo and not calling <code>update</code> later may
389: * result in a previous logo lying around as an "orphaned" bitstream.
390: *
391: * @param is the stream to use as the new logo
392: *
393: * @return the new logo bitstream, or <code>null</code> if there is no
394: * logo (<code>null</code> was passed in)
395: */
396: public Bitstream setLogo(InputStream is) throws AuthorizeException,
397: IOException, SQLException {
398: // Check authorisation
399: // authorized to remove the logo when DELETE rights
400: // authorized when canEdit
401: if (!((is == null) && AuthorizeManager.authorizeActionBoolean(
402: ourContext, this , Constants.DELETE))) {
403: canEdit();
404: }
405:
406: // First, delete any existing logo
407: if (logo != null) {
408: log.info(LogManager.getHeader(ourContext, "remove_logo",
409: "community_id=" + getID()));
410: communityRow.setColumnNull("logo_bitstream_id");
411: logo.delete();
412: logo = null;
413: }
414:
415: if (is != null) {
416: Bitstream newLogo = Bitstream.create(ourContext, is);
417: communityRow
418: .setColumn("logo_bitstream_id", newLogo.getID());
419: logo = newLogo;
420:
421: // now create policy for logo bitstream
422: // to match our READ policy
423: List policies = AuthorizeManager.getPoliciesActionFilter(
424: ourContext, this , Constants.READ);
425: AuthorizeManager.addPolicies(ourContext, policies, newLogo);
426:
427: log.info(LogManager.getHeader(ourContext, "set_logo",
428: "community_id=" + getID() + "logo_bitstream_id="
429: + newLogo.getID()));
430: }
431:
432: modified = true;
433: return logo;
434: }
435:
436: /**
437: * Update the community metadata (including logo) to the database.
438: */
439: public void update() throws SQLException, IOException,
440: AuthorizeException {
441: // Check authorisation
442: canEdit();
443:
444: log.info(LogManager.getHeader(ourContext, "update_community",
445: "community_id=" + getID()));
446:
447: DatabaseManager.update(ourContext, communityRow);
448:
449: if (modified) {
450: ourContext.addEvent(new Event(Event.MODIFY,
451: Constants.COMMUNITY, getID(), null));
452: modified = false;
453: }
454: if (modifiedMetadata) {
455: ourContext.addEvent(new Event(Event.MODIFY_METADATA,
456: Constants.COMMUNITY, getID(), getDetails()));
457: modifiedMetadata = false;
458: clearDetails();
459: }
460: }
461:
462: /**
463: * Get the collections in this community. Throws an SQLException because
464: * creating a community object won't load in all collections.
465: *
466: * @return array of Collection objects
467: */
468: public Collection[] getCollections() throws SQLException {
469: List<Collection> collections = new ArrayList<Collection>();
470:
471: // Get the table rows
472: TableRowIterator tri = DatabaseManager
473: .queryTable(
474: ourContext,
475: "collection",
476: "SELECT collection.* FROM collection, community2collection WHERE "
477: + "community2collection.collection_id=collection.collection_id "
478: + "AND community2collection.community_id= ? ORDER BY collection.name",
479: getID());
480:
481: // Make Collection objects
482: while (tri.hasNext()) {
483: TableRow row = tri.next();
484:
485: // First check the cache
486: Collection fromCache = (Collection) ourContext
487: .fromCache(Collection.class, row
488: .getIntColumn("collection_id"));
489:
490: if (fromCache != null) {
491: collections.add(fromCache);
492: } else {
493: collections.add(new Collection(ourContext, row));
494: }
495: }
496: // close the TableRowIterator to free up resources
497: tri.close();
498:
499: // Put them in an array
500: Collection[] collectionArray = new Collection[collections
501: .size()];
502: collectionArray = (Collection[]) collections
503: .toArray(collectionArray);
504:
505: return collectionArray;
506: }
507:
508: /**
509: * Get the immediate sub-communities of this community. Throws an
510: * SQLException because creating a community object won't load in all
511: * collections.
512: *
513: * @return array of Community objects
514: */
515: public Community[] getSubcommunities() throws SQLException {
516: List<Community> subcommunities = new ArrayList<Community>();
517:
518: // Get the table rows
519: TableRowIterator tri = DatabaseManager
520: .queryTable(
521: ourContext,
522: "community",
523: "SELECT community.* FROM community, community2community WHERE "
524: + "community2community.child_comm_id=community.community_id "
525: + "AND community2community.parent_comm_id= ? ORDER BY community.name",
526: getID());
527:
528: // Make Community objects
529: while (tri.hasNext()) {
530: TableRow row = tri.next();
531:
532: // First check the cache
533: Community fromCache = (Community) ourContext.fromCache(
534: Community.class, row.getIntColumn("community_id"));
535:
536: if (fromCache != null) {
537: subcommunities.add(fromCache);
538: } else {
539: subcommunities.add(new Community(ourContext, row));
540: }
541: }
542: // close the TableRowIterator to free up resources
543: tri.close();
544:
545: // Put them in an array
546: Community[] communityArray = new Community[subcommunities
547: .size()];
548: communityArray = (Community[]) subcommunities
549: .toArray(communityArray);
550:
551: return communityArray;
552: }
553:
554: /**
555: * Return the parent community of this community, or null if the community
556: * is top-level
557: *
558: * @return the immediate parent community, or null if top-level
559: */
560: public Community getParentCommunity() throws SQLException {
561: Community parentCommunity = null;
562:
563: // Get the table rows
564: TableRowIterator tri = DatabaseManager
565: .queryTable(
566: ourContext,
567: "community",
568: "SELECT community.* FROM community, community2community WHERE "
569: + "community2community.parent_comm_id=community.community_id "
570: + "AND community2community.child_comm_id= ? ",
571: getID());
572:
573: // Make Community object
574: if (tri.hasNext()) {
575: TableRow row = tri.next();
576:
577: // First check the cache
578: Community fromCache = (Community) ourContext.fromCache(
579: Community.class, row.getIntColumn("community_id"));
580:
581: if (fromCache != null) {
582: parentCommunity = fromCache;
583: } else {
584: parentCommunity = new Community(ourContext, row);
585: }
586: }
587: // close the TableRowIterator to free up resources
588: tri.close();
589:
590: return parentCommunity;
591: }
592:
593: /**
594: * Return an array of parent communities of this community, in ascending
595: * order. If community is top-level, return an empty array.
596: *
597: * @return an array of parent communities, empty if top-level
598: */
599: public Community[] getAllParents() throws SQLException {
600: List<Community> parentList = new ArrayList<Community>();
601: Community parent = getParentCommunity();
602:
603: while (parent != null) {
604: parentList.add(parent);
605: parent = parent.getParentCommunity();
606: }
607:
608: // Put them in an array
609: Community[] communityArray = new Community[parentList.size()];
610: communityArray = (Community[]) parentList
611: .toArray(communityArray);
612:
613: return communityArray;
614: }
615:
616: /**
617: * Create a new collection within this community. The collection is created
618: * without any workflow groups or default submitter group.
619: *
620: * @return the new collection
621: */
622: public Collection createCollection() throws SQLException,
623: AuthorizeException {
624: // Check authorisation
625: AuthorizeManager.authorizeAction(ourContext, this ,
626: Constants.ADD);
627:
628: Collection c = Collection.create(ourContext);
629: addCollection(c);
630:
631: return c;
632: }
633:
634: /**
635: * Add an exisiting collection to the community
636: *
637: * @param c
638: * collection to add
639: */
640: public void addCollection(Collection c) throws SQLException,
641: AuthorizeException {
642: // Check authorisation
643: AuthorizeManager.authorizeAction(ourContext, this ,
644: Constants.ADD);
645:
646: log.info(LogManager.getHeader(ourContext, "add_collection",
647: "community_id=" + getID() + ",collection_id="
648: + c.getID()));
649:
650: // Find out if mapping exists
651: TableRowIterator tri = DatabaseManager.queryTable(ourContext,
652: "community2collection",
653: "SELECT * FROM community2collection WHERE "
654: + "community_id= ? AND collection_id= ? ",
655: getID(), c.getID());
656:
657: if (!tri.hasNext()) {
658: // No existing mapping, so add one
659: TableRow mappingRow = DatabaseManager.create(ourContext,
660: "community2collection");
661:
662: mappingRow.setColumn("community_id", getID());
663: mappingRow.setColumn("collection_id", c.getID());
664:
665: ourContext.addEvent(new Event(Event.ADD,
666: Constants.COMMUNITY, getID(), Constants.COLLECTION,
667: c.getID(), c.getHandle()));
668:
669: DatabaseManager.update(ourContext, mappingRow);
670: }
671: // close the TableRowIterator to free up resources
672: tri.close();
673: }
674:
675: /**
676: * Create a new sub-community within this community.
677: *
678: * @return the new community
679: */
680: public Community createSubcommunity() throws SQLException,
681: AuthorizeException {
682: // Check authorisation
683: AuthorizeManager.authorizeAction(ourContext, this ,
684: Constants.ADD);
685:
686: Community c = create(this , ourContext);
687: addSubcommunity(c);
688:
689: return c;
690: }
691:
692: /**
693: * Add an exisiting community as a subcommunity to the community
694: *
695: * @param c
696: * subcommunity to add
697: */
698: public void addSubcommunity(Community c) throws SQLException,
699: AuthorizeException {
700: // Check authorisation
701: AuthorizeManager.authorizeAction(ourContext, this ,
702: Constants.ADD);
703:
704: log.info(LogManager.getHeader(ourContext, "add_subcommunity",
705: "parent_comm_id=" + getID() + ",child_comm_id="
706: + c.getID()));
707:
708: // Find out if mapping exists
709: TableRowIterator tri = DatabaseManager.queryTable(ourContext,
710: "community2community",
711: "SELECT * FROM community2community WHERE parent_comm_id= ? "
712: + "AND child_comm_id= ? ", getID(), c.getID());
713:
714: if (!tri.hasNext()) {
715: // No existing mapping, so add one
716: TableRow mappingRow = DatabaseManager.create(ourContext,
717: "community2community");
718:
719: mappingRow.setColumn("parent_comm_id", getID());
720: mappingRow.setColumn("child_comm_id", c.getID());
721:
722: ourContext.addEvent(new Event(Event.ADD,
723: Constants.COMMUNITY, getID(), Constants.COMMUNITY,
724: c.getID(), c.getHandle()));
725:
726: DatabaseManager.update(ourContext, mappingRow);
727: }
728: // close the TableRowIterator to free up resources
729: tri.close();
730: }
731:
732: /**
733: * Remove a collection. Any items then orphaned are deleted.
734: *
735: * @param c
736: * collection to remove
737: */
738: public void removeCollection(Collection c) throws SQLException,
739: AuthorizeException, IOException {
740: // Check authorisation
741: AuthorizeManager.authorizeAction(ourContext, this ,
742: Constants.REMOVE);
743:
744: log.info(LogManager.getHeader(ourContext, "remove_collection",
745: "community_id=" + getID() + ",collection_id="
746: + c.getID()));
747:
748: // Remove any mappings
749: DatabaseManager.updateQuery(ourContext,
750: "DELETE FROM community2collection WHERE community_id= ? "
751: + "AND collection_id= ? ", getID(), c.getID());
752:
753: ourContext.addEvent(new Event(Event.REMOVE,
754: Constants.COMMUNITY, getID(), Constants.COLLECTION, c
755: .getID(), c.getHandle()));
756:
757: // Is the community an orphan?
758: TableRowIterator tri = DatabaseManager
759: .query(
760: ourContext,
761: "SELECT * FROM community2collection WHERE collection_id= ? ",
762: c.getID());
763:
764: if (!tri.hasNext()) {
765: //make the right to remove the collection explicit because the
766: // implicit relation
767: //has been removed. This only has to concern the currentUser
768: // because
769: //he started the removal process and he will end it too.
770: //also add right to remove from the collection to remove it's
771: // items.
772: AuthorizeManager.addPolicy(ourContext, c, Constants.DELETE,
773: ourContext.getCurrentUser());
774: AuthorizeManager.addPolicy(ourContext, c, Constants.REMOVE,
775: ourContext.getCurrentUser());
776:
777: // Orphan; delete it
778: c.delete();
779: }
780: // close the TableRowIterator to free up resources
781: tri.close();
782: }
783:
784: /**
785: * Remove a subcommunity. Any substructure then orphaned is deleted.
786: *
787: * @param c
788: * subcommunity to remove
789: */
790: public void removeSubcommunity(Community c) throws SQLException,
791: AuthorizeException, IOException {
792: // Check authorisation
793: AuthorizeManager.authorizeAction(ourContext, this ,
794: Constants.REMOVE);
795:
796: log.info(LogManager.getHeader(ourContext,
797: "remove_subcommunity", "parent_comm_id=" + getID()
798: + ",child_comm_id=" + c.getID()));
799:
800: // Remove any mappings
801: DatabaseManager.updateQuery(ourContext,
802: "DELETE FROM community2community WHERE parent_comm_id= ? "
803: + " AND child_comm_id= ? ", getID(), c.getID());
804:
805: ourContext.addEvent(new Event(Event.REMOVE,
806: Constants.COMMUNITY, getID(), Constants.COMMUNITY, c
807: .getID(), c.getHandle()));
808:
809: // Is the subcommunity an orphan?
810: TableRowIterator tri = DatabaseManager
811: .query(
812: ourContext,
813: "SELECT * FROM community2community WHERE child_comm_id= ? ",
814: c.getID());
815:
816: if (!tri.hasNext()) {
817: //make the right to remove the sub explicit because the implicit
818: // relation
819: //has been removed. This only has to concern the currentUser
820: // because
821: //he started the removal process and he will end it too.
822: //also add right to remove from the subcommunity to remove it's
823: // children.
824: AuthorizeManager.addPolicy(ourContext, c, Constants.DELETE,
825: ourContext.getCurrentUser());
826: AuthorizeManager.addPolicy(ourContext, c, Constants.REMOVE,
827: ourContext.getCurrentUser());
828:
829: // Orphan; delete it
830: c.delete();
831: }
832: // close the TableRowIterator to free up resources
833: tri.close();
834: }
835:
836: /**
837: * Delete the community, including the metadata and logo. Collections and
838: * subcommunities that are then orphans are deleted.
839: */
840: public void delete() throws SQLException, AuthorizeException,
841: IOException {
842: // Check authorisation
843: // FIXME: If this was a subcommunity, it is first removed from it's
844: // parent.
845: // This means the parentCommunity == null
846: // But since this is also the case for top-level communities, we would
847: // give everyone rights to remove the top-level communities.
848: // The same problem occurs in removing the logo
849: if (!AuthorizeManager.authorizeActionBoolean(ourContext,
850: getParentCommunity(), Constants.REMOVE)) {
851: AuthorizeManager.authorizeAction(ourContext, this ,
852: Constants.DELETE);
853: }
854:
855: // If not a top-level community, have parent remove me; this
856: // will call delete() after removing the linkage
857: Community parent = getParentCommunity();
858:
859: if (parent != null) {
860: parent.removeSubcommunity(this );
861:
862: return;
863: }
864:
865: log.info(LogManager.getHeader(ourContext, "delete_community",
866: "community_id=" + getID()));
867:
868: ourContext.addEvent(new Event(Event.DELETE,
869: Constants.COMMUNITY, getID(), getHandle()));
870:
871: // Remove from cache
872: ourContext.removeCached(this , getID());
873:
874: // Remove collections
875: Collection[] cols = getCollections();
876:
877: for (int i = 0; i < cols.length; i++) {
878: removeCollection(cols[i]);
879: }
880:
881: // Remove subcommunities
882: Community[] comms = getSubcommunities();
883:
884: for (int j = 0; j < comms.length; j++) {
885: removeSubcommunity(comms[j]);
886: }
887:
888: // Remove the logo
889: setLogo(null);
890:
891: // Remove all authorization policies
892: AuthorizeManager.removeAllPolicies(ourContext, this );
893:
894: // get rid of the content count cache if it exists
895: try {
896: ItemCounter ic = new ItemCounter(ourContext);
897: ic.remove(this );
898: } catch (ItemCountException e) {
899: // FIXME: upside down exception handling due to lack of good
900: // exception framework
901: throw new RuntimeException(e.getMessage(), e);
902: }
903:
904: // Delete community row
905: DatabaseManager.delete(ourContext, communityRow);
906: }
907:
908: /**
909: * Return <code>true</code> if <code>other</code> is the same Community
910: * as this object, <code>false</code> otherwise
911: *
912: * @param other
913: * object to compare to
914: *
915: * @return <code>true</code> if object passed in represents the same
916: * community as this object
917: */
918: public boolean equals(Object other) {
919: if (!(other instanceof Community)) {
920: return false;
921: }
922:
923: return (getID() == ((Community) other).getID());
924: }
925:
926: /**
927: * return type found in Constants
928: */
929: public int getType() {
930: return Constants.COMMUNITY;
931: }
932:
933: /**
934: * return TRUE if context's user can edit community, false otherwise
935: *
936: * @return boolean true = current user can edit community
937: */
938: public boolean canEditBoolean() throws java.sql.SQLException {
939: try {
940: canEdit();
941:
942: return true;
943: } catch (AuthorizeException e) {
944: return false;
945: }
946: }
947:
948: public void canEdit() throws AuthorizeException, SQLException {
949: Community[] parents = getAllParents();
950:
951: for (int i = 0; i < parents.length; i++) {
952: if (AuthorizeManager.authorizeActionBoolean(ourContext,
953: parents[i], Constants.WRITE)) {
954: return;
955: }
956:
957: if (AuthorizeManager.authorizeActionBoolean(ourContext,
958: parents[i], Constants.ADD)) {
959: return;
960: }
961: }
962:
963: AuthorizeManager.authorizeAction(ourContext, this ,
964: Constants.WRITE);
965: }
966:
967: /**
968: * counts items in this community
969: *
970: * @return total items
971: */
972: public int countItems() throws SQLException {
973: int total = 0;
974: // add collection counts
975: Collection[] cols = getCollections();
976: for (int i = 0; i < cols.length; i++) {
977: total += cols[i].countItems();
978: }
979: // add sub-community counts
980: Community[] comms = getSubcommunities();
981: for (int j = 0; j < comms.length; j++) {
982: total += comms[j].countItems();
983: }
984: return total;
985: }
986: }
|