/*
* � Copyright IBM Corp. 2010
*
* 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.ibm.xsp.extlib.component.rest;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.profiler.Profiler;
import com.ibm.commons.util.profiler.ProfilerAggregator;
import com.ibm.commons.util.profiler.ProfilerType;
import com.ibm.domino.services.rest.RestServiceEngine;
import com.ibm.xsp.FacesExceptionEx;
import com.ibm.xsp.ajax.AjaxUtil;
import com.ibm.xsp.application.UniqueViewIdManager;
import com.ibm.xsp.component.FacesAjaxComponent;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.model.domino.DominoUtils;
import com.ibm.xsp.util.FacesUtil;
import com.ibm.xsp.webapp.XspHttpServletResponse;
/**
* Component that handles REST services.
* <p>
* This abstract class is designed to be the base class of a component serving REST service.
* It should be inherited from actual implementation, like the UI REST service.
* </p>
* @author priand
*/
public abstract class UIBaseRestService extends UIComponentBase implements FacesAjaxComponent {
private static final ProfilerType profilerRestService = new ProfilerType("XSP REST Service"); //$NON-NLS-1$
public static final String COMPONENT_TYPE = "com.ibm.xsp.extlib.BaseRestService"; //$NON-NLS-1$
public UIBaseRestService() {
}
// =================================================================
// REST service customization
// =================================================================
public IRestService getService() {
return null;
}
public String getPathInfo() {
return null;
}
public boolean isIgnoreRequestParams() {
return true;
}
public boolean isPreventDojoStore() {
return true;
}
public String getJsId() {
return null;
}
public boolean isState() {
return false;
}
// =================================================================
// Access to the service URL
// =================================================================
public String getUrl() {
return getUrl(FacesContext.getCurrentInstance(), null);
}
public String getUrl(String extraPathInfo) {
return getUrl(FacesContext.getCurrentInstance(), extraPathInfo);
}
public String getUrl(FacesContext context, String extraPathInfo) {
String pathInfo = getPathInfo();
String url = getUrlPath(context, pathInfo, extraPathInfo);
boolean hasQ = false;
// Compose the query string
String vid = getAjaxViewid(context);
if(StringUtil.isNotEmpty(vid)) {
url += (hasQ?"&":"?") + AjaxUtil.AJAX_VIEWID + "=" + vid;
hasQ = true;
}
// If not path info was specified,use the component ajax id
String axTarget = getAjaxTarget(context, pathInfo);
if(StringUtil.isNotEmpty(axTarget)) {
url += (hasQ?"&":"?") + AjaxUtil.AJAX_AXTARGET + "=" + axTarget;
hasQ = true;
}
return url;
}
public String getUrlPath(FacesContext context, String pathInfo, String extraPathInfo) {
ExternalContext externalContext = context.getExternalContext();
String contextPath = externalContext.getRequestContextPath();
String servletPath = externalContext.getRequestServletPath();
StringBuilder b = new StringBuilder();
b.append(contextPath);
b.append(servletPath);
// If there is a path info, use it as part of the URL
if(StringUtil.isNotEmpty(pathInfo)) {
if(!pathInfo.startsWith("/")) {
b.append("/");
}
b.append(pathInfo);
// the extra path info is only valid in this case
if (StringUtil.isNotEmpty(extraPathInfo)) {
b.append("/");
b.append(extraPathInfo);
}
}
//MNIA9UCECY
String url= b.toString();
url=DominoUtils.handleProxyPrefix(url);
return url;
}
public String getAjaxViewid(FacesContext context) {
String vid = UniqueViewIdManager.getUniqueViewId(context.getViewRoot());
if(StringUtil.isNotEmpty(vid)) {
return vid;
}
return null;
}
public String getAjaxTarget(FacesContext context, String pathInfo) {
if(StringUtil.isEmpty(pathInfo)) {
return getClientId(context);
}
return null;
}
// =================================================================
// Dojo interface
// =================================================================
public String getDojoStoreId(FacesContext context) {
String jsId = getJsId();
if(StringUtil.isNotEmpty(jsId)) {
return jsId;
}
return getClientId(context);
}
public static String findRestServiceStoreId(FacesContext context, UIComponent from, String storeComponentId) {
if(StringUtil.isNotEmpty(storeComponentId)) {
UIComponent sc = FacesUtil.getComponentFor(from, storeComponentId);
if(!(sc instanceof UIBaseRestService)) {
throw new FacesExceptionEx(null,"Cannot find Rest Service component {0}",storeComponentId); // $NLX-UIBaseRestService.CannotfindRestServicecomponent0-1$
}
return ((UIBaseRestService)sc).getDojoStoreId(context);
}
return null;
}
// =================================================================
// Ajax service implementation
// =================================================================
public boolean handles(FacesContext context) {
String reqPathInfo = context.getExternalContext().getRequestPathInfo();
if(StringUtil.isNotEmpty(reqPathInfo)) {
String pathInfo = getPathInfo();
if(StringUtil.isEmpty(pathInfo)) {
return false;
}
if(!pathInfo.startsWith("/")) {
pathInfo = "/"+pathInfo;
}
if (!pathInfo.endsWith("/")) {
pathInfo += "/";
}
if (!reqPathInfo.startsWith("/")) {
reqPathInfo = "/" + reqPathInfo;
}
if (!reqPathInfo.endsWith("/")) {
reqPathInfo += "/";
}
if(reqPathInfo.startsWith(pathInfo)) {
return true;
}
}
return false;
}
public void processAjaxRequest(FacesContext context) throws IOException {
if( Profiler.isEnabled()) {
String svc = context.getExternalContext().getRequestServletPath()+ context.getExternalContext().getRequestPathInfo();
ProfilerAggregator agg = Profiler.startProfileBlock(profilerRestService,svc);
long ts = Profiler.getCurrentTime();
try {
_processAjaxRequest(context);
} finally {
Profiler.endProfileBlock(agg,ts);
}
} else {
_processAjaxRequest(context);
}
}
public void _processAjaxRequest(FacesContext context) throws IOException {
// --------------------------------------------
// New implementation
// delegate to the REST service if available
// --------------------------------------------
IRestService service = getService();
if(service!=null) {
HttpServletRequest httpRequest = (HttpServletRequest)context.getExternalContext().getRequest();
HttpServletResponse httpResponse = (HttpServletResponse)context.getExternalContext().getResponse();
// Disable the XPages response buffer as this will collide with the engine one
// We mark it as committed and use its delegate instead
if(httpResponse instanceof XspHttpServletResponse) {
XspHttpServletResponse r = (XspHttpServletResponse)httpResponse;
r.setCommitted(true);
httpResponse = r.getDelegate();
}
RestServiceEngine engine = service.createEngine(context, this, httpRequest, httpResponse);
engine.processRequest();
// Save the view state...
boolean saveState = isState();
if(saveState) {
ExtLibUtil.saveViewState(context);
}
return;
}
}
}