blob: 5fbb6c93f8395a5e8a52613d5162302d919fb17f [file] [log] [blame]
/*
* 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 org.apache.sling.jcr.webdav.impl.servlets;
import java.io.IOException;
import javax.jcr.Repository;
import javax.jcr.Session;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.jackrabbit.server.SessionProvider;
import org.apache.jackrabbit.server.io.CopyMoveHandler;
import org.apache.jackrabbit.server.io.DeleteHandler;
import org.apache.jackrabbit.server.io.IOHandler;
import org.apache.jackrabbit.server.io.PropertyHandler;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavLocatorFactory;
import org.apache.jackrabbit.webdav.WebdavRequest;
import org.apache.jackrabbit.webdav.WebdavResponse;
import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
import org.apache.sling.commons.mime.MimeTypeService;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.webdav.impl.handler.SlingCopyMoveManager;
import org.apache.sling.jcr.webdav.impl.handler.SlingDeleteManager;
import org.apache.sling.jcr.webdav.impl.handler.SlingIOManager;
import org.apache.sling.jcr.webdav.impl.handler.SlingPropertyManager;
import org.apache.sling.jcr.webdav.impl.helper.SlingLocatorFactory;
import org.apache.sling.jcr.webdav.impl.helper.SlingResourceConfig;
import org.apache.sling.jcr.webdav.impl.helper.SlingSessionProvider;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.propertytypes.ServiceDescription;
import org.osgi.service.component.propertytypes.ServiceVendor;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
/**
* The <code>SlingWebDavServlet</code> implements the WebDAV protocol as a
* default servlet for Sling handling all WebDAV methods.
*
*/
@Component(
name = "org.apache.sling.jcr.webdav.impl.servlets.SimpleWebDavServlet",
configurationPolicy = ConfigurationPolicy.REQUIRE,
service = { Servlet.class },
property = {
"sling.servlet.resourceTypes=sling/servlet/default",
"sling.servlet.methods=*"
},
reference = {
@Reference( name = SlingWebDavServlet.IOHANDLER_REF_NAME, service = IOHandler.class,
cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC,
bind = "bindIOHandler", unbind = "unbindIOHandler"),
@Reference( name = SlingWebDavServlet.PROPERTYHANDLER_REF_NAME, service = PropertyHandler.class,
cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC,
bind = "bindPropertyHandler", unbind = "unbindPropertyHandler"),
@Reference( name = SlingWebDavServlet.COPYMOVEHANDLER_REF_NAME, service = CopyMoveHandler.class,
cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC,
bind = "bindCopyMoveHandler", unbind = "unbindCopyMoveHandler"),
@Reference( name = SlingWebDavServlet.DELETEHANDLER_REF_NAME, service = DeleteHandler.class,
cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC,
bind = "bindDeleteHandler", unbind = "unbindDeleteHandler")
})
@ServiceDescription("Sling WebDAV Servlet")
@ServiceVendor("The Apache Software Foundation")
@Designate(ocd = SlingWebDavServlet.Config.class)
public class SlingWebDavServlet extends SimpleWebdavServlet {
public static final String DEFAULT_CONTEXT = "/dav";
public static final boolean DEFAULT_CREATE_ABSOLUTE_URI = true;
public static final String DEFAULT_REALM = "Sling WebDAV";
public static final String TYPE_NONCOLLECTIONS_DEFAULT = "nt:file";
public static final String TYPE_CONTENT_DEFAULT = "nt:resource";
public static final String TYPE_COLLECTIONS_DEFAULT = "sling:Folder";
public static final String TYPE_COLLECTIONS = "type.collections";
public static final String TYPE_NONCOLLECTIONS = "type.noncollections";
public static final String TYPE_CONTENT = "type.content";
static final String IOHANDLER_REF_NAME = "IOHandler";
static final String PROPERTYHANDLER_REF_NAME = "PropertyHandler";
static final String COPYMOVEHANDLER_REF_NAME = "CopyMoveHandler";
static final String DELETEHANDLER_REF_NAME = "DeleteHandler";
@SuppressWarnings("java:S100")
@ObjectClassDefinition(name = "%dav.name", description = "%dav.description")
public @interface Config {
@AttributeDefinition(name = "%dav.root.name", description = "%dav.root.description")
String dav_root() default DEFAULT_CONTEXT;
@AttributeDefinition(name = "%dav.create-absolute-uri.name", description = "%dav.create-absolute-uri.description")
boolean dav_create$_$absolute$_$uri() default DEFAULT_CREATE_ABSOLUTE_URI;
@AttributeDefinition(name = "%dav.realm.name", description = "%dav.realm.description")
String dav_realm() default DEFAULT_REALM;
@AttributeDefinition(name = "%collection.types.name", description = "%collection.types.description")
String[] collection_types() default {TYPE_NONCOLLECTIONS_DEFAULT, TYPE_CONTENT_DEFAULT};
@AttributeDefinition(name = "%filter.prefixes.name", description = "%filter.prefixes.description")
String[] filter_prefixes() default {"rep", "jcr"};
@AttributeDefinition(name = "%filter.types.name", description = "%filter.types.description")
String[] filter_types() default {};
@AttributeDefinition(name = "%filter.uris.name", description = "%filter.uris.description")
String[] filter_uris() default {};
@AttributeDefinition(name = "%type.collections.name", description = "%type.collections.description")
String type_collections() default TYPE_COLLECTIONS_DEFAULT;
@AttributeDefinition(name = "%type.noncollections.name", description = "%type.noncollections.description")
String type_noncollections() default TYPE_NONCOLLECTIONS_DEFAULT;
@AttributeDefinition(name = "%type.content.name", description = "%type.content.description")
String type_content() default TYPE_CONTENT_DEFAULT;
}
@Reference
private SlingRepository repository;
@Reference
private HttpService httpService;
@Reference
private MimeTypeService mimeTypeService;
private final SlingIOManager ioManager = new SlingIOManager(IOHANDLER_REF_NAME);
private final SlingPropertyManager propertyManager = new SlingPropertyManager(PROPERTYHANDLER_REF_NAME);
private final SlingCopyMoveManager copyMoveManager = new SlingCopyMoveManager(COPYMOVEHANDLER_REF_NAME);
private final SlingDeleteManager deleteManager = new SlingDeleteManager(DELETEHANDLER_REF_NAME);
private SlingResourceConfig resourceConfig;
private DavLocatorFactory locatorFactory;
private SessionProvider sessionProvider;
private boolean simpleWebDavServletRegistered;
// ---------- SimpleWebdavServlet overwrites -------------------------------
@Override
public void init() throws ServletException {
super.init();
setResourceConfig(resourceConfig);
}
@Override
public Repository getRepository() {
return repository;
}
@Override
public DavLocatorFactory getLocatorFactory() {
if (locatorFactory == null) {
// configured default workspace name
SlingRepository slingRepo = (SlingRepository) getRepository();
String workspace = slingRepo.getDefaultWorkspace();
// no configuration, try to login and acquire the default name
if (workspace == null || workspace.length() == 0) {
Session tmp = null;
try {
tmp = slingRepo.login();
workspace = tmp.getWorkspace().getName();
} catch (Throwable t) {
// TODO: log !!
workspace = "default"; // fall back name
} finally {
if (tmp != null) {
tmp.logout();
}
}
}
locatorFactory = new SlingLocatorFactory(workspace);
}
return locatorFactory;
}
@Override
public synchronized SessionProvider getSessionProvider() {
if (sessionProvider == null) {
sessionProvider = new SlingSessionProvider();
}
return sessionProvider;
}
@Activate
protected void activate(ComponentContext context, Config config)
throws NamespaceException, ServletException {
this.ioManager.setComponentContext(context);
this.propertyManager.setComponentContext(context);
this.copyMoveManager.setComponentContext(context);
this.deleteManager.setComponentContext(context);
resourceConfig = new SlingResourceConfig(mimeTypeService,
config,
ioManager,
propertyManager,
copyMoveManager,
deleteManager);
// Register servlet, and set the contextPath field to signal successful registration
Servlet simpleServlet = new SlingSimpleWebDavServlet(resourceConfig, getRepository());
httpService.registerServlet(resourceConfig.getServletContextPath(),
simpleServlet, resourceConfig.getServletInitParams(), null);
simpleWebDavServletRegistered = true;
}
@Deactivate
protected void deactivate(ComponentContext context) {
if (simpleWebDavServletRegistered) {
httpService.unregister(resourceConfig.getServletContextPath());
simpleWebDavServletRegistered = false;
}
this.resourceConfig = null;
this.ioManager.setComponentContext(null);
this.propertyManager.setComponentContext(null);
this.copyMoveManager.setComponentContext(null);
this.deleteManager.setComponentContext(null);
}
public void bindIOHandler(final ServiceReference ioHandlerReference) {
this.ioManager.bindIOHandler(ioHandlerReference);
}
public void unbindIOHandler(final ServiceReference ioHandlerReference) {
this.ioManager.unbindIOHandler(ioHandlerReference);
}
public void bindPropertyHandler(final ServiceReference propertyHandlerReference) {
this.propertyManager.bindPropertyHandler(propertyHandlerReference);
}
public void unbindPropertyHandler(final ServiceReference propertyHandlerReference) {
this.propertyManager.unbindPropertyHandler(propertyHandlerReference);
}
public void bindCopyMoveHandler(final ServiceReference copyMoveHandlerReference) {
this.copyMoveManager.bindCopyMoveHandler(copyMoveHandlerReference);
}
public void unbindCopyMoveHandler(final ServiceReference copyMoveHandlerReference) {
this.copyMoveManager.unbindCopyMoveHandler(copyMoveHandlerReference);
}
public void bindDeleteHandler(final ServiceReference deleteHandlerReference) {
this.deleteManager.bindDeleteHandler(deleteHandlerReference);
}
public void unbindDeleteHandler(final ServiceReference deleteHandlerReference) {
this.deleteManager.unbindDeleteHandler(deleteHandlerReference);
}
/** Overridden as the base class uses sendError that we don't want (SLING-2443) */
@Override
protected void sendUnauthorized(WebdavRequest request, WebdavResponse response, DavException error) throws IOException {
response.setHeader("WWW-Authenticate", getAuthenticateHeaderValue());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
if (error != null) {
response.getWriter().write(error.getStatusPhrase());
response.getWriter().write("\n");
}
response.getWriter().flush();
}
}