/*******************************************************************************
* $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-util/tool-lib/src/java/org/sakaiproject/metaobj/shared/control/XsltArtifactView.java $
* $Id: XsltArtifactView.java 123167 2013-04-23 18:26:31Z chmaurer@iupui.edu $
* **********************************************************************************
*
* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.metaobj.shared.control;
import org.springframework.web.servlet.view.xslt.AbstractXsltView;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.util.NestedServletException;
import org.springframework.validation.Errors;
import org.springframework.validation.ObjectError;
import org.springframework.validation.FieldError;
import org.springframework.validation.BindingResultUtils;
import org.jdom.transform.JDOMSource;
import org.jdom.Element;
import org.jdom.Document;
import org.sakaiproject.content.api.ResourceEditingHelper;
import org.sakaiproject.content.api.ResourceToolAction;
import org.sakaiproject.metaobj.shared.mgt.StructuredArtifactDefinitionManager;
import org.sakaiproject.metaobj.shared.model.Artifact;
import org.sakaiproject.metaobj.shared.model.ElementBean;
import org.sakaiproject.metaobj.shared.model.Id;
import org.sakaiproject.metaobj.shared.FormHelper;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.tool.api.ToolSession;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.tool.cover.ToolManager;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.util.Web;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.Map.Entry;
import java.io.InputStream;
/**
* Created by IntelliJ IDEA.
* User: johnellis
* Date: Oct 30, 2006
* Time: 10:10:42 AM
* To change this template use File | Settings | File Templates.
*/
public class XsltArtifactView extends AbstractXsltView {
private ResourceLoader resourceLoader = new ResourceLoader();
private String bundleLocation;
private static final String STYLESHEET_PARAMS =
"org.sakaiproject.metaobj.shared.control.XsltArtifactView.paramsMap";
private static final String STYLESHEET_LOCATION =
"org.sakaiproject.metaobj.shared.control.XsltArtifactView.stylesheetLocation";
private String uriResolverBeanName;
private URIResolver uriResolver;
private boolean readOnly;
// These parameter names are reserved. Anything not on this list may be passed
// as an HTTP query parameter to pass through from the browser to the stylesheet.
protected static final List<String> reservedParams = Collections.unmodifiableList(Arrays.asList(
"preview", "fromResources", "edit", "panelId", "subForm",
FormHelper.XSL_SITE_ID, FormHelper.XSL_PRESENTATION_TYPE,
FormHelper.XSL_PRESENTATION_ID, FormHelper.XSL_PRESENTATION_ITEM_ID,
FormHelper.XSL_PRESENTATION_ITEM_NAME, FormHelper.XSL_FORM_TYPE,
FormHelper.XSL_ARTIFACT_ID, FormHelper.XSL_ARTIFACT_REFERENCE,
FormHelper.XSL_OBJECT_ID, FormHelper.XSL_OBJECT_TITLE, FormHelper.XSL_WIZARD_PAGE_ID
));
protected Source createXsltSource(Map map, String string, HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws Exception {
httpServletResponse.setContentType(getContentType());
WebApplicationContext context = getWebApplicationContext();
setUriResolver((URIResolver)context.getBean(uriResolverBeanName));
ToolSession toolSession = SessionManager.getCurrentToolSession();
String homeType = null;
ElementBean bean = (ElementBean) map.get("bean");
Element root = null;
Map paramsMap = new Hashtable();
for (Enumeration e = httpServletRequest.getParameterNames(); e.hasMoreElements(); ) {
String k = e.nextElement().toString();
// Do not allow reserved parameter names to be overwritten
if (!reservedParams.contains(k)) {
paramsMap.put(k, httpServletRequest.getParameter(k));
}
}
httpServletRequest.setAttribute(STYLESHEET_PARAMS, paramsMap);
if (toolSession.getAttribute(FormHelper.PREVIEW_HOME_TAG) != null) {
paramsMap.put("preview", "true");
}
if (toolSession.getAttribute(ResourceToolAction.ACTION_PIPE) != null) {
paramsMap.put("fromResources", "true");
}
if (httpServletRequest.getAttribute(FormHelper.URL_DECORATION) != null) {
paramsMap.put("urlDecoration", httpServletRequest.getAttribute(FormHelper.URL_DECORATION));
}
HashMap<String, String> xslParams = new HashMap<String, String>();
xslParams.put(FormHelper.XSL_PRESENTATION_ID, FormHelper.PRESENTATION_ID);
xslParams.put(FormHelper.XSL_PRESENTATION_TYPE, FormHelper.PRESENTATION_TEMPLATE_ID);
xslParams.put(FormHelper.XSL_PRESENTATION_ITEM_ID, FormHelper.PRESENTATION_ITEM_DEF_ID);
xslParams.put(FormHelper.XSL_PRESENTATION_ITEM_NAME, FormHelper.PRESENTATION_ITEM_DEF_NAME);
xslParams.put(FormHelper.XSL_FORM_TYPE, ResourceEditingHelper.CREATE_SUB_TYPE);
xslParams.put(FormHelper.XSL_ARTIFACT_REFERENCE, ResourceEditingHelper.ATTACHMENT_ID);
xslParams.put(FormHelper.XSL_OBJECT_ID, FormHelper.XSL_OBJECT_ID);
xslParams.put(FormHelper.XSL_OBJECT_TITLE, FormHelper.XSL_OBJECT_TITLE);
xslParams.put(FormHelper.XSL_WIZARD_PAGE_ID, FormHelper.XSL_WIZARD_PAGE_ID);
// Load up our XSL parameters according to the mapping into the tool session above.
// Note that this is not always one-to-one due to some string/key inconsistencies around the tools.
for (Entry<String, String> item : xslParams.entrySet()) {
Object val = toolSession.getAttribute(item.getValue());
if (val != null) {
paramsMap.put(item.getKey(), val);
}
}
Id id = null;
if (bean instanceof Artifact) {
root = getStructuredArtifactDefinitionManager().createFormViewXml(
(Artifact) bean, null);
homeType = getHomeType((Artifact) bean);
id = ((Artifact) bean).getId();
}
else {
EditedArtifactStorage sessionBean = (EditedArtifactStorage)httpServletRequest.getSession().getAttribute(
EditedArtifactStorage.EDITED_ARTIFACT_STORAGE_SESSION_KEY);
if ( sessionBean != null ) {
root = getStructuredArtifactDefinitionManager().createFormViewXml(
(Artifact) sessionBean.getRootArtifact(), null);
replaceNodes(root, bean, sessionBean);
paramsMap.put("subForm", "true");
homeType = getHomeType(sessionBean.getRootArtifact());
id = sessionBean.getRootArtifact().getId();
}
else {
return new javax.xml.transform.dom.DOMSource();
}
}
if (id != null) {
paramsMap.put("edit", "true");
paramsMap.put(FormHelper.XSL_ARTIFACT_ID, id.getValue());
}
httpServletRequest.setAttribute(STYLESHEET_LOCATION,
getStructuredArtifactDefinitionManager().getTransformer(homeType, readOnly));
Errors errors = BindingResultUtils.getBindingResult(map, "bean");
if (errors != null && errors.hasErrors()) {
Element errorsElement = new Element("errors");
List errorsList = errors.getAllErrors();
for (Iterator i=errorsList.iterator();i.hasNext();) {
Element errorElement = new Element("error");
ObjectError error = (ObjectError) i.next();
if (error instanceof FieldError) {
FieldError fieldError = (FieldError) error;
errorElement.setAttribute("field", fieldError.getField());
Element rejectedValue = new Element("rejectedValue");
if (fieldError.getRejectedValue() != null) {
rejectedValue.addContent(fieldError.getRejectedValue().toString());
}
errorElement.addContent(rejectedValue);
}
Element message = new Element("message");
message.addContent(context.getMessage(error, getResourceLoader().getLocale()));
errorElement.addContent(message);
errorsElement.addContent(errorElement);
}
root.addContent(errorsElement);
}
if (httpServletRequest.getParameter("success") != null) {
Element success = new Element("success");
success.setAttribute("messageKey", httpServletRequest.getParameter("success"));
root.addContent(success);
}
if (toolSession.getAttribute(ResourceEditingHelper.CUSTOM_CSS) != null) {
Element uri = new Element("uri");
uri.setText((String) toolSession.getAttribute(ResourceEditingHelper.CUSTOM_CSS));
root.getChild("css").addContent(uri);
uri.setAttribute("order", "100");
}
if (toolSession.getAttribute(FormHelper.FORM_STYLES) != null) {
List styles = (List) toolSession.getAttribute(FormHelper.FORM_STYLES);
int index = 101;
for (Iterator<String> i=styles.iterator();i.hasNext();) {
Element uri = new Element("uri");
uri.setText(i.next());
root.getChild("css").addContent(uri);
uri.setAttribute("order", "" + index);
index++;
}
}
Document doc = new Document(root);
return new JDOMSource(doc);
}
protected String getHomeType(Artifact bean) {
if (bean.getHome().getType() == null) {
return "new bean";
}
else if (bean.getHome().getType().getId() == null) {
return "new bean";
}
return bean.getHome().getType().getId().getValue();
}
protected void replaceNodes(Element root, ElementBean bean, EditedArtifactStorage sessionBean) {
Element structuredData = root.getChild("formData").getChild("artifact").getChild("structuredData");
structuredData.removeContent();
structuredData.addContent((Element)bean.getBaseElement().clone());
Element schema = root.getChild("formData").getChild("artifact").getChild("schema");
Element schemaRoot = schema.getChild("element");
StringTokenizer st = new StringTokenizer(sessionBean.getCurrentPath(), "/");
Element newRoot = schemaRoot;
while (st.hasMoreTokens()) {
String schemaName = st.nextToken();
List children = newRoot.getChild("children").getChildren("element");
for (Iterator i=children.iterator();i.hasNext();) {
Element schemaElement = (Element) i.next();
if (schemaName.equals(schemaElement.getAttributeValue("name"))) {
newRoot = schemaElement;
break;
}
}
}
schema.removeChild("element");
schema.addContent(newRoot.detach());
}
protected Map getParameters(HttpServletRequest request) {
Map params = super.getParameters(request);
if (params == null) {
params = new Hashtable();
}
if (ToolManager.getCurrentPlacement() != null) {
params.put("panelId", Web.escapeJavascript("Main" + ToolManager.getCurrentPlacement().getId()));
params.put(FormHelper.XSL_SITE_ID, ToolManager.getCurrentPlacement().getContext());
}
if ( request.getAttribute(STYLESHEET_PARAMS) != null )
params.putAll((Map) request.getAttribute(STYLESHEET_PARAMS));
if ( request.getAttribute(STYLESHEET_LOCATION) != null )
params.put(STYLESHEET_LOCATION, request.getAttribute(STYLESHEET_LOCATION));
return params;
}
/**
* Perform the actual transformation, writing to the given result.
* @param source the Source to transform
* @param parameters a Map of parameters to be applied to the stylesheet
* @param result the result to write to
* @throws Exception we let this method throw any exception; the
* AbstractXlstView superclass will catch exceptions
*/
protected void doTransform(Source source, Map parameters, Result result, String encoding)
throws Exception {
InputStream stylesheetLocation = null;
// Nulls gets logged by getTransformer, so don't bother logging again.
if (parameters != null)
stylesheetLocation = (InputStream) parameters.get(STYLESHEET_LOCATION);
Transformer trans = getTransformer(stylesheetLocation);
// Explicitly apply URIResolver to every created Transformer.
if (getUriResolver() != null) {
trans.setURIResolver(getUriResolver());
}
// Apply any subclass supplied parameters to the transformer.
if (parameters != null) {
for (Iterator it = parameters.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
trans.setParameter(entry.getKey().toString(), entry.getValue());
}
if (logger.isDebugEnabled()) {
logger.debug("Added parameters [" + parameters + "] to transformer object");
}
}
// Specify default output properties.
//trans.setOutputProperty(OutputKeys.ENCODING, encoding);
trans.setOutputProperty(OutputKeys.INDENT, "yes");
// Xalan-specific, but won't do any harm in other XSLT engines.
trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
// Perform the actual XSLT transformation.
try {
trans.transform(source, result);
if (logger.isDebugEnabled()) {
logger.debug("XSLT transformed with stylesheet [" + stylesheetLocation + "]");
}
}
catch (TransformerException ex) {
throw new NestedServletException("Couldn't perform transform with stylesheet [" +
stylesheetLocation + "] in XSLT view with name [" + getBeanName() + "]", ex);
}
}
protected Transformer getTransformer(InputStream transformer) throws TransformerException {
try {
if ( transformer == null ) {
logger.warn(this+".getTransformer passed null InputStream");
return getTransformerFactory().newTransformer();
}
else {
return getTransformerFactory().newTransformer(new StreamSource(transformer));
}
}
catch (TransformerConfigurationException ex) {
logger.warn("Couldn't create XSLT transformer for stylesheet in XSLT view with name [" + getBeanName() + "]", ex);
return getTransformerFactory().newTransformer();
}
}
protected StructuredArtifactDefinitionManager getStructuredArtifactDefinitionManager() {
return (StructuredArtifactDefinitionManager)
ComponentManager.get("structuredArtifactDefinitionManager");
}
public String getBundleLocation() {
return bundleLocation;
}
public void setBundleLocation(String bundleLocation) {
this.bundleLocation = bundleLocation;
setResourceLoader(new ResourceLoader(bundleLocation));
}
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public String getUriResolverBeanName() {
return uriResolverBeanName;
}
public void setUriResolverBeanName(String uriResolverBeanName) {
this.uriResolverBeanName = uriResolverBeanName;
}
public URIResolver getUriResolver() {
return uriResolver;
}
public void setUriResolver(URIResolver uriResolver) {
this.uriResolver = uriResolver;
getTransformerFactory().setURIResolver(uriResolver);
}
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
protected void dumpDocument(Element node) {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
transformer.transform( new JDOMSource(node), new StreamResult(System.out) );
}
catch ( Exception e )
{
e.printStackTrace();
}
}
}