Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.milton.http.annotated.AnnotationResourceFactory Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.annotations.AccessControlList;
import io.milton.annotations.AddressBooks;
import io.milton.annotations.Authenticate;
import io.milton.annotations.CTag;
import io.milton.annotations.CalendarColor;
import io.milton.annotations.CalendarDateRangeQuery;
import io.milton.annotations.CalendarInvitations;
import io.milton.annotations.CalendarInvitationsCTag;
import io.milton.annotations.CalendarOrder;
import io.milton.annotations.CalendarUserType;
import io.milton.annotations.Calendars;
import io.milton.annotations.ChildOf;
import io.milton.annotations.ChildrenOf;
import io.milton.annotations.ContactData;
import io.milton.annotations.ContentLength;
import io.milton.annotations.ContentType;
import io.milton.annotations.Copy;
import io.milton.annotations.CreatedDate;
import io.milton.annotations.Delete;
import io.milton.annotations.DirectoryGateway;
import io.milton.annotations.Email;
import io.milton.annotations.FreeBusyQuery;
import io.milton.annotations.Get;
import io.milton.annotations.ICalData;
import io.milton.annotations.MakeCollection;
import io.milton.annotations.MaxAge;
import io.milton.annotations.ModifiedDate;
import io.milton.annotations.Move;
import io.milton.annotations.Name;
import io.milton.annotations.Post;
import io.milton.annotations.PrincipalSearch;
import io.milton.annotations.PutChild;
import io.milton.annotations.Realm;
import io.milton.annotations.Root;
import io.milton.annotations.SupportedComponentSets;
import io.milton.annotations.UniqueId;
import io.milton.annotations.Users;
import io.milton.common.Path;
import io.milton.http.Auth;
import io.milton.http.AuthenticationService;
import io.milton.http.HttpManager;
import io.milton.http.LockInfo;
import io.milton.http.LockManager;
import io.milton.http.LockTimeout;
import io.milton.http.Request;
import io.milton.http.Request.Method;
import io.milton.http.ResourceFactory;
import io.milton.http.Response;
import io.milton.http.caldav.CalendarSearchService;
import io.milton.http.exceptions.BadRequestException;
import io.milton.http.exceptions.NotAuthorizedException;
import io.milton.http.template.ViewResolver;
import io.milton.http.values.SupportedCalendarComponentListsSet;
import io.milton.http.webdav.DisplayNameFormatter;
import io.milton.resource.CollectionResource;
import io.milton.resource.PropFindableResource;
import io.milton.resource.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A resource factory which provides access to files in a file system.
*
* Using this with milton is equivalent to using the dav servlet in tomcat
*
*/
public final class AnnotationResourceFactory implements ResourceFactory {
private static final Logger log = LoggerFactory.getLogger(AnnotationResourceFactory.class);
private AuthenticationService authenticationService;
private CalendarSearchService calendarSearchService;
private boolean doEarlyAuth = true;
private io.milton.http.SecurityManager securityManager;
private LockManager lockManager;
private String contextPath;
private Collection controllers;
private ViewResolver viewResolver;
/**
* Replace with a suitable cluster enabled Map for cluster support
*/
private Map> mapOfTempResources = new ConcurrentHashMap<>();
private final Map mapOfAnnotationHandlers = new HashMap<>(); // keyed on annotation class
private final Map mapOfAnnotationHandlersByMethod = new EnumMap<>(Method.class); // keyed on http method
final RootAnnotationHandler rootAnnotationHandler = new RootAnnotationHandler(this);
final GetAnnotationHandler getAnnotationHandler = new GetAnnotationHandler(this);
final PostAnnotationHandler postAnnotationHandler = new PostAnnotationHandler(this);
final ChildrenOfAnnotationHandler childrenOfAnnotationHandler = new ChildrenOfAnnotationHandler(this);
final ChildOfAnnotationHandler childOfAnnotationHandler = new ChildOfAnnotationHandler(this);
final DisplayNameAnnotationHandler displayNameAnnotationHandler = new DisplayNameAnnotationHandler(this);
final DisplayNameSetterAnnotationHandler displayNameSetterAnnotationHandler = new DisplayNameSetterAnnotationHandler(this);
final MakeCollectionAnnotationHandler makCollectionAnnotationHandler = new MakeCollectionAnnotationHandler(this);
final MakeCalendarAnnotationHandler makeCalendarAnnotationHandler = new MakeCalendarAnnotationHandler(this);
final MoveAnnotationHandler moveAnnotationHandler = new MoveAnnotationHandler(this);
final DeleteAnnotationHandler deleteAnnotationHandler = new DeleteAnnotationHandler(this);
final CopyAnnotationHandler copyAnnotationHandler = new CopyAnnotationHandler(this);
final PutChildAnnotationHandler putChildAnnotationHandler = new PutChildAnnotationHandler(this);
final UsersAnnotationHandler usersAnnotationHandler = new UsersAnnotationHandler(this);
final AuthenticateAnnotationHandler authenticateAnnotationHandler = new AuthenticateAnnotationHandler(this);
final AccessControlListAnnotationHandler accessControlListAnnotationHandler = new AccessControlListAnnotationHandler(this);
final CTagAnnotationHandler cTagAnnotationHandler = new CTagAnnotationHandler(this);
final ICalDataAnnotationHandler iCalDataAnnotationHandler = new ICalDataAnnotationHandler(this);
final CalendarsAnnotationHandler calendarsAnnotationHandler = new CalendarsAnnotationHandler(this);
final AddressBooksAnnotationHandler addressBooksAnnotationHandler = new AddressBooksAnnotationHandler(this);
final ContactDataAnnotationHandler contactDataAnnotationHandler = new ContactDataAnnotationHandler(this);
final PrincipalSearchAnnotationHandler principalSearchAnnotationHandler = new PrincipalSearchAnnotationHandler(this);
final CommonPropertyAnnotationHandler nameAnnotationHandler = new CommonPropertyAnnotationHandler(Name.class, this, "name", "fileName");
final CommonPropertyAnnotationHandler emailAnnotationHandler = new CommonPropertyAnnotationHandler(Email.class, this, "email");
final CommonPropertyAnnotationHandler supportedComponentSets = new CommonPropertyAnnotationHandler(SupportedComponentSets.class, this, "supportedComponentSets");
final CommonPropertyAnnotationHandler realmAnnotationHandler = new CommonPropertyAnnotationHandler(Realm.class, this, "realm");
final CommonPropertyAnnotationHandler modifiedDateAnnotationHandler = new CommonPropertyAnnotationHandler<>(ModifiedDate.class, this, "modifiedDate");
final CommonPropertyAnnotationHandler createdDateAnnotationHandler = new CommonPropertyAnnotationHandler<>(CreatedDate.class, this);
final ContentTypeAnnotationHandler contentTypeAnnotationHandler = new ContentTypeAnnotationHandler(this, "contentType");
final CommonPropertyAnnotationHandler contentLengthAnnotationHandler = new CommonPropertyAnnotationHandler<>(ContentLength.class, this, "contentLength");
final CommonPropertyAnnotationHandler maxAgeAnnotationHandler = new CommonPropertyAnnotationHandler<>(MaxAge.class, this, "maxAge");
final CommonPropertyAnnotationHandler uniqueIdAnnotationHandler = new CommonPropertyAnnotationHandler<>(UniqueId.class, this, "id");
final CommonPropertyAnnotationHandler calendarColorAnnotationHandler = new CommonPropertyAnnotationHandler<>(CalendarColor.class, this, "color");
final CommonPropertyAnnotationHandler calendarOrderAnnotationHandler = new CommonPropertyAnnotationHandler<>(CalendarOrder.class, this, "order");
final CommonPropertyAnnotationHandler calendarUserTypeAnnotationHandler = new CommonPropertyAnnotationHandler<>(CalendarUserType.class, this, "calendarUserType", "cuType");
final CalendarDateRangeQueryAnnotationHandler calendarDateRangeQueryAnnotationHandler = new CalendarDateRangeQueryAnnotationHandler(this);
final FreeBusyQueryAnnotationHandler freeBusyQueryAnnotationHandler = new FreeBusyQueryAnnotationHandler(this);
final CalendarInvitationsAnnotationHandler calendarInvitationsAnnotationHandler = new CalendarInvitationsAnnotationHandler(this);
final CalendarInvitationsCTagAnnotationHandler calendarInvitationsCTagAnnotationHandler = new CalendarInvitationsCTagAnnotationHandler(this);
final CommonPropertyAnnotationHandler directoryGatewayAnnotationHandler = new CommonPropertyAnnotationHandler(DirectoryGateway.class, this, "directoryGateway");
public AnnotationResourceFactory() {
supportedComponentSets.setDefaultValue(SupportedCalendarComponentListsSet.EVENTS_ONLY);
mapOfAnnotationHandlers.put(Root.class, rootAnnotationHandler);
mapOfAnnotationHandlers.put(Get.class, getAnnotationHandler);
mapOfAnnotationHandlers.put(Post.class, postAnnotationHandler);
mapOfAnnotationHandlers.put(ChildrenOf.class, childrenOfAnnotationHandler);
mapOfAnnotationHandlers.put(ChildOf.class, childOfAnnotationHandler);
mapOfAnnotationHandlers.put(Name.class, nameAnnotationHandler);
mapOfAnnotationHandlers.put(DisplayNameAnnotationHandler.class, displayNameAnnotationHandler);
mapOfAnnotationHandlers.put(DisplayNameSetterAnnotationHandler.class, displayNameSetterAnnotationHandler);
mapOfAnnotationHandlers.put(MakeCollection.class, makCollectionAnnotationHandler);
mapOfAnnotationHandlers.put(Move.class, moveAnnotationHandler);
mapOfAnnotationHandlers.put(Delete.class, deleteAnnotationHandler);
mapOfAnnotationHandlers.put(Copy.class, copyAnnotationHandler);
mapOfAnnotationHandlers.put(PutChild.class, putChildAnnotationHandler);
mapOfAnnotationHandlers.put(Users.class, usersAnnotationHandler);
mapOfAnnotationHandlers.put(Authenticate.class, authenticateAnnotationHandler);
mapOfAnnotationHandlers.put(AccessControlList.class, accessControlListAnnotationHandler);
mapOfAnnotationHandlers.put(AddressBooks.class, addressBooksAnnotationHandler);
mapOfAnnotationHandlers.put(Calendars.class, calendarsAnnotationHandler);
mapOfAnnotationHandlers.put(MakeCalendarAnnotationHandler.class, makeCalendarAnnotationHandler);
mapOfAnnotationHandlers.put(ModifiedDate.class, modifiedDateAnnotationHandler);
mapOfAnnotationHandlers.put(CreatedDate.class, createdDateAnnotationHandler);
mapOfAnnotationHandlers.put(ContentType.class, contentTypeAnnotationHandler);
mapOfAnnotationHandlers.put(MaxAge.class, maxAgeAnnotationHandler);
mapOfAnnotationHandlers.put(ContentLength.class, contentLengthAnnotationHandler);
mapOfAnnotationHandlers.put(UniqueId.class, uniqueIdAnnotationHandler);
mapOfAnnotationHandlers.put(CTag.class, cTagAnnotationHandler);
mapOfAnnotationHandlers.put(ICalData.class, iCalDataAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarColor.class, calendarColorAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarOrder.class, calendarOrderAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarUserType.class, calendarUserTypeAnnotationHandler);
mapOfAnnotationHandlers.put(ContactData.class, contactDataAnnotationHandler);
mapOfAnnotationHandlers.put(PrincipalSearch.class, principalSearchAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarDateRangeQuery.class, calendarDateRangeQueryAnnotationHandler);
mapOfAnnotationHandlers.put(FreeBusyQuery.class, freeBusyQueryAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarInvitations.class, calendarInvitationsAnnotationHandler);
mapOfAnnotationHandlers.put(CalendarInvitationsCTag.class, calendarInvitationsCTagAnnotationHandler);
mapOfAnnotationHandlers.put(Email.class, emailAnnotationHandler);
mapOfAnnotationHandlers.put(SupportedComponentSets.class, supportedComponentSets);
for (AnnotationHandler ah : mapOfAnnotationHandlers.values()) {
Method[] methods = ah.getSupportedMethods();
if (methods != null) {
for (Method m : methods) {
mapOfAnnotationHandlersByMethod.put(m, ah);
}
}
}
}
@Override
public Resource getResource(String host, String url) throws NotAuthorizedException, BadRequestException {
if (log.isTraceEnabled()) {
log.trace("getResource: host: " + host + " - url:" + url);
}
AnnoCollectionResource hostRoot = locateHostRoot(host, HttpManager.request());
if (hostRoot == null) {
if (rootAnnotationHandler.getControllerMethods().isEmpty()) {
log.warn("No @Root methods were found, so i cant find a root resource. Note that controller methods are displayed on startup");
} else {
log.warn("Could not find a root resource for host: " + host + " Using " + rootAnnotationHandler.getControllerMethods().size() + " root methods");
}
return null;
}
Resource r;
url = stripContext(url);
if (url.equals("/") || url.isEmpty()) {
r = hostRoot;
} else {
Path path = Path.path(url);
r = findFromRoot(hostRoot, path);
if (log.isTraceEnabled()) {
if (r == null) {
log.trace("Resource not found: host=" + host + " path=" + path);
} else {
if (r instanceof AnnoResource) {
AnnoResource ar = (AnnoResource) r;
log.trace("Found AnnoResource: " + r.getClass() + " for path=" + path + " with source: " + ar.getSource());
} else {
log.trace("Found resource: " + r.getClass() + " for path=" + path);
}
}
}
}
return r;
}
public Resource findFromRoot(AnnoCollectionResource rootFolder, Path p) throws NotAuthorizedException, BadRequestException {
CollectionResource col = rootFolder;
Resource r = null;
for (String s : p.getParts()) {
if (col == null) {
if (log.isTraceEnabled()) {
log.trace("findFromRoot: collection is null, can't look for child: " + s);
}
return null;
}
r = col.child(s);
if (r == null) {
if (log.isTraceEnabled()) {
log.trace("findFromRoot: Couldnt find child: " + s + " of parent: " + col.getName() + " with type: " + col.getClass());
}
return null;
} else {
if (log.isTraceEnabled()) {
if (r instanceof AnnoResource) {
AnnoResource ar = (AnnoResource) r;
log.trace("findFromRoot: found a child: " + r.getName() + " with source type: " + ar.getSource().getClass());
} else {
log.trace("findFromRoot: found a child: " + r.getName() + " of type: " + r.getClass());
}
}
}
if (r instanceof CollectionResource) {
col = (CollectionResource) r;
} else {
col = null;
}
}
return r;
}
public String getRealm(String host) {
return securityManager.getRealm(host);
}
public void setAuthenticationService(AuthenticationService authenticationService) {
this.authenticationService = authenticationService;
}
public AuthenticationService getAuthenticationService() {
return authenticationService;
}
public CalendarSearchService getCalendarSearchService() {
return calendarSearchService;
}
public void setCalendarSearchService(CalendarSearchService calendarSearchService) {
this.calendarSearchService = calendarSearchService;
}
/**
* If true authentication will be attempted as soon as the root resource is
* located
*
* @return
*/
public boolean isDoEarlyAuth() {
return doEarlyAuth;
}
public void setDoEarlyAuth(boolean doEarlyAuth) {
this.doEarlyAuth = doEarlyAuth;
}
public void setSecurityManager(io.milton.http.SecurityManager securityManager) {
if (securityManager != null) {
log.debug("securityManager: " + securityManager.getClass());
} else {
log.warn("Setting null FsSecurityManager. This WILL cause null pointer exceptions");
}
this.securityManager = securityManager;
}
public io.milton.http.SecurityManager getSecurityManager() {
return securityManager;
}
public void setMaxAgeSeconds(Long maxAgeSeconds) {
maxAgeAnnotationHandler.setDefaultValue(maxAgeSeconds);
}
public Long getMaxAgeSeconds() {
return maxAgeAnnotationHandler.getDefaultValue();
}
public LockManager getLockManager() {
return lockManager;
}
public void setLockManager(LockManager lockManager) {
this.lockManager = lockManager;
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
public String getContextPath() {
return contextPath;
}
/**
* Get a context path which is definitely valid as a path. Ie it always
* begins with a slash, and ends with a slash, and is a single slash if
* representing the root
*
* @return
*/
public String getValidContextPath() {
String s = getContextPath();
if (s == null || s.isEmpty()) {
return "/";
}
if (!s.endsWith("/")) {
s += "/";
}
return s;
}
public String stripContext(String url) {
if (this.contextPath != null && contextPath.length() > 0 && !contextPath.equals("/")) {
String c;
if (!contextPath.startsWith("/")) {
c = "/" + contextPath;
} else {
c = contextPath;
}
url = url.replaceFirst(c, "");
//log.debug("stripped context: " + url);
}
return url;
}
public Collection getControllers() {
return controllers;
}
public void setControllers(Collection controllers) {
this.controllers = Collections.unmodifiableCollection(controllers);
log.info("setControllers: " + controllers.size() + " parsing controllers...");
for (Object controller : controllers) {
log.info("Parse controller: " + controller.getClass());
for (AnnotationHandler ah : mapOfAnnotationHandlers.values()) {
log.info(" - controller: " + controller.getClass() + " handler: " + ah.getAnnoClass());
ah.parseController(controller);
}
}
log.info("Controller parsing complete. Listing found methods..");
for (AnnotationHandler ah : mapOfAnnotationHandlers.values()) {
log.info("Annotation: " + ah.getAnnoClass());
List list = ah.getControllerMethods();
if (list == null || list.isEmpty()) {
log.info(" No methods found");
} else {
for (ControllerMethod cm : ah.getControllerMethods()) {
log.info(" method: " + cm.method);
}
}
}
}
public ViewResolver getViewResolver() {
return viewResolver;
}
public void setViewResolver(ViewResolver viewResolver) {
this.viewResolver = viewResolver;
}
private AnnoCollectionResource locateHostRoot(String host, Request request) {
AnnoCollectionResource rootRes;
if (request != null) {
// attempt to find one cached in the request
rootRes = (AnnoCollectionResource) request.getAttributes().get("RootRes_" + host);
if (rootRes != null) {
return rootRes;
}
}
Object root = rootAnnotationHandler.execute(host);
if (root == null) {
return null;
}
rootRes = new AnnoCollectionResource(this, root, null);
if (request != null) {
request.getAttributes().put("RootRes_" + host, rootRes);
}
return rootRes;
}
public boolean isCompatible(Object source, Method m) {
if (in(m, Method.REPORT, Method.LOCK, Method.UNLOCK, Method.HEAD, Method.OPTIONS, Method.PROPPATCH, Method.ACL)) {
return true;
}
AnnotationHandler ah = mapOfAnnotationHandlersByMethod.get(m);
if (ah != null) {
boolean b = ah.isCompatible(source);
if (log.isTraceEnabled()) {
log.trace("isCompatible: " + source + " - " + m + " = " + b);
}
return b;
}
log.warn("No annotation handler is configured for http method: " + m);
return false;
}
/**
*
* @param sourceRes
* @param m
* @param otherValues - any other values to be provided which can be mapped
* onto method arguments
* @return
* @throws Exception
*/
public Object[] buildInvokeArgs(AnnoResource sourceRes, java.lang.reflect.Method m, Object... otherValues) throws Exception {
return buildInvokeArgsExt(sourceRes, null, false, m, otherValues);
}
/**
*
* @param sourceRes
* @param mandatorySecondArg - if present will be used as second arg. Used
* by AccessControlListAnnotationHandler to always provide user to second
* arg, even when null
* @param forceUseSecondArg
* @param m
* @param otherValues
* @return
* @throws Exception
*/
public Object[] buildInvokeArgsExt(AnnoResource sourceRes, Object mandatorySecondArg, boolean forceUseSecondArg, java.lang.reflect.Method m, Object... otherValues) throws Exception {
if (log.isTraceEnabled()) {
log.trace("buildInvokeArgsExt: source=" + sourceRes.getSource() + " on method: " + m);
}
Request request = HttpManager.request();
Response response = HttpManager.response();
Auth auth = request.getAuthorization();
AnnoPrincipalResource principal = null;
if (auth != null) {
if (auth.getTag() instanceof AnnoPrincipalResource) {
principal = (AnnoPrincipalResource) auth.getTag();
}
}
Object[] args = new Object[m.getParameterTypes().length];
List list = new ArrayList();
list.add(sourceRes.getSource()); // First argument MUST be the source object!!!
// put otherValues on. Note these are more specific then parents so must be added first
for (Object s : otherValues) {
list.add(s);
if (s instanceof AnnoResource) {
AnnoResource otherRes = (AnnoResource) s;
list.add(otherRes.getSource());
}
}
// put this resource's parents on the stack
AnnoResource r = sourceRes.getParent();
while (r != null) {
list.add(r.getSource());
list.add(r);
r = r.getParent();
}
for (int i = 0; i < m.getParameterTypes().length; i++) {
if (i == 1 && forceUseSecondArg) {
args[i] = mandatorySecondArg; // hack for methods which can have a null 2nd arg. Without this any other matching object would be provided
} else {
if (isPrincipalArg(m, i)) {
principal = checkAuthentication(sourceRes, principal);
if (principal != null) {
args[i] = principal.source;
} else {
log.warn("Null principal provided for method: " + m);
args[i] = null;
}
} else {
Class type = m.getParameterTypes()[i];
Object argValue;
try {
argValue = findArgValue(type, request, response, list);
} catch (UnresolvableParameterException e) {
log.warn("Could not resolve parameter: " + i + " in method: " + m.getName());
argValue = null;
}
args[i] = argValue;
}
}
}
return args;
}
public java.lang.reflect.Method findMethodForAnno(Class sourceClass, Class annoClass) {
for (java.lang.reflect.Method m : sourceClass.getMethods()) {
Annotation a = m.getAnnotation(annoClass);
if (a != null) {
return m;
}
}
return null;
}
private Object findArgValue(Class type, Request request, Response response, List otherAvailValues) throws Exception {
if (type == Request.class) {
return request;
} else if (type == Response.class) {
return response;
} else if (type == byte[].class) {
InputStream in = (InputStream) findArgValue(InputStream.class, request, response, otherAvailValues);
return toBytes(in);
} else {
for (Object o : otherAvailValues) {
if (o != null && type.isAssignableFrom(o.getClass())) {
otherAvailValues.remove(o); // remove it so that we dont use same value for next param of same type
return o;
}
}
}
if (log.isInfoEnabled()) {
if (log.isDebugEnabled()) {
log.info("Unknown parameter type: " + type);
log.debug("Available types are:");
log.debug(" - " + Request.class);
log.debug(" - " + Response.class);
for (Object o : otherAvailValues) {
if (o != null) {
log.debug(" - " + o.getClass());
} else {
log.debug(" - null");
}
}
} else {
log.info("Unknown parameter type: " + type + " Enable DEBUG level logging to see available objects");
}
}
throw new UnresolvableParameterException("Couldnt find parameter of type: " + type);
}
private byte[] toBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
IOUtils.copy(inputStream, bout);
return bout.toByteArray();
}
/**
* Create a Resource to wrap a source pojo object.
*
* @param childSource
* @param parent
* @param m
* @return
*/
public AnnoResource instantiate(Object childSource, AnnoCollectionResource parent, java.lang.reflect.Method m) {
if (authenticateAnnotationHandler.canAuthenticate(childSource)) {
return new AnnoPrincipalResource(this, childSource, parent);
}
if (parent instanceof AnnoPrincipalResource) {
// Check for a Calendars method which takes this source as first arg
if (calendarsAnnotationHandler.isCompatible(childSource)) {
AnnoPrincipalResource p = (AnnoPrincipalResource) parent;
return new AnnoCalendarHomeResource(this, childSource, p, calendarSearchService);
}
}
if (m.getAnnotation(Calendars.class) != null) {
return new AnnoCalendarResource(this, childSource, parent);
}
if (parent instanceof AnnoCalendarResource) {
if (childrenOfAnnotationHandler.isCompatible(childSource) || childOfAnnotationHandler.isCompatible(childSource)) {
// This is an edge case, shouldnt really have collections inside calendars
return new AnnoCollectionResource(this, childSource, parent);
} else {
return new AnnoEventResource(this, childSource, parent);
}
}
if (m.getAnnotation(AddressBooks.class) != null) {
return new AnnoAddressBookResource(this, childSource, parent);
}
if (parent instanceof AnnoAddressBookResource) {
return new AnnoContactResource(this, childSource, parent);
}
if (childrenOfAnnotationHandler.isCompatible(childSource) || childOfAnnotationHandler.isCompatible(childSource)) {
return new AnnoCollectionResource(this, childSource, parent);
} else {
return new AnnoFileResource(this, childSource, parent);
}
}
public CommonResource instantiate(LockHolder r, AnnoCollectionResource parent) {
return new LockNullResource(this, parent, r);
}
/**
* Create an in-memory resource with the given timeout. The resource will
* not be persisted, but may be distributed among the cluster if configured
* as such.
*
* The resource may be flushed from the in-memory list after the given
* timeout if not-null
*
* The type of the object returned is not intended to have any significance
* and does not contain any meaningful content
*
* @param parentCollection
* @param name
* @param timeout - optional. The resource will be removed after this
* timeout expires
* @param lockInfo
* @return - a temporary (not persistent) resource of an indeterminate type
*/
public LockHolder createLockHolder(AnnoCollectionResource parentCollection, String name, LockTimeout timeout, LockInfo lockInfo) {
String parentKey = parentCollection.getUniqueId();
if (parentKey == null) {
throw new RuntimeException("Cant create temp resource because parent's uniqueID is null. Please add the @UniqueID for class: " + parentCollection.getSource().getClass());
}
LockHolder r = new LockHolder(UUID.randomUUID());
r.setParentCollectionId(parentKey);
r.setName(name);
r.setLockTimeout(timeout);
r.setLockInfo(lockInfo);
synchronized (this) {
List list = mapOfTempResources.get(parentKey);
if (list == null) {
list = new CopyOnWriteArrayList<>();
mapOfTempResources.put(parentKey, list);
}
list.add(r);
}
return r;
}
/**
* Null-safe method to get the list of lock holders for the given parent.
* These are resources created by a LOCK-null request, where resources are
* locked prior to being created. The lock-null resource is replaced
* following a PUT to that resource
*
* @param parent
* @return
*/
public List getTempResourcesForParent(AnnoCollectionResource parent) {
String parentKey = parent.getUniqueId();
if (parentKey == null) {
return Collections.emptyList();
}
return getTempResourcesForParent(parentKey);
}
public List getTempResourcesForParent(String parentKey) {
List list = mapOfTempResources.get(parentKey);
if (list == null) {
return Collections.emptyList();
} else {
return list;
}
}
/**
* Removes the LockHolder from memory and also from the parent which
* contains it (if loaded)
*
* @param parent
* @param name
*/
public void removeLockHolder(AnnoCollectionResource parent, String name) {
List list = getTempResourcesForParent(parent);
Iterator it = list.iterator();
List toRemove = new ArrayList<>();
while (it.hasNext()) {
LockHolder o = it.next();
if (o.getName().equals(name)) {
toRemove.add(o);
//it.remove();
}
}
list.removeAll(toRemove);
parent.removeLockHolder(name);
}
public Map> getMapOfTempResources() {
return mapOfTempResources;
}
public void setMapOfTempResources(Map> mapOfTempResources) {
this.mapOfTempResources = mapOfTempResources;
}
private boolean in(Method m, Method... methods) {
for (Method listMethod : methods) {
if (m.equals(listMethod)) {
return true;
}
}
return false;
}
private boolean isPrincipalArg(java.lang.reflect.Method m, int i) {
Annotation[] arr = m.getParameterAnnotations()[i];
Class annoType = io.milton.annotations.Principal.class;
for (Annotation a : arr) {
if (a.annotationType().equals(annoType)) {
return true;
}
}
return false;
}
/**
* Process the source object (which may be a Collection of source objects),
* and for each one instantiate an AnnoResource and append it to the result
* set
*
*
* @param result - to append to
* @param sources - single source object, or multiple source objects in a
* Collection
* @param parent - the parent collection of these resource(s)
* @param cm - the controller method they were found by
*/
public void createAndAppend(Collection result, Object sources, AnnoCollectionResource parent, ControllerMethod cm) {
if (sources == null) {
// ignore
} else if (sources instanceof Collection) {
Collection l = (Collection) sources;
for (Object item : l) {
result.add(instantiate(item, parent, cm.method));
}
} else if (sources.getClass().isArray()) {
Object[] arr = (Object[]) sources;
for (Object item : arr) {
result.add(instantiate(item, parent, cm.method));
}
} else {
result.add(instantiate(sources, parent, cm.method));
}
}
private AnnoPrincipalResource checkAuthentication(AnnoResource res, AnnoPrincipalResource principal) throws NotAuthorizedException {
if (principal != null) {
return principal;
}
if (doEarlyAuth) {
if (authenticationService != null) {
Request request = HttpManager.request();
// Note that authentication will usually result in a call to getResource to find the principal..
AuthenticationService.AuthStatus authStatus = authenticationService.authenticate(res, request);
if (authStatus == null) {
log.trace("Authentication not attempted");
throw new NotAuthorizedException(res);
} else {
if (authStatus.loginFailed) {
log.warn("Early authentication failed");
throw new NotAuthorizedException(res);
} else {
log.trace("Early authentication succeeded");
Auth auth = authStatus.auth;
if (auth != null) {
if (auth.getTag() instanceof AnnoPrincipalResource) {
principal = (AnnoPrincipalResource) auth.getTag();
}
}
return principal;
}
}
}
}
return null;
}
public static class AnnotationsDisplayNameFormatter implements DisplayNameFormatter {
private final DisplayNameFormatter wrapped;
public AnnotationsDisplayNameFormatter(DisplayNameFormatter wrapper) {
this.wrapped = wrapper;
}
@Override
public String formatDisplayName(PropFindableResource res) {
if (res instanceof AnnoResource) {
AnnoResource r = (AnnoResource) res;
return r.getDisplayName();
}
return wrapped.formatDisplayName(res);
}
}
public CalendarDateRangeQueryAnnotationHandler getCalendarDateRangeQueryAnnotationHandler() {
return calendarDateRangeQueryAnnotationHandler;
}
public CalendarInvitationsAnnotationHandler getCalendarInvitationsAnnotationHandler() {
return calendarInvitationsAnnotationHandler;
}
public CalendarInvitationsCTagAnnotationHandler getCalendarInvitationsCTagAnnotationHandler() {
return calendarInvitationsCTagAnnotationHandler;
}
public FreeBusyQueryAnnotationHandler getFreeBusyQueryAnnotationHandler() {
return freeBusyQueryAnnotationHandler;
}
public UsersAnnotationHandler getUsersAnnotationHandler() {
return usersAnnotationHandler;
}
}