/**
* <copyright>
*
* Copyright (c) 2009, 2010, 2012 Springsite BV (The Netherlands) and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Martin Taal - Initial API and implementation
* Dzmitry [zmicer] Harachka - implementation
* </copyright>
*
* $Id: ServiceContext.java,v 1.7 2011/08/27 19:21:32 mtaal Exp $
*/
package org.eclipse.emf.texo.server.service;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.texo.component.ComponentProvider;
import org.eclipse.emf.texo.component.TexoComponent;
import org.eclipse.emf.texo.server.model.request.RequestModelPackage;
import org.eclipse.emf.texo.server.model.response.ErrorType;
import org.eclipse.emf.texo.server.model.response.ResponseModelPackage;
import org.eclipse.emf.texo.store.MemoryObjectStore;
import org.eclipse.emf.texo.store.ObjectStore;
/**
* Defines the context in which a {@link ModelOperation} operates. Contains for example request parameters and allows to
* set result content and result type and result response code. The context is used for as well input as well as
* providing results of an operation. A ServiceContext is not shared and is used for one single thread and operation
* bean.
*
* @author <a href="mailto:zmicer.harachka@gmail.com">Dzmitry [zmicer] Harachka</a>
* @author <a href="mtaal@elver.org">Martin Taal</a>
* @version $Revision: 1.7 $
*/
public abstract class ServiceContext implements TexoComponent {
protected static final String CONTENT_TYPE_HEADER_PARAM = "Content-Type"; //$NON-NLS-1$
protected static final String RESPONSE_HEADER_CACHE_CONTROL = "Cache-Control"; //$NON-NLS-1$
protected static final String RESPONSE_NO_CACHE = "no-cache"; //$NON-NLS-1$
// flag set when running texo testcases, not used in other cases
private static boolean isInTexoTestRun = false;
public static void setInTexoTestRun() {
isInTexoTestRun = true;
}
protected static boolean isInTexoTestRun() {
return isInTexoTestRun;
}
private String requestContent;
private Map<String, Object> requestParameters = new HashMap<String, Object>();
private String requestURI;
// default is true
private boolean useWebServiceUriFormat = true;
/**
* @see #getServiceRequestURI()
*/
private String serviceRequestURI;
private String responseContent;
private int responseCode = HttpServletResponse.SC_OK; // default is okay
private String responseContentType;
private Map<String, String> responseHeaders = new HashMap<String, String>();
private boolean errorOccured = false;
private ObjectStore objectStore;
private ServiceOptions serviceOptions = ComponentProvider.getInstance().newInstance(ServiceOptions.class);
public ServiceContext() {
// most of the time caching is not needed
getResponseHeaders().put(RESPONSE_HEADER_CACHE_CONTROL, RESPONSE_NO_CACHE);
// touch the request package so it is read
RequestModelPackage.initialize();
}
/**
* The delegate is the underlying representation of the context, this can be for example the request object.
*/
private Object delegate;
public String getRequestContent() {
return requestContent;
}
public void setRequestContent(String requestContent) {
this.requestContent = requestContent;
}
public Map<String, Object> getRequestParameters() {
return requestParameters;
}
public void setRequestParameters(Map<String, Object> requestParameters) {
this.requestParameters = requestParameters;
}
public String getRequestURI() {
return requestURI;
}
public void setRequestURI(String requestURI) {
this.requestURI = requestURI;
}
public String getResponseContent() {
return responseContent;
}
public void setResponseContent(String responseContent) {
this.responseContent = responseContent;
}
public int getResponseCode() {
return responseCode;
}
public void setResponseCode(int responseCode) {
this.responseCode = responseCode;
}
public String getResponseContentType() {
return responseContentType;
}
public void setResponseContentType(String responseType) {
responseContentType = responseType;
getResponseHeaders().put(CONTENT_TYPE_HEADER_PARAM, responseType);
}
public Object getDelegate() {
return delegate;
}
public void setDelegate(Object delegate) {
this.delegate = delegate;
}
public void createErrorResult(Throwable t) {
setResponseCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
final ErrorType error = createErrorType(t, new ArrayList<Throwable>());
if (getObjectStore() == null) {
// error occured probably during object store creation
// use the in memory object store for now
setObjectStore(ComponentProvider.getInstance().newInstance(MemoryObjectStore.class));
}
setResponseContent(convertToResultFormat(error));
setErrorOccured(true);
}
public void createResourceNotFoundResult() {
createErrorResult(new IllegalArgumentException("Resource not found " + getRequestURI())); //$NON-NLS-1$
setResponseCode(HttpServletResponse.SC_NOT_FOUND);
}
public Map<String, String> getResponseHeaders() {
return responseHeaders;
}
public boolean isErrorOccured() {
return errorOccured;
}
public void setErrorOccured(boolean errorOccured) {
this.errorOccured = errorOccured;
}
/**
* The part of the requestURI which is specific for the service, the service can use this to identify a specific
* resource which is being fetched. For example say that the complete request URI is this:
* http://www.test.com/xmlwebservice/SalesOrder/1231
*
* which would be a url pointing to a specific SalesOrder. Then the serviceRequestURI will be: SalesOrder/1231
*
* So without a preceding /.
*/
public String getServiceRequestURI() {
return serviceRequestURI;
}
/**
* @param serviceRequestURI
* @see #getServiceRequestURI()
*/
public void setServiceRequestURI(String serviceRequestURI) {
this.serviceRequestURI = serviceRequestURI;
}
protected ErrorType createErrorType(Throwable t, List<Throwable> handledThrowables) {
final ErrorType error = ResponseModelPackage.INSTANCE.getModelFactory().createErrorType();
error.setErrorClass(t.getClass().getName());
error.setMessage(t.getMessage());
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.close();
error.setStackTrace(sw.toString());
if (t.getCause() != null && !handledThrowables.contains(t.getCause())) {
error.setCause(createErrorType(t.getCause(), handledThrowables));
}
return error;
}
/**
* Convert a single object to the format supported by the implementing service, for example to json or to xml.
*
* @param object
* the object to convert, should typically be a Texo generated object
* @return a string representing the format returned by the webservice.
*/
protected abstract String convertToResultFormat(Object object);
/**
* Convert a single object to the format supported by the implementing service, for example to json or to xml.
*
* @param object
* the object to convert, should typically be a Texo generated object
* @return a string representing the format returned by the webservice.
*/
protected abstract String convertToResultFormat(EObject eObject);
/**
* Convert the passed object to the format expected (xml or json for example) and place the result in the response
* content.
*
* @param object
* the object to convert
* @see ServiceContext#setResponseContent(String)
*/
public void setResultInResponse(Object object) {
setResponseContent(convertToResultFormat(object));
}
/**
* Convert the passed object to the format expected (xml or json for example) and place the result in the response
* content.
*
* @param eObject
* the {@link EObject} to convert
* @see ServiceContext#setResponseContent(String)
*/
public void setResultInResponse(EObject eObject) {
setResponseContent(convertToResultFormat(eObject));
}
/**
* Get the data posted as the request content as a list of objects.
*
* @return the list of objects present in the request content
*/
public abstract List<Object> getRequestData();
public ObjectStore getObjectStore() {
return objectStore;
}
public void setObjectStore(ObjectStore objectStore) {
this.objectStore = objectStore;
}
public ServiceOptions getServiceOptions() {
return serviceOptions;
}
public void setServiceOptions(ServiceOptions serviceOptions) {
this.serviceOptions = serviceOptions;
}
public boolean isUseWebServiceUriFormat() {
return useWebServiceUriFormat;
}
public void setUseWebServiceUriFormat(boolean useWebServiceUriFormat) {
this.useWebServiceUriFormat = useWebServiceUriFormat;
}
}