001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019:
020: package org.openharmonise.dav.server.managers;
021:
022: import java.net.*;
023: import java.util.*;
024: import java.util.logging.*;
025:
026: import org.openharmonise.dav.server.apm.APMException;
027: import org.openharmonise.dav.server.utils.*;
028: import org.openharmonise.rm.*;
029: import org.openharmonise.rm.factory.*;
030: import org.openharmonise.rm.metadata.*;
031: import org.openharmonise.rm.resources.*;
032: import org.openharmonise.rm.resources.lifecycle.*;
033: import org.openharmonise.rm.resources.metadata.properties.*;
034: import org.openharmonise.rm.resources.users.User;
035:
036: import com.ibm.webdav.*;
037: import com.ibm.webdav.impl.ResourceImpl;
038: import com.ibm.webdav.protocol.http.*;
039:
040: /**
041: * Implementation of the <code>VersionedNamespaceManager</code> interface
042: * providing the Delta-V functionality on top of <code>NamespaceManager</code>.
043: *
044: * @author Michael Bell
045: * @version $Revision: 1.3 $
046: *
047: */
048: public class VersionedNamespaceManager extends
049: HarmoniseNamespaceManager implements
050: com.ibm.webdav.impl.VersionedNamespaceManager {
051:
052: static private Logger m_logger = Logger
053: .getLogger(VersionedNamespaceManager.class.getName());
054:
055: /**
056: *
057: */
058: public VersionedNamespaceManager() {
059: super ();
060: }
061:
062: /**
063: * @param resource
064: */
065: public VersionedNamespaceManager(ResourceImpl resource) {
066: super (resource);
067: }
068:
069: /**
070: * Checkin this resource, i.e. make live/approved
071: *
072: * @return
073: * @throws WebDAVException
074: */
075: public String checkin() throws WebDAVException {
076: String versionURL = null;
077:
078: try {
079: if (m_child.isPendingVersion() == false) {
080: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
081: "Resource needs to be checked out");
082: }
083:
084: addCreator();
085:
086: addPublicationDate();
087:
088: User usr = ((HarmoniseSessionManager) m_resource
089: .getUserAuthenticator()).getUser(m_resource);
090:
091: //ensure change status is allowed
092: if (m_auxillary != null
093: && m_auxillary.isChangeStatusValid(usr, m_child) == false) {
094:
095: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
096: "Object workflow not complete");
097:
098: }
099:
100: m_child = CommandWrapper.changeStatus(m_dsi, m_child, usr,
101: Status.APPROVED);
102:
103: versionURL = HarmoniseNameResolver.getVersionPath(m_child);
104:
105: if (m_auxillary != null) {
106: m_auxillary.changeStatus(usr, m_child,
107: Status.UNAPPROVED, Status.APPROVED);
108: }
109:
110: } catch (NameResolverException e) {
111: throw new WebDAVException(
112: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
113: .getLocalizedMessage());
114: } catch (DataAccessException e) {
115: throw new WebDAVException(
116: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
117: .getLocalizedMessage());
118: } catch (APMException e) {
119: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
120: throw new WebDAVException(
121: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
122: .getLocalizedMessage());
123: }
124: return versionURL;
125: }
126:
127: /**
128: * Adds a 'creator-displayname' property to this resource.
129: *
130: * @throws WebDAVException
131: */
132: private void addCreator() throws WebDAVException {
133:
134: try {
135: if (m_child.isPendingVersion() == true
136: && (m_child instanceof Property) == false) {
137:
138: Profile prof = m_child.getProfile();
139:
140: if (prof == null) {
141: prof = new Profile(m_dsi);
142: prof.setName("default");
143: m_child.setProfile(prof);
144: }
145:
146: Property creatorProp = PropertyFactory
147: .getPropertyFromName(
148: m_dsi,
149: VersionedPropertiesManager.TAG_CREATOR_DISPLAYNAME);
150:
151: if (prof.isValidProperty(creatorProp) == true) {
152:
153: prof.removeProperty(creatorProp);
154:
155: GeneralPropertyInstance propInst = new GeneralPropertyInstance(
156: m_dsi, creatorProp);
157:
158: User usr = ((HarmoniseSessionManager) m_resource
159: .getUserAuthenticator())
160: .getUser(m_resource);
161:
162: propInst.addValue(usr.getName());
163:
164: prof.addPropertyInstance(propInst);
165:
166: m_child = (AbstractChildObject) m_child.save();
167: }
168: }
169:
170: } catch (DataAccessException e) {
171: throw new WebDAVException(
172: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
173: .getLocalizedMessage());
174: } catch (HarmoniseFactoryException e) {
175: throw new WebDAVException(
176: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
177: .getLocalizedMessage());
178: } catch (ProfileException e) {
179: throw new WebDAVException(
180: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
181: .getLocalizedMessage());
182: } catch (InvalidPropertyValueException e) {
183: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN, e
184: .getLocalizedMessage());
185: } catch (EditException e) {
186: throw new WebDAVException(
187: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
188: .getLocalizedMessage());
189: } catch (InvalidProfileException e) {
190: throw new WebDAVException(
191: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
192: .getLocalizedMessage());
193: } catch (InvalidNameException e) {
194: throw new WebDAVException(
195: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
196: .getLocalizedMessage());
197: } catch (PopulateException e) {
198: throw new WebDAVException(
199: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
200: .getLocalizedMessage());
201: }
202: }
203:
204: /**
205: * Add START property.
206: */
207: private void addPublicationDate() throws WebDAVException {
208:
209: try {
210: if (m_child.isPendingVersion() == true
211: && (m_child instanceof AbstractParentObject) == false) {
212:
213: Profile prof = m_child.getProfile();
214:
215: if (prof == null) {
216: prof = new Profile(m_dsi);
217: prof.setName("default");
218: m_child.setProfile(prof);
219: }
220:
221: Property prop = PropertyFactory.getPropertyFromName(
222: m_dsi, HarmoniseNameResolver.START_PROP_NAME);
223:
224: if (prof.isValidProperty(prop) == true) {
225: GeneralPropertyInstance propInst = (GeneralPropertyInstance) prof
226: .getPropertyInstance(prop);
227:
228: if (propInst == null) {
229: propInst = (GeneralPropertyInstance) PropertyInstanceFactory
230: .getPropertyInstance(m_dsi, prop);
231: prof.addPropertyInstance(propInst);
232: }
233:
234: propInst.clearValues();
235:
236: Date date = new Date();
237:
238: propInst.addValue(date);
239:
240: m_child = (AbstractChildObject) m_child.save();
241: }
242:
243: }
244: } catch (InvalidPropertyInstanceException e) {
245: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN, e
246: .getLocalizedMessage());
247: } catch (DataAccessException e) {
248: throw new WebDAVException(
249: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
250: .getLocalizedMessage());
251: } catch (InvalidProfileException e) {
252: throw new WebDAVException(
253: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
254: .getLocalizedMessage());
255: } catch (HarmoniseFactoryException e) {
256: throw new WebDAVException(
257: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
258: .getLocalizedMessage());
259: } catch (ProfileException e) {
260: throw new WebDAVException(
261: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
262: .getLocalizedMessage());
263: } catch (InvalidPropertyValueException e) {
264: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN, e
265: .getLocalizedMessage());
266: } catch (EditException e) {
267: throw new WebDAVException(
268: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
269: .getLocalizedMessage());
270: } catch (InvalidNameException e) {
271: throw new WebDAVException(
272: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
273: .getLocalizedMessage());
274: } catch (PopulateException e) {
275: throw new WebDAVException(
276: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
277: .getLocalizedMessage());
278: }
279:
280: }
281:
282: /**
283: * Checkout this resource, i.e. create a new pending version.
284: *
285: * @throws WebDAVException
286: */
287: public void checkout() throws WebDAVException {
288: try {
289: if (m_child.isLiveVersion() == true) {
290: m_child = (AbstractChildObject) m_child
291: .createNewVersion();
292: } else if (m_child.isHistorical() == true) {
293: AbstractChildObject liveChild = (AbstractChildObject) m_child
294: .getLiveVersion();
295: if (liveChild != null
296: && liveChild.getPendingVersions().size() > 0) {
297: throw new WebDAVException(
298: WebDAVStatus.SC_FORBIDDEN,
299: "Can only have once checked out resource at a time");
300: }
301:
302: User usr = ((HarmoniseSessionManager) m_resource
303: .getUserAuthenticator()).getUser(m_resource);
304:
305: //first need to check that there isn't already a
306: //resource with the same name in the live collection
307: String sHistPath = m_child.getPath();
308:
309: AbstractParentObject parent = (AbstractParentObject) HarmoniseObjectFactory
310: .instantiateHarmoniseObject(m_dsi, m_child
311: .getParentObjectClassName(), sHistPath);
312: if (parent == null) {
313: m_logger.log(Level.WARNING,
314: "Unable to instantiate "
315: + m_child
316: .getParentObjectClassName()
317: + " in path " + sHistPath);
318: throw new WebDAVException(
319: WebDAVStatus.SC_INTERNAL_SERVER_ERROR,
320: "Missing Parent Object");
321: }
322: AbstractChildObject sameNameChild = parent
323: .getChildByName(m_child.getName());
324: if (sameNameChild == null
325: || sameNameChild.equals(m_child
326: .getLiveVersion())) {
327: //no child with name exists in live collection
328: //or the child that does exist is the current live version so reactivate
329: m_child = CommandWrapper.reactivate(m_dsi, m_child,
330: usr);
331: } else {
332: //child with same name exists in live collection
333: if (m_logger.isLoggable(Level.INFO)) {
334: m_logger
335: .logp(
336: Level.INFO,
337: VersionedNamespaceManager.class
338: .getName(),
339: "checkout",
340: "throwing PRECONDICTION_FAILED on checkout method (reactivate) - Resource "
341: + m_child.getName()
342: + " with same name already exists in live collecttion");
343: }
344: throw new WebDAVException(
345: WebDAVStatus.SC_PRECONDITION_FAILED,
346: "Resource with the same name exists in the live collection");
347: }
348:
349: } else if (m_child.isPendingVersion() == true) {
350: if (m_logger.isLoggable(Level.INFO)) {
351: m_logger.logp(Level.INFO,
352: VersionedNamespaceManager.class.getName(),
353: "checkout",
354: "throwing FORBIDDEN on checkout method - Resource "
355: + m_child.getName()
356: + " is already checked out");
357: }
358:
359: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
360: "Resource is already checked out");
361: }
362:
363: m_resource.getResponseContext().location(
364: HarmoniseNameResolver.getVersionPath(m_child));
365:
366: } catch (EditException e) {
367: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
368: throw new WebDAVException(
369: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
370: .getLocalizedMessage());
371: } catch (DataAccessException e) {
372: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
373: throw new WebDAVException(
374: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
375: .getLocalizedMessage());
376: } catch (NameResolverException e) {
377: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
378: throw new WebDAVException(
379: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
380: .getLocalizedMessage());
381: } catch (HarmoniseFactoryException e) {
382: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
383: throw new WebDAVException(
384: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
385: .getLocalizedMessage());
386: }
387: }
388:
389: /**
390: * Returns a list of allowed DeltaV methods for this resource.
391: *
392: * @return
393: */
394: public List getAllowedMethods() throws WebDAVException {
395: List allowedMethods = super .getAllowedMethods();
396:
397: if (m_child != null) {
398: if (HarmoniseNameResolver.isArchiveURL(m_resource.getURL()) == true
399: || (m_child != null && m_child.isHistorical())) {
400: try {
401: AbstractChildObject liveChild = (AbstractChildObject) m_child
402: .getLiveVersion();
403: if ((m_child instanceof AbstractParentObject) == false) {
404: if (liveChild == null
405: || liveChild.getPendingVersions()
406: .size() == 0) {
407: allowedMethods
408: .add(CheckOutMethod.METHOD_NAME);
409: }
410: }
411: } catch (DataAccessException e) {
412: throw new WebDAVException(
413: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
414: .getLocalizedMessage());
415: }
416: } else {
417: List versionMethods = new ArrayList();
418: try {
419: if (m_child.isPendingVersion() == true) {
420: if (m_child.getLiveVersion() == null) {
421: versionMethods
422: .add(VersionControlMethod.METHOD_NAME);
423: } else {
424: versionMethods
425: .add(CheckInMethod.METHOD_NAME);
426: versionMethods
427: .add(UncheckOutMethod.METHOD_NAME);
428: versionMethods
429: .add(ReportMethod.METHOD_NAME);
430: }
431:
432: } else {
433: if (m_child.isHistorical() == true) {
434: AbstractChildObject liveChild = (AbstractChildObject) m_child
435: .getLiveVersion();
436:
437: if (liveChild == null
438: || liveChild.getPendingVersions()
439: .size() == 0) {
440: versionMethods
441: .add(CheckOutMethod.METHOD_NAME);
442: }
443:
444: } else {
445: versionMethods
446: .add(CheckOutMethod.METHOD_NAME);
447: }
448:
449: versionMethods.add(ReportMethod.METHOD_NAME);
450: }
451: } catch (DataAccessException e) {
452: throw new WebDAVException(
453: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
454: .getLocalizedMessage());
455: }
456:
457: versionMethods = super
458: .filterAllowedMethods(versionMethods);
459:
460: allowedMethods.addAll(versionMethods);
461:
462: }
463: }
464:
465: return allowedMethods;
466: }
467:
468: /**
469: * Returns a list of all versions of this resource represented as <code>ResourceImpl</code>.
470: * objects
471: *
472: * @return
473: */
474: public List getVersions() throws WebDAVException {
475: Vector versions;
476: try {
477: versions = new Vector();
478:
479: AbstractChildObject live = (AbstractChildObject) m_child
480: .getLiveVersion();
481:
482: ResourceImpl member = new ResourceImpl(new URL(
483: HarmoniseNameResolver.getVersionPath(live)), live
484: .getName());
485: versions.add(member);
486:
487: List hists = live.getHistoricalVersions();
488: addVersionResources(versions, hists);
489:
490: } catch (DataAccessException e) {
491: throw new WebDAVException(
492: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
493: .getLocalizedMessage());
494: } catch (MalformedURLException e) {
495: throw new WebDAVException(
496: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
497: .getLocalizedMessage());
498: } catch (NameResolverException e) {
499: throw new WebDAVException(
500: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
501: .getLocalizedMessage());
502: }
503:
504: return versions;
505: }
506:
507: /**
508: * Adds <code>ResourceImpl</code> representations of the child objects held in
509: * <code>childObjs</code> to <code>versionResources</code>.
510: *
511: * @param versionResources
512: * @param childObjs
513: * @throws WebDAVException
514: * @throws MalformedURLException
515: * @throws DataAccessException
516: * @throws NameResolverException
517: */
518: private void addVersionResources(List versionResources,
519: List childObjs) throws WebDAVException,
520: MalformedURLException, DataAccessException,
521: NameResolverException {
522: Iterator iter = childObjs.iterator();
523:
524: while (iter.hasNext()) {
525: AbstractChildObject child = (AbstractChildObject) iter
526: .next();
527:
528: ResourceImpl member = new ResourceImpl(new URL(
529: HarmoniseNameResolver.getVersionPath(child)), child
530: .getName());
531: versionResources.add(member);
532: }
533: }
534:
535: /**
536: * Returns <code>true</code> if this version is checked in.
537: *
538: * @return
539: */
540: public boolean isCheckedInVersion() throws WebDAVException {
541: boolean bIsVersioned = false;
542:
543: try {
544: bIsVersioned = m_child.isLiveVersion();
545: } catch (DataAccessException e) {
546: throw new WebDAVException(
547: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
548: .getLocalizedMessage());
549: }
550:
551: return bIsVersioned;
552: }
553:
554: /**
555: * Returns <code>true</code> of this version is checked out.
556: *
557: * @return
558: */
559: public boolean isCheckedOutVersion() throws WebDAVException {
560: boolean bIsVersioned = false;
561:
562: try {
563: bIsVersioned = m_child.isPendingVersion();
564: } catch (DataAccessException e) {
565: throw new WebDAVException(
566: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
567: .getLocalizedMessage());
568: }
569:
570: return bIsVersioned;
571: }
572:
573: /**
574: * Returns <code>true</code> if this resource is under version control in the
575: * DAV sense, i.e. it has a live Harmonise version
576: *
577: * @return
578: */
579: public boolean isVersioned() throws WebDAVException {
580: boolean bIsVersioned = false;
581:
582: if (m_child != null) {
583: try {
584: bIsVersioned = (m_child.isHistorical() == true || m_child
585: .getLiveVersion() != null);
586: } catch (DataAccessException e) {
587: throw new WebDAVException(
588: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
589: .getLocalizedMessage());
590: }
591: }
592:
593: return bIsVersioned;
594: }
595:
596: /**
597: * Uncheckout this resource. In Harmonise terms, this means getting rid of the pending
598: * version.
599: *
600: * @throws WebDAVException
601: */
602: public void uncheckout() throws WebDAVException {
603: try {
604: if (m_child.isPendingVersion() == true) {
605: m_child.archive();
606: } else {
607: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
608: "Resource is not checked out");
609: }
610: } catch (DataAccessException e) {
611: throw new WebDAVException(
612: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
613: .getLocalizedMessage());
614: } catch (EditException e) {
615: throw new WebDAVException(
616: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
617: .getLocalizedMessage());
618: }
619: }
620:
621: /**
622: * Adds this resource to version control, in the DAV sense. In Harmonise terms,
623: * the child object is made live/approved.
624: *
625: */
626: public void versionControl() throws WebDAVException {
627: try {
628: if (m_child.isPendingVersion() == false
629: || m_child.getLiveVersion() != null) {
630: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
631: "Resource needs to be a new unversioned resource");
632: }
633:
634: addCreator();
635:
636: addPublicationDate();
637:
638: User usr = ((HarmoniseSessionManager) m_resource
639: .getUserAuthenticator()).getUser(m_resource);
640:
641: // ensure change status is allowed
642: if (m_auxillary != null
643: && m_auxillary.isChangeStatusValid(usr, m_child) == false) {
644:
645: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
646: "Object workflow not complete");
647:
648: }
649:
650: m_child = CommandWrapper.changeStatus(m_dsi, m_child, usr,
651: Status.APPROVED);
652:
653: if (m_auxillary != null) {
654: m_auxillary.changeStatus(usr, m_child,
655: Status.UNAPPROVED, Status.APPROVED);
656: }
657: } catch (DataAccessException e) {
658: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
659: throw new WebDAVException(
660: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
661: .getLocalizedMessage());
662: } catch (APMException e) {
663: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
664: throw new WebDAVException(
665: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
666: .getLocalizedMessage());
667: }
668:
669: }
670:
671: /* (non-Javadoc)
672: * @see com.ibm.webdav.impl.NamespaceManager#isVersionable()
673: */
674: public boolean isVersionable() throws WebDAVException {
675: return true;
676: }
677:
678: }
|