/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/shared/mgt/home/StructuredArtifactHome.java $ * $Id: StructuredArtifactHome.java 120216 2013-02-18 19:44:04Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2004, 2005, 2006, 2007, 2008 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.mgt.home; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; import java.util.*; import org.jdom.*; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.metaobj.shared.mgt.*; import org.sakaiproject.metaobj.shared.model.*; import org.sakaiproject.metaobj.shared.ArtifactFinder; import org.sakaiproject.metaobj.utils.Config; import org.sakaiproject.metaobj.utils.xml.SchemaNode; import org.sakaiproject.metaobj.worksite.intf.WorksiteAware; import org.sakaiproject.metaobj.worksite.mgt.WorksiteManager; import org.sakaiproject.metaobj.registry.FormResourceType; import org.sakaiproject.entity.api.ResourcePropertiesEdit; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.content.api.ContentHostingService; import org.sakaiproject.content.api.ContentResourceEdit; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.exception.*; import org.sakaiproject.util.ResourceLoader; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; /** * Created by IntelliJ IDEA. * User: John Ellis * Date: May 17, 2004 * Time: 2:52:00 PM * To change this template use File | Settings | File Templates. */ public class StructuredArtifactHome extends XmlElementHome implements WorksiteAware, ApplicationContextAware, Comparable, StreamableObjectHome { protected final static org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory.getLog(StructuredArtifactHome.class); private boolean modifiable = false; private PresentableObjectHome repositoryHelper; private IdManager idManager; private String siteId; private ArtifactFinder artifactFinder; private ResourceLoader rl = new ResourceLoader("org.sakaiproject.metaobj.messages"); private static final MessageFormat format = new MessageFormat("<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL={0}/member/viewArtifact.osp?artifactId={1}&artifactType={2}&pid={3}\">"); public Artifact store(Artifact object) throws PersistenceException { Id id = object.getId(); if (id == null) { return addArtifact(object); } else { return updateArtifact(object); } } protected Artifact updateArtifact(Artifact object) throws PersistenceException { StructuredArtifact artifact = (StructuredArtifact) object; String resourceId = getContentHostingService().resolveUuid(artifact.getId().getValue()); try { ContentResourceEdit resourceEdit = getContentHostingService().editResource(resourceId); resourceEdit.setContent(getInfoBytes(object)); resourceEdit.getProperties().addProperty( ResourceProperties.PROP_DISPLAY_NAME, object.getDisplayName()); getContentHostingService().commitResource(resourceEdit); } catch (PermissionException e) { throw new PersistenceException(e, rl.getString("perm_file_err"), null, null); } catch (IdUnusedException e) { throw new PersistenceException(e, rl.getString("unknown_file_err"), null, null); } catch (TypeException e) { throw new PersistenceException(e, rl.getString("unknown_file_err"), null, null); } catch (InUseException e) { throw new PersistenceException(e, rl.getString("unknown_file_err"), null, null); } catch (ServerOverloadException e) { throw new PersistenceException(e, rl.getString("unknown_file_err"), null, null); } catch (OverQuotaException e) { throw new PersistenceException(e, rl.getString("quota_file_err"), null, null); } return object; } public StructuredArtifact load(ContentResource resource, Id artifactId) { try { Agent resourceOwner = getAgentManager().getAgent( resource.getProperties().getProperty(ResourceProperties.PROP_CREATOR)); SAXBuilder builder = new SAXBuilder(); builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // SAK-23245 Document doc = builder.build(resource.streamContent()); StructuredArtifact xmlObject = new StructuredArtifact(doc.getRootElement(), getSchema().getChild(getRootNode())); xmlObject.setBaseResource(resource); xmlObject.setId(artifactId); xmlObject.setDisplayName( (String) resource.getProperties().get( resource.getProperties().getNamePropDisplayName())); xmlObject.setHome(this); xmlObject.setOwner(resourceOwner); return xmlObject; } catch (Exception e) { throw new PersistenceException(e, "", null, null); } } public StructuredArtifact load(ContentResource resource) { Id artifactId = getIdManager().getId(getContentHostingService().getUuid(resource.getId())); return load(resource, artifactId); } private AgentManager getAgentManager() { return (AgentManager) ComponentManager.get("agentManager"); } public Artifact load(Id id) throws PersistenceException { /** todo NodeMetadata node = getNodeMetadataService().getNode(id); SAXBuilder builder = new SAXBuilder(); try { Document doc = builder.build( getStreamStore().load(node, RepositoryNode.TECH_MD_TYPE)); StructuredArtifact xmlObject = new StructuredArtifact(doc.getRootElement(), getSchema().getChild(getRootNode())); xmlObject.setId(id); xmlObject.setDisplayName(node.getName()); xmlObject.setHome(this); xmlObject.setOwner(node.getOwner()); return xmlObject; } catch (Exception e) { throw new SchemaInvalidException(e); } */ return null; } public void remove(Artifact object) throws PersistenceException { /** getStreamStore().delete(getNodeMetadata(object.getId())); getNodeMetadataService().delete(object.getId()); */ } public Artifact cloneArtifact(Artifact copy, String newName) throws PersistenceException { /** todo NodeMetadata oldMetadata = getNodeMetadataService().getNode(copy.getId()); String origName = oldMetadata.getName(); oldMetadata.setName(newName); NodeMetadata newMetadata = getNodeMetadataService().copyNode(oldMetadata); oldMetadata.setName(origName); getStreamStore().copyStreams(getNodeMetadataService().getNode(copy.getId()), newMetadata); return new LightweightArtifact(this, newMetadata); */ return null; } protected Artifact addArtifact(Artifact object) throws PersistenceException { StructuredArtifact artifact = (StructuredArtifact) object; String newFileId = artifact.getParentFolder() + getIdManager().createId().getValue(); try { ContentResourceEdit resource = getContentHostingService().addResource(newFileId); resource.setResourceType(FormResourceType.FORM_TYPE_ID); ResourcePropertiesEdit resourceProperties = resource.getPropertiesEdit(); resourceProperties.addProperty (ResourceProperties.PROP_DISPLAY_NAME, object.getDisplayName()); resourceProperties.addProperty (ResourceProperties.PROP_DESCRIPTION, object.getDisplayName()); resourceProperties.addProperty(ResourceProperties.PROP_CONTENT_ENCODING, "UTF-8"); resourceProperties.addProperty(ResourceProperties.PROP_STRUCTOBJ_TYPE, getTypeId()); resourceProperties.addProperty(ResourceProperties.PROP_IS_COLLECTION, Boolean.FALSE.toString()); resourceProperties.addProperty(ContentHostingService.PROP_ALTERNATE_REFERENCE, org.sakaiproject.metaobj.shared.mgt.MetaobjEntityManager.METAOBJ_ENTITY_PREFIX); resource.setContent(getInfoBytes(artifact)); resource.setContentType("application/x-osp"); getContentHostingService().commitResource(resource); artifact.setId(getIdManager().getId(getContentHostingService().getUuid(newFileId))); return object; } catch (PermissionException e) { throw new PersistenceException("No permission to write file", null, null); } catch (IdUsedException e) { throw new PersistenceException("Resource exists {0}", new Object[]{artifact.getDisplayName()}, "displayName"); } catch (IdInvalidException e) { throw new PersistenceException("Invalid name {0}", new Object[]{artifact.getDisplayName()}, "displayName"); } catch (InconsistentException e) { throw new PersistenceException("Invalid name {0}", new Object[]{artifact.getDisplayName()}, "displayName"); } catch (ServerOverloadException e) { throw new PersistenceException(e, "Unknown file error", null, null); } catch (OverQuotaException e) { throw new PersistenceException("Over quota", null, null); } } /** * protected InputStream getFileStream(StructuredArtifact xmlObject) { * StringBuilder sb = new StringBuilder(); * <p/> * format.format(new Object[]{getHostBaseUrl(), xmlObject.getId().getValue(), * getType().getId().getValue(), * getWorksiteManager().getCurrentWorksiteId() }, * sb, new FieldPosition(0)); * logger.debug("redirecting to: " + sb.toString()); * InputStream is = new ByteArrayInputStream(sb.toString().getBytes()); * <p/> * return is; * } */ protected byte[] getInfoBytes(Artifact object) throws PersistenceException { XMLOutputter outputter = new XMLOutputter(); StructuredArtifact xmlObject = (StructuredArtifact) object; ByteArrayOutputStream os = new ByteArrayOutputStream(); try { Format format = Format.getPrettyFormat(); outputter.setFormat(format); outputter.output(xmlObject.getBaseElement(), os); return os.toByteArray(); } catch (IOException e) { throw new PersistenceException(e, "Unable to write object", null, null); } } public byte[] getBytes(StructuredArtifact artifact) { return getInfoBytes(artifact); } protected InputStream getInfoStream(Artifact object) throws PersistenceException { return new ByteArrayInputStream(getInfoBytes(object)); } public String getHostBaseUrl() { return Config.getInstance().getProperties().getProperty("baseUrl"); } public Element getArtifactAsXml(Artifact art) { StructuredArtifact sa = (StructuredArtifact) art; Element root = new Element("artifact"); root.addContent(getMetadata(sa)); Element data = new Element("structuredData"); Element baseElement = (Element) sa.getBaseElement().clone(); data.addContent(baseElement); root.addContent(data); Element schemaData = new Element("schema"); schemaData.addContent(createInstructions()); try { schemaData.addContent(addSchemaInfo(getRootSchema())); } catch (JDOMException e) { throw new RuntimeException("Invalid schema info"); } // for now, don't call this... we may add this when // we need to store id rather than ref... for now, keep // this backward compatible with existing templates // replaceFileRefs(schemaData, data); root.addContent(schemaData); return root; } protected void replaceFileRefs(Element schemaData, Element data) { try { XPath fileAttachPath = XPath.newInstance(".//element[@type='xs:anyURI']"); List fileElements = fileAttachPath.selectNodes(schemaData); for (Iterator i=fileElements.iterator();i.hasNext();) { processFileElement((Element)i.next(), data); } } catch (JDOMException e) { throw new RuntimeException(e); } } protected void processFileElement(Element element, Element data) throws JDOMException { String path = ""; while (element != null) { if (path.length() > 0) { path = "/" + path; } path = element.getAttributeValue("name") + path; element = element.getParentElement(); if (element != null) { element = element.getParentElement(); } } List fileElements = XPath.selectNodes(data, path); for (Iterator i=fileElements.iterator();i.hasNext();) { Element filePath = (Element) i.next(); String fileId = filePath.getTextTrim(); Artifact fileArt = getArtifactFinder().load(getIdManager().getId(fileId)); PresentableObjectHome home = (PresentableObjectHome) fileArt.getHome(); Element file = home.getArtifactAsXml(fileArt); file.setName("artifact"); filePath.addContent(file); } } protected Element getMetadata(Artifact art) { Element root = new Element("metaData"); if (art.getId() != null) { root.addContent(createNode("id", art.getId().getValue())); } root.addContent(createNode("displayName", art.getDisplayName())); Element type = new Element("type"); root.addContent(type); type.addContent(createNode("id", "file")); type.addContent(createNode("description", "file")); ContentResource contentResource = ((StructuredArtifact)art).getBaseResource(); if (contentResource != null) { Element repositoryNode = ContentHostingUtil.createRepoNode(contentResource); root.addContent(repositoryNode); } return root; } protected Element createNode(String name, String value) { Element newNode = new Element(name); newNode.addContent(value); return newNode; } protected Element createInstructions() { Element instructions = new Element("instructions"); instructions.setContent(new CDATA(getInstruction())); return instructions; } protected Element addSchemaInfo(SchemaNode schema) throws JDOMException { Element schemaElement = new Element("element"); schemaElement.setAttribute("name", schema.getName()); if (schema.getType() != null && schema.getType().getBaseType() != null) { schemaElement.setAttribute("type", schema.getType().getBaseType()); } schemaElement.setAttribute("minOccurs", schema.getMinOccurs() + ""); schemaElement.setAttribute("maxOccurs", schema.getMaxOccurs() + ""); Element annotation = schema.getSchemaElement().getChild("annotation", schema.getSchemaElement().getNamespace()); if (annotation != null) { schemaElement.addContent(i18nFilterAnnotations(annotation)); } Element simpleType = schema.getSchemaElement().getChild("simpleType", schema.getSchemaElement().getNamespace()); if (simpleType != null) { schemaElement.addContent((Content) simpleType.clone()); } else if (schema.getSchemaElement().getAttribute("type") != null) { Element externalType = getSimpleType(schema.getSchemaElement().getAttributeValue("type"), schema.getSchemaElement().getDocument().getRootElement()); if (externalType != null) { schemaElement.addContent((Content) externalType.clone()); } } List children = schema.getChildren(); Element childElement = new Element("children"); boolean found = false; for (Iterator i = children.iterator(); i.hasNext();) { childElement.addContent(addSchemaInfo((SchemaNode) i.next())); found = true; } if (found) { schemaElement.addContent(childElement); } return schemaElement; } protected Element getSimpleType(String attribute, Element rootElement) throws JDOMException { XPath docPath = XPath.newInstance("xs:simpleType[@name='"+attribute+"']"); List elements = docPath.selectNodes(rootElement); if (elements.size() == 0) { return null; } return (Element) elements.get(0); } protected Content i18nFilterAnnotations(Element content) throws JDOMException { Locale locale = rl.getLocale(); Map<String, Element> documentElements = new Hashtable<String, Element>(); filterElements(documentElements, content, null); filterElements(documentElements, content, locale.getLanguage()); filterElements(documentElements, content, locale.getLanguage() + "_" + locale.getCountry()); filterElements(documentElements, content, locale.getLanguage() + "_" + locale.getCountry() + "_" + locale.getVariant()); Element returned = (Element) content.clone(); returned.removeChildren("documentation", content.getNamespace()); for (Iterator<Element> i=documentElements.values().iterator();i.hasNext();) { returned.addContent((Content) i.next().clone()); } return returned; } protected void filterElements(Map<String, Element> documentElements, Element content, String lang) throws JDOMException { XPath docPath; if (lang == null) { docPath = XPath.newInstance("xs:documentation[not(@xml:lang)]"); } else { docPath = XPath.newInstance("xs:documentation[lang('"+lang+"')]"); } List elements = docPath.selectNodes(content); for (Iterator<Element> i=elements.iterator();i.hasNext();) { Element child = i.next(); String source = child.getAttributeValue("source"); if (source != null) { documentElements.put(child.getAttributeValue("source"), child); } } } public String getSiteId() { return siteId; } public void setSiteId(String siteId) { this.siteId = siteId; } public boolean isModifiable() { return modifiable; } /** * @return true if SAD is global (available to all worksites) */ public boolean isGlobal() { return (getSiteId() == null || getSiteId().length() == 0); } public PresentableObjectHome getRepositoryHelper() { return repositoryHelper; } public void setRepositoryHelper(PresentableObjectHome repositoryHelper) { this.repositoryHelper = repositoryHelper; } public IdManager getIdManager() { if (idManager == null) { setIdManager((IdManager) ComponentManager.get("idManager")); } return idManager; } public void setIdManager(IdManager idManager) { this.idManager = idManager; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { setIdManager((IdManager) applicationContext.getBean("idManager")); setRepositoryHelper((PresentableObjectHome) applicationContext.getBean("repositoryHelper")); } public int compareTo(Object o) { StructuredArtifactHome that = (StructuredArtifactHome) o; return this.getType().getDescription().toLowerCase().compareTo(that.getType().getDescription().toLowerCase()); } public InputStream getStream(Id artifactId) { try { StructuredArtifact artifact = (StructuredArtifact) load(artifactId); return getInfoStream(artifact); } catch (PersistenceException e) { throw new RuntimeException(e); } } public boolean isSystemOnly() { return false; } protected WorksiteManager getWorksiteManager() { return (WorksiteManager) ComponentManager.getInstance().get(WorksiteManager.class.getName()); } public ArtifactFinder getArtifactFinder() { if (artifactFinder == null) { setArtifactFinder((ArtifactFinder) ComponentManager.get( "org.sakaiproject.metaobj.shared.ArtifactFinder.fileArtifact")); } return artifactFinder; } public void setArtifactFinder(ArtifactFinder artifactFinder) { this.artifactFinder = artifactFinder; } protected ContentHostingService getContentHostingService() { return (ContentHostingService)ComponentManager.get( "org.sakaiproject.content.api.ContentHostingService"); } }