package org.toobsframework.pres.component; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Vector; import javax.servlet.http.Cookie; import javax.xml.transform.URIResolver; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.toobsframework.pres.component.config.GetObject; import org.toobsframework.exception.ParameterException; import org.toobsframework.pres.component.datasource.api.DataSourceNotInitializedException; import org.toobsframework.pres.component.datasource.api.IDataSource; import org.toobsframework.pres.component.datasource.api.IDataSourceObject; import org.toobsframework.pres.component.datasource.api.InvalidSearchContextException; import org.toobsframework.pres.component.datasource.api.InvalidSearchFilterException; import org.toobsframework.pres.component.datasource.api.ObjectCreationException; import org.toobsframework.pres.component.datasource.api.ObjectNotFoundException; import org.toobsframework.pres.component.datasource.impl.DataSourceObjectImpl; import org.toobsframework.pres.util.ComponentRequestManager; import org.toobsframework.pres.util.CookieVO; import org.toobsframework.pres.util.ParameterUtil; import org.toobsframework.pres.util.PresConstants; import org.toobsframework.servlet.ContextHelper; import org.toobsframework.transformpipeline.domain.IXMLTransformer; import org.toobsframework.transformpipeline.domain.XMLTransformerException; import org.toobsframework.transformpipeline.domain.XMLTransformerFactory; import org.toobsframework.util.BetwixtUtil; import org.toobsframework.util.Configuration; /** * @author pudney */ @SuppressWarnings("unchecked") public class Component { private static final String XML_HEADER = "<?xml version=\"1.0\"?>"; private static final String XML_START_COMPONENTS = "<component"; private static final String XML_END_COMPONENTS = "</component>"; private static final String XML_START_OBJECTS = "<objects>"; private static final String XML_END_OBJECTS = "</objects>"; private static final String XML_START_ERRORS = "<errors>"; private static final String XML_END_ERRORS = "</errors>"; private static final String XML_START_ERROR_OBJS = "<errorobjects>"; private static final String XML_END_ERROR_OBJS = "</errorobjects>"; private static Log log = LogFactory.getLog(Component.class); private ComponentRequestManager componentRequestManager; private String Id; private boolean renderErrorObject; private boolean scanUrls; private boolean initDone; private Map transforms; private GetObject[] objectsConfig; private String[] controllerNames; private String[] styles; private String fileName; public Component() { this.Id = null; this.initDone = false; componentRequestManager = (ComponentRequestManager)ContextHelper.getWebApplicationContext().getBean("componentRequestManager"); } public IDataSourceObject[] getObjects(Map paramsIn, Map paramsOut) throws ComponentException, ComponentNotInitializedException, ParameterException { ArrayList allObjects = new ArrayList(); if (!this.initDone) { ComponentNotInitializedException ex = new ComponentNotInitializedException(); ex.setComponentId(this.Id); throw ex; } int len = objectsConfig.length; for (int i = 0; i < len; i++) { Map params = new HashMap(paramsIn); GetObject thisObjDef = objectsConfig[i]; //Fetch Datasource for this get. IDataSource datasource = (IDataSource)ContextHelper.getWebApplicationContext().getBean(thisObjDef.getDatasource()); //Fix the params using the param mapping for //this configuration. if(thisObjDef.getParameters() != null){ ParameterUtil.mapParameters("Component:" + this.Id + ":GetObject:" + thisObjDef.getDaoObject(), thisObjDef.getParameters().getParameter(), params, params, this.Id, allObjects); } ArrayList theseObjects = new ArrayList(); //Call the appropriate action. Map outParams = new HashMap(); if (thisObjDef.getObjectAction().equals("get")) { Object guidObj = null; String thisGuidParam = ParameterUtil.resolveParam(thisObjDef.getGuidParam(), params)[0]; if (thisGuidParam != null && params.containsKey(thisGuidParam)) { guidObj = params.get(thisGuidParam); } if (guidObj != null && guidObj.getClass().isArray()) { guidObj = ((String[]) params.get(thisGuidParam))[0]; } else { guidObj = (String) params.get(thisGuidParam); } Object obj = null; obj = checkForValidation(paramsIn, thisObjDef, (String)guidObj); if (obj == null) { obj = this.getObject( datasource, thisObjDef.getReturnedValueObject(), ParameterUtil.resolveParam(thisObjDef.getDaoObject(), params)[0], thisObjDef.getNoCache(), (String)guidObj, params, outParams); } theseObjects.add(obj); } else if (thisObjDef.getObjectAction().equals("getCookie")) { String searchCriteria = ParameterUtil.resolveParam(thisObjDef.getSearchCriteria(), params)[0]; String thisGuidParam = ParameterUtil.resolveParam(thisObjDef.getGuidParam(), params)[0]; String cookieName = (searchCriteria != null ? searchCriteria : ""); Object guidValue = params.get(thisGuidParam); if (guidValue != null && guidValue.getClass().isArray()) { cookieName += ((String[])guidValue)[0]; } else { cookieName += guidValue; } String cookieValue = null; Cookie[] cookies = componentRequestManager.get().getHttpRequest().getCookies(); if (cookies != null) { for (int c = 0; c < cookies.length; c++) { Cookie cookie = cookies[c]; if (cookie.getName().equals(cookieName)) { cookieValue = cookie.getValue(); break; } } } if (cookieName != null && cookieValue != null) { theseObjects.add(this.createObject(new CookieVO(cookieName, cookieValue))); } } else if (thisObjDef.getObjectAction().equals("search")) { try { theseObjects.addAll(datasource.search( ParameterUtil.resolveParam(thisObjDef.getReturnedValueObject(), params)[0], ParameterUtil.resolveParam(thisObjDef.getDaoObject(), params)[0], thisObjDef.getSearchCriteria(), thisObjDef.getSearchMethod(), thisObjDef.getPermissionAction(), params, outParams)); } catch (ObjectCreationException e) { throw new ComponentException("Problem fetching object:" + this.Id + ":" + thisObjDef.getDaoObject() + ":" + thisObjDef.getReturnedValueObject(), e); } catch (InvalidSearchContextException e) { throw new ComponentException("Invalid Search Context", e); } catch (InvalidSearchFilterException e) { throw new ComponentException("Ivalid Search Filter", e); } catch (DataSourceNotInitializedException e) { throw new ComponentException("Datasource Not Initialized", e); } } else if (thisObjDef.getObjectAction().equals("searchIndex")) { try { theseObjects.addAll(datasource.searchIndex( thisObjDef.getReturnedValueObject(), ParameterUtil.resolveParam(thisObjDef.getDaoObject(), params)[0], thisObjDef.getSearchCriteria(), thisObjDef.getSearchMethod(), thisObjDef.getPermissionAction(), params, outParams)); } catch (ObjectCreationException e) { throw new ComponentException("Problem fetching object:" + thisObjDef.getDaoObject(), e); } catch (InvalidSearchContextException e) { throw new ComponentException("Invalid Search Context", e); } catch (InvalidSearchFilterException e) { throw new ComponentException("Ivalid Search Filter", e); } catch (DataSourceNotInitializedException e) { throw new ComponentException("Datasource Not Initialized", e); } } ParameterUtil.mapScriptParams(outParams, paramsIn); if(thisObjDef.getOutputParameters() != null){ ParameterUtil.mapOutputParameters(thisObjDef.getOutputParameters().getParameter(), paramsIn, this.Id, theseObjects); if (paramsOut != null) { ParameterUtil.mapOutputParameters(thisObjDef.getOutputParameters().getParameter(), paramsOut, this.Id, theseObjects); } } allObjects.addAll(theseObjects); } allObjects.trimToSize(); IDataSourceObject[] objArray = new IDataSourceObject[allObjects.size()]; objArray = (IDataSourceObject[]) allObjects.toArray(objArray); return objArray; } public IDataSourceObject createObject(Object valueObject) throws ComponentException, ComponentNotInitializedException { if (valueObject == null) { return null; } DataSourceObjectImpl dsObj = new DataSourceObjectImpl(); dsObj.setValueObject(valueObject); return dsObj; } public IDataSourceObject getObject(IDataSource datasource, String returnedValueObject, String daoObject, boolean noCache, String guid, Map params, Map outParams) throws ComponentException, ComponentNotInitializedException { IDataSourceObject object = null; if (!this.initDone) { ComponentNotInitializedException ex = new ComponentNotInitializedException(); ex.setComponentId(this.Id); throw ex; } try { if (!noCache) { object = componentRequestManager.checkRequestCache("get", returnedValueObject, guid); } if (object == null) { object = datasource.getObject(returnedValueObject, daoObject, guid, params, outParams); if (!noCache) { componentRequestManager.cacheObject("get", returnedValueObject, guid, object); } } } catch (DataSourceNotInitializedException ex) { ComponentException ce = new ComponentException("Datasource not initialized.", ex); throw ce; } catch (ObjectNotFoundException ex) { ComponentException ce = new ComponentException("Error getting object " + returnedValueObject + " for component " + this.Id, ex); throw ce; } return object; } public void init() { this.initDone = true; } public String render(String contentType, Map params, Map paramsOut) throws ComponentNotInitializedException, ComponentException, ParameterException { return this.render(contentType, params, paramsOut, null); } /** * Runs the objects through the xml pipeline to get the proper rendering of * the component as defined in the config file. * * @return rendered component * @throws ComponentNotInitializedException * @throws ComponentException */ public String render(String contentType, Map params, Map paramsOut, URIResolver uriResolver) throws ComponentNotInitializedException, ComponentException, ParameterException { StringBuffer renderedOutput = new StringBuffer(); Date start = new Date(); String componentXML = this.getObjectsAsXML(params, paramsOut); Date endGet = new Date(); if (!contentType.equals("bizXML")) { renderedOutput.append(this.callXMLPipeline(contentType, componentXML, params, uriResolver)); } else { renderedOutput.append(componentXML); } Date end = new Date(); if (log.isDebugEnabled()) { log.debug("Comp [" + Id + "] gTime: " + (endGet.getTime()-start.getTime()) + " rTime: " + (end.getTime()-endGet.getTime()) + " fTime: " + (end.getTime()-start.getTime())); } return renderedOutput.toString(); } /** * Gets all of the objects in this component as a single xml file with a * proper wrapper. * * @return component as xml * @throws ComponentNotInitializedException * @throws ComponentException */ private String getObjectsAsXML(Map params, Map paramsOut) throws ComponentNotInitializedException, ComponentException, ParameterException { StringBuffer xml = new StringBuffer(); IDataSourceObject[] objects = this.getObjects(params, paramsOut); try { xml.append(XML_HEADER); xml.append(XML_START_COMPONENTS).append(" id=\"").append(this.Id).append("\">"); xml.append(XML_START_OBJECTS); if ((objects != null) && (objects.length > 0)) { for (int i = 0; i < objects.length; i++) { xml.append(objects[i].toXml()); } } xml.append(XML_END_OBJECTS); if (renderErrorObject) { if (params.containsKey(PresConstants.VALIDATION_ERROR_MESSAGES)) { componentRequestManager.get().getHttpResponse().setHeader("toobs.error.validation", "true"); List globalErrorList = (List)params.get(PresConstants.VALIDATION_ERROR_MESSAGES); for (int g = 0; g < globalErrorList.size(); g++) { xml.append(XML_START_ERRORS); List errorList = (List)globalErrorList.get(g); for (int i = 0; i < errorList.size(); i++) { xml.append(BetwixtUtil.toXml(errorList.get(i))); } xml.append(XML_END_ERRORS); } } if (params.containsKey(PresConstants.VALIDATION_ERROR_OBJECTS)) { List globalMessageList = (List)params.get(PresConstants.VALIDATION_ERROR_OBJECTS); for (int g = 0; g < globalMessageList.size(); g++) { xml.append(XML_START_ERROR_OBJS); List errorList = (List)globalMessageList.get(g); for (int i = 0; i < errorList.size(); i++) { xml.append(BetwixtUtil.toXml(errorList.get(i))); } xml.append(XML_END_ERROR_OBJS); } } } xml.append(XML_END_COMPONENTS); } catch (IOException ex) { throw new ComponentException("Error getting xml for object", ex); } return xml.toString(); } /** * Runs the objects through the xml pipeline to get the proper rendering of * the component as defined in the config file. * * @return rendered component * @throws ComponentNotInitializedException * @throws ComponentException */ private String callXMLPipeline(String contentType, String inputXMLString, Map inParams, URIResolver uriResolver) throws ComponentException, ParameterException { StringBuffer outputString = new StringBuffer(); Vector outputXML = new Vector(); try { // Initialize variables needed to run transformer. IXMLTransformer xmlTransformer = null; Vector inputXSLs = new Vector(); HashMap params = new HashMap(); Vector inputXML = new Vector(); // Prepare XML inputXML.add(inputXMLString); // Prepare XSLs and Params. Vector contentTransforms = (Vector) this.getTransforms().get(contentType); if (contentTransforms != null && contentTransforms.size() > 0) { Iterator it = contentTransforms.iterator(); while (it.hasNext()) { Transform transform = (Transform) it.next(); inputXSLs.add(transform.getTransformName()); //Fix the params using the param mapping for //this configuration. if(transform.getTransformParams() != null){ ParameterUtil.mapParameters("Transform:" + transform.getTransformName(), transform.getTransformParams().getParameter(), inParams, params, this.Id); } } } else { throw new ComponentException("Component with id: " + this.Id + " does not have a transform for content type: " + contentType); } //ParameterUtil.mapFrameworkParams(inParams, params); // Figure out which Transformer to run and prepare as // necessary for that Transformer. Vector xslSources = new Vector(); xslSources.addAll(inputXSLs); if (xslSources.size() > 1) { if (!"xhtml".equals(contentType)) { xmlTransformer = XMLTransformerFactory.getInstance().getChainTransformer(XMLTransformerFactory.OUTPUT_FORMAT_XML, uriResolver); } else { xmlTransformer = XMLTransformerFactory.getInstance().getChainTransformer(XMLTransformerFactory.OUTPUT_FORMAT_HTML, uriResolver); } } else { xmlTransformer = XMLTransformerFactory.getInstance().getDefaultTransformer(uriResolver); } // Do Transformation xslSources.trimToSize(); if (xslSources.size() > 0) { params.put("context", Configuration.getInstance().getMainContext() + "/"); if (inParams.get("appContext") != null) { params.put("appContext", inParams.get("appContext")); } outputXML = xmlTransformer.transform(xslSources, inputXML, params); } else { outputXML = inputXML; } } catch (XMLTransformerException xte) { log.error(xte); throw new ComponentException("Error running transform", xte); } // Prepare output for (int ox = 0; ox < outputXML.size(); ox++) { outputString.append((String) outputXML.get(ox)); } // Return return outputString.toString(); } private Object checkForValidation(Map paramsIn, GetObject getObjDef, String guid) throws ComponentException, ComponentNotInitializedException { List<Object> errorObjects = (List<Object>)paramsIn.get(PresConstants.VALIDATION_ERROR_OBJECTS); if(errorObjects != null) { for(int i = 0; i < errorObjects.size(); i++) { Object errorObject = errorObjects.get(i); Class errorObjClass = errorObject.getClass(); //if the error obj class and the returned value object match... String errorObjClassName = errorObjClass.getName(); errorObjClassName = errorObjClassName.substring(errorObjClassName.lastIndexOf(".") + 1); if(errorObjClassName.equals(getObjDef.getReturnedValueObject())) { //then check the guid value try { Method getGuidMethod = errorObjClass.getMethod("getGuid"); String errorObjGuid = (String)getGuidMethod.invoke(errorObject); // if guids match, return the error obj instance if(errorObjGuid != null && errorObjGuid.equals(guid)) return this.createObject(errorObject); // if exception, then just continue } catch(NoSuchMethodException nsme) { } catch(IllegalAccessException iae) { } catch(InvocationTargetException iae) { } } } } return null; } /** * Loads the transformer based on the type of transform requested. * * @param type * * @return XMLTransformer * @throws StrutsCXException private IXMLTransformer getXMLTransformer(String type) throws XMLTransformerException { return XMLTransformerFactory.getInstance().getXMLTransformer(type); } */ public GetObject[] getObjectsConfig() { return objectsConfig; } public void setObjectsConfig(GetObject[] objectsConfig) { this.objectsConfig = objectsConfig; } public void setId(String Id) { this.Id = Id; } public String getId() { return this.Id; } public void setTransforms(Map transforms) { this.transforms = transforms; } public Map getTransforms() { return this.transforms; } public boolean isRenderErrorObject() { return renderErrorObject; } public void setRenderErrorObject(boolean renderErrorObject) { this.renderErrorObject = renderErrorObject; } public boolean isScanUrls() { return scanUrls; } public void setScanUrls(boolean scanUrls) { this.scanUrls = scanUrls; } public String[] getControllerNames() { return controllerNames; } public void setControllerNames(String[] controllerNames) { this.controllerNames = controllerNames; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String[] getStyles() { return styles; } public void setStyles(String[] styles) { this.styles = styles; } }