io.milton.http.annotated.AnnoCollectionResource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of milton-server-ce Show documentation
Show all versions of milton-server-ce Show documentation
Milton Community Edition: Supports DAV level 1 and is available on Apache2 license
The newest version!
/*
*
* Copyright 2014 McEvoy Software Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.milton.http.annotated;
import io.milton.common.Path;
import io.milton.http.LockInfo;
import io.milton.http.LockTimeout;
import io.milton.http.LockToken;
import io.milton.http.Request;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.ConflictException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.exceptions.NotFoundException;
import io.milton.resource.CollectionResource;
import io.milton.resource.DeletableCollectionResource;
import io.milton.resource.ExtMakeCalendarResource;
import io.milton.resource.LockingCollectionResource;
import io.milton.resource.MakeCollectionableResource;
import io.milton.resource.PutableResource;
import io.milton.resource.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.slf4j.LoggerFactory;
/**
* Placeholder object to represent a node in an annotations hierachy acting as a
* collection
*
* A source object (ie your pojo) is considered a collection if it can have
* children , ie if there exists at least one @ChildOf or @ChildrenOf method
* which has that object as its source type. Note this is keyed on the class.
*
* This class includes methods suitable for use in page templating logic for
* navigating through the hierarchy.
*
* @author brad
*/
public class AnnoCollectionResource extends AnnoResource implements CollectionResource, PutableResource, MakeCollectionableResource, LockingCollectionResource, DeletableCollectionResource, ExtMakeCalendarResource {
private static final org.slf4j.Logger log = LoggerFactory.getLogger(AnnoCollectionResource.class);
/**
* lazy loaded list of all children of this collection
*/
private ResourceList children;
/**
* this holds child items located single prior to the children list being
* populated
*/
private ResourceList singlyLoadedChildItems;
public AnnoCollectionResource(final AnnotationResourceFactory outer, Object source, AnnoCollectionResource parent) {
super(outer, source, parent);
}
@Override
public Resource child(String childName) throws NotAuthorizedException, BadRequestException {
// attempt to locate singly, ie without loading entire list of children
// first check if it has already been loaded singly
if (singlyLoadedChildItems != null && singlyLoadedChildItems.hasChild(childName)) {
return singlyLoadedChildItems.get(childName);
}
// if children list has already been loaded then look for child in there
if (children != null) {
for (Resource r : children) {
if (r.getName().equals(childName)) {
return r;
}
}
}
// try to load singly using ChildOf annotation, if present
// childTriValue can be null, the child source object, or a special value indicating no search
Object childTriValue = null;
try {
childTriValue = annoFactory.childOfAnnotationHandler.execute(this, childName);
} catch (NotFoundException ex) {
log.warn("Failed to lookup child", ex);
}
if (childTriValue == null) {
//return null; // definitely not found
// well, actually. ChildOf can just apply to a certain sort of child, so if its not found
// that doesnt mean that there might not be some othe child
// so we can't assume in any circumstance that a null means not found. Must always fall through to ChildrenOf
} else if (childTriValue.equals(ChildOfAnnotationHandler.NOT_ATTEMPTED)) {
// there is no ChildOf method, so fall through to iterating over all children
} else {
// got one!
AnnoResource r = (AnnoResource) childTriValue;
if (singlyLoadedChildItems == null) {
singlyLoadedChildItems = new ResourceList();
}
singlyLoadedChildItems.add(r);
return r;
}
// Previously we checked in children list if it was loaded to avoid double-instantiating
// childOf objects. Since we've got here without finding a child, we can load the
// list of children and iterate over it.
// We can end up iterating over the list twice, but thats because there
// is no guarantee that getChildren is the same as children
for (Resource r : getChildren(true)) {
if (r.getName().equals(childName)) {
return r;
}
}
return null;
}
@Override
public List extends Resource> getChildren() throws NotAuthorizedException, BadRequestException {
return getResourceList();
}
public List extends Resource> getChildren(boolean isChildLookup) throws NotAuthorizedException, BadRequestException {
return findChildren(isChildLookup);
}
public ResourceList getResourceList() throws NotAuthorizedException, BadRequestException {
return findChildren(false);
}
public ResourceList getSubFolders() throws NotAuthorizedException, BadRequestException {
return getResourceList().getDirs();
}
public ResourceList getFiles() throws NotAuthorizedException, BadRequestException {
return getResourceList().getFiles();
}
protected ResourceList findChildren(boolean isChildLookup) throws NotAuthorizedException, BadRequestException {
if (children == null) {
initChildren(isChildLookup);
}
return children;
}
/**
* Called when the children list is first accessed
*
* This will create the children ResourceList and populate it with known
* child resources
*
* @param isChildLookup - indicates this is being called in the context of a
* call to load a single child by name
*
* @throws NotAuthorizedException
* @throws BadRequestException
*/
protected void initChildren(boolean isChildLookup) throws NotAuthorizedException, BadRequestException {
children = new ResourceList();
Set set;
try {
set = annoFactory.childrenOfAnnotationHandler.execute(this, isChildLookup);
} catch (NotAuthorizedException e) {
throw e;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
children.addAll(set);
// Now add any temp lock resources
for (LockHolder holder : annoFactory.getTempResourcesForParent(this)) {
CommonResource cr = annoFactory.instantiate(holder, this);
children.add(cr);
}
// if there are singly loaded items we must replace their dopple-ganger in children
// because there might already be references to those resource objects elsewhere in code
// and having two objects representing the same resource causes unpredictable chaos!!!
if (singlyLoadedChildItems != null) {
for (CommonResource r : singlyLoadedChildItems) {
children.remove(r.getName());
children.add(r);
}
}
}
public Map getChildrenMap() throws NotAuthorizedException, BadRequestException {
return getResourceList().getMap();
}
public Map getChildrenOfType() throws NotAuthorizedException, BadRequestException {
return getResourceList().getOfType();
}
@Override
public CollectionResource createCollection(String newName) throws NotAuthorizedException, ConflictException, BadRequestException {
Object newlyCreatedSource = annoFactory.makCollectionAnnotationHandler.execute(this, newName);
AnnoCollectionResource r = new AnnoCollectionResource(annoFactory, newlyCreatedSource, this);
if (children != null) {
children.add(r);
}
return r;
}
@Override
public CollectionResource createCalendar(String newName, Map fieldsToSet) throws NotAuthorizedException, ConflictException, BadRequestException {
Object newlyCreatedSource = annoFactory.makeCalendarAnnotationHandler.execute(this, newName, fieldsToSet);
AnnoCollectionResource r = new AnnoCalendarResource(annoFactory, newlyCreatedSource, this);
if (children != null) {
children.add(r);
}
return r;
}
@Override
public Resource createNew(String newName, InputStream inputStream, Long length, String contentType) throws IOException, ConflictException, NotAuthorizedException, BadRequestException {
Object newChildSource = annoFactory.putChildAnnotationHandler.execute(this, newName, inputStream, length, contentType);
AnnoCollectionResource newRes = new AnnoCollectionResource(annoFactory, newChildSource, this);
if (children != null) {
CommonResource oldRes = children.get(newName);
if (oldRes != null) {
children.remove(oldRes);
}
children.add(newRes);
}
return newRes;
}
@Override
public AnnoCollectionResource getRoot() {
if (parent == null) {
return this;
} else {
return parent.getRoot();
}
}
@Override
public LockToken createAndLock(String name, LockTimeout timeout, LockInfo lockInfo) throws NotAuthorizedException {
LockHolder r = annoFactory.createLockHolder(this, name, timeout, lockInfo);
if (children != null) {
CommonResource cr = annoFactory.instantiate(r, parent);
children.add(cr);
}
return new LockToken(r.getId().toString(), lockInfo, timeout);
}
void removeLockHolder(String name) {
if (children != null) {
children.removeIf(r -> r instanceof LockNullResource && r.getName().equals(name));
}
}
@Override
public boolean isLockedOutRecursive(Request request) {
return false; // TODO
}
public Resource find(String s) throws NotAuthorizedException, BadRequestException {
Path p = Path.path(s);
return findPath(p);
}
/**
* Locate a resource from the given path evaluated relative to this
* resource.
*
* Supports ".." and "." segments, any other strings are considered file
* names
*
* @param p
* @return
* @throws NotAuthorizedException
* @throws BadRequestException
*/
public Resource findPath(Path p) throws NotAuthorizedException, BadRequestException {
Resource r = this;
for (String segment : p.getParts()) {
if (segment.equals("..")) {
if (r instanceof AnnoResource) {
AnnoResource ar = (AnnoResource) r;
r = ar.getParent();
} else {
log.warn("Couldnt get parent of resource type: " + r.getClass());
return null;
}
} else if (segment.equals(".")) {
// do nothing
} else {
if (r instanceof CollectionResource) {
CollectionResource col = (CollectionResource) r;
r = col.child(segment);
} else {
log.warn("Couldnt find child: " + segment + " of parent: " + r.getName() + " because the parent is not actually a collection");
return null;
}
}
}
return r;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy