/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* 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 com.fujitsu.dc.core.rs.box;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import javax.xml.bind.JAXBException;
import org.apache.http.HttpStatus;
import org.apache.wink.webdav.WebDAVMethod;
import org.apache.wink.webdav.model.Prop;
import org.apache.wink.webdav.model.Propstat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fujitsu.dc.core.DcCoreException;
import com.fujitsu.dc.core.annotations.ACL;
import com.fujitsu.dc.core.annotations.REPORT;
import com.fujitsu.dc.core.auth.BoxPrivilege;
import com.fujitsu.dc.core.model.DavCmp;
import com.fujitsu.dc.core.model.DavCommon;
import com.fujitsu.dc.core.model.DavRsCmp;
import com.fujitsu.dc.core.model.jaxb.Mkcol;
import com.fujitsu.dc.core.model.jaxb.Mkcol.RequestException;
import com.fujitsu.dc.core.model.jaxb.MkcolResponse;
import com.fujitsu.dc.core.model.jaxb.ObjectFactory;
import com.fujitsu.dc.core.model.jaxb.ObjectIo;
import com.fujitsu.dc.core.utils.ResourceUtils;
/**
* Box以下の存在しないパスを担当するJAX-RSリソース.
*/
public class NullResource {
static Logger log = LoggerFactory.getLogger(NullResource.class);
DavRsCmp davRsCmp;
boolean isParentNull;
/**
* constructor.
* @param parent 親リソース
* @param davCmp バックエンド実装に依存する処理を受け持つ部品
* @param isParentNull 親がNullResourceかを判別する
*/
public NullResource(final DavRsCmp parent, final DavCmp davCmp, final boolean isParentNull) {
this.davRsCmp = new DavRsCmp(parent, davCmp);
this.isParentNull = isParentNull;
}
/**
* GETメソッドの処理. 404 Not Foundを返す.
* @return 404 Not Foundを表すJax-RS Response
*/
@GET
public final Response get() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.READ);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* このパスに新たなファイルを配置する.
* @param contentType Content-Typeヘッダ
* @param inputStream リクエストボディ
* @return Jax-RS Responseオブジェクトト
*/
@PUT
public final Response put(
@HeaderParam(HttpHeaders.CONTENT_TYPE) final String contentType,
final InputStream inputStream) {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
// 途中のパスが存在しないときは409エラー
/*
* A PUT that would result in the creation of a resource without an
* appropriately scoped parent collection MUST fail with a 409 (Conflict).
*/
if (!DavCommon.isValidResourceName(this.davRsCmp.getDavCmp().getName())) {
throw DcCoreException.Dav.RESOURCE_NAME_INVALID;
}
if (this.isParentNull) {
throw DcCoreException.Dav.HAS_NOT_PARENT.params(this.davRsCmp.getParent().getUrl());
}
return this.davRsCmp.getDavCmp().putForCreate(contentType, inputStream).build();
}
/**
* このパスに新たなCollectionを作成する.
* @param contentType Content-Type ヘッダ
* @param contentLength Content-Length ヘッダ
* @param transferEncoding Transfer-Encoding ヘッダ
* @param inputStream リクエストボディ
* @return JAX-RS Response
*/
@WebDAVMethod.MKCOL
public Response mkcol(@HeaderParam(HttpHeaders.CONTENT_TYPE) final String contentType,
@HeaderParam("Content-Length") final Long contentLength,
@HeaderParam("Transfer-Encoding") final String transferEncoding,
final InputStream inputStream) {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
// 途中のパスが存在しないときは409エラー
/*
* 409 (Conflict) - A collection cannot be made at the Request-URI until one or more intermediate collections
* have been created.
*/
if (this.isParentNull) {
throw DcCoreException.Dav.HAS_NOT_PARENT.params(this.davRsCmp.getParent().getUrl());
}
if (!DavCommon.isValidResourceName(this.davRsCmp.getDavCmp().getName())) {
throw DcCoreException.Dav.RESOURCE_NAME_INVALID;
}
// リクエストが空なら素直にwebdavでコレクションを作成する
if (!ResourceUtils.hasApparentlyRequestBody(contentLength, transferEncoding)) {
return this.davRsCmp.getDavCmp().mkcol(DavCmp.TYPE_COL_WEBDAV).build();
}
// リクエストが空でない場合、パースして適切な拡張を行う。
Mkcol mkcol = null;
try {
mkcol = ObjectIo.unmarshal(inputStream, Mkcol.class);
} catch (Exception e1) {
throw DcCoreException.Dav.XML_ERROR.reason(e1);
}
ObjectFactory factory = new ObjectFactory();
String colType;
try {
colType = mkcol.getDcColType();
log.debug(colType);
Response response = this.davRsCmp.getDavCmp().mkcol(colType).build();
// ServiceCollectionの場合は、ServiceSource用のWebdavCollectionを生成する
if (colType.equals(DavCmp.TYPE_COL_SVC) && response.getStatus() == HttpStatus.SC_CREATED) {
this.davRsCmp.getDavCmp().loadAndCheckDavInconsistency();
DavCmp srcCmp = this.davRsCmp.getDavCmp().getChild(DavCmp.SERVICE_SRC_COLLECTION);
response = srcCmp.mkcol(DavCmp.TYPE_COL_WEBDAV).build();
}
return response;
// return this.parent.mkcolChild(this.pathName, colType);
} catch (RequestException e) {
final MkcolResponse mr = factory.createMkcolResponse();
Propstat stat = factory.createPropstat();
stat.setStatus("HTTP/1.1 403 Forbidden");
List<Prop> listProp = mkcol.getPropList();
if (!listProp.isEmpty()) {
stat.setProp(listProp.get(0));
}
org.apache.wink.webdav.model.Error error = factory.createError();
error.setAny(factory.createValidResourceType());
stat.setError(error);
stat.setResponsedescription(e.getMessage());
mr.addPropstat(stat);
StreamingOutput str = new StreamingOutput() {
@Override
public void write(final OutputStream os) throws IOException {
try {
ObjectIo.marshal(mr, os);
} catch (JAXBException e) {
throw new WebApplicationException(e);
}
}
};
return Response.status(HttpStatus.SC_FORBIDDEN).entity(str).build();
}
}
/**
* 現在のリソースの一つ下位パスを担当するJax-RSリソースを返す.
* @param nextPath 一つ下のパス名
* @param request リクエスト
* @return 下位パスを担当するJax-RSリソースオブジェクト
*/
@Path("{nextPath}")
public Object nextPath(@PathParam("nextPath") final String nextPath,
@Context HttpServletRequest request) {
return this.davRsCmp.nextPath(nextPath, request);
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@DELETE
public final Response delete() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@POST
public final Response post() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@REPORT
public final Response report() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.READ);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@WebDAVMethod.PROPFIND
public final Response propfind() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.READ);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@WebDAVMethod.PROPPATCH
public final Response proppatch() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@ACL
public final Response acl() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* 404 NOT FOUNDを返す.
* @return Jax-RS 応答オブジェクト
*/
@WebDAVMethod.MOVE
public final Response move() {
// アクセス制御
this.davRsCmp.checkAccessContext(this.davRsCmp.getAccessContext(), BoxPrivilege.WRITE);
throw DcCoreException.Dav.RESOURCE_NOT_FOUND.params(this.davRsCmp.getUrl());
}
/**
* OPTIONSメソッド.
* @return JAX-RS Response
*/
@OPTIONS
public Response options() {
return this.davRsCmp.options();
}
}