/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/shared/mgt/impl/StructuredArtifactDefinitionManagerImpl.java $ * $Id: StructuredArtifactDefinitionManagerImpl.java 130481 2013-10-15 17:36:54Z dsobiera@indiana.edu $ *********************************************************************************** * * 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.impl; import org.jdom.CDATA; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; import org.jdom.xpath.XPath; import org.sakaiproject.authz.cover.FunctionManager; import org.sakaiproject.authz.api.SecurityAdvisor; import org.sakaiproject.authz.api.SecurityService; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.content.api.ContentCollection; import org.sakaiproject.content.api.ContentHostingService; import org.sakaiproject.content.api.ContentResource; import org.sakaiproject.content.api.ContentCollectionEdit; import org.sakaiproject.exception.*; import org.sakaiproject.metaobj.security.AllowChildrenMapSecurityAdvisor; import org.sakaiproject.metaobj.security.AllowMapSecurityAdvisor; import org.sakaiproject.metaobj.security.AuthenticationManager; import org.sakaiproject.metaobj.security.AuthorizationFacade; import org.sakaiproject.metaobj.shared.ArtifactFinder; import org.sakaiproject.metaobj.shared.DownloadableManager; import org.sakaiproject.metaobj.shared.SharedFunctionConstants; import org.sakaiproject.metaobj.shared.mgt.*; import org.sakaiproject.metaobj.shared.mgt.home.StructuredArtifactDefinition; import org.sakaiproject.metaobj.shared.mgt.home.StructuredArtifactHomeInterface; import org.sakaiproject.metaobj.shared.model.*; import org.sakaiproject.metaobj.utils.xml.SchemaFactory; import org.sakaiproject.metaobj.utils.xml.SchemaNode; import org.sakaiproject.metaobj.worksite.mgt.WorksiteManager; import org.sakaiproject.service.legacy.resource.DuplicatableToolService; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.tool.api.Placement; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.ResourceLoader; import org.sakaiproject.event.cover.NotificationService; import org.sakaiproject.entity.api.Reference; import org.sakaiproject.entity.api.ResourcePropertiesEdit; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.entity.cover.EntityManager; import org.sakaiproject.thread_local.cover.ThreadLocalManager; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import javax.xml.transform.TransformerException; import java.io.*; import java.util.*; import java.util.zip.*; /** * @author chmaurer * @author jbush */ public class StructuredArtifactDefinitionManagerImpl extends HibernateDaoSupport implements StructuredArtifactDefinitionManager, DuplicatableToolService, DownloadableManager, FormConsumer { static final private String DOWNLOAD_FORM_ID_PARAM = "formId"; private static final String SYSTEM_COLLECTION_ID = "/system/"; static final private String IMPORT_BASE_FOLDER_ID = "importedForms"; private static final String HAS_HOMES_TAG = "org.sakaiproject.metaobj.hasHomes"; private AuthorizationFacade authzManager = null; private IdManager idManager; private WorksiteManager worksiteManager; private ContentHostingService contentHosting; private ToolManager toolManager; private List globalSites; private List globalSiteTypes; private ArtifactFinder artifactFinder; private ArtifactFinder structuredArtifactFinder; private int expressionMax = 999; private boolean replaceViews = true; private List formConsumers; private SecurityService securityService; private boolean autoDdl = true; private boolean enableLocksConversion = true; private static ResourceLoader messages = new ResourceLoader( "org.sakaiproject.metaobj.messages"); public StructuredArtifactDefinitionManagerImpl() { } public Map getHomes() { Map<String, StructuredArtifactDefinitionBean> returnMap = new HashMap<String, StructuredArtifactDefinitionBean>(); List list = findHomes(); for (Iterator iter = list.iterator(); iter.hasNext();) { StructuredArtifactDefinitionBean sad = (StructuredArtifactDefinitionBean) iter.next(); returnMap.put(sad.getId().getValue(), sad); } return returnMap; } /** * @param worksiteId * @return a map with all worksite and global homes */ public Map getWorksiteHomes(Id worksiteId) { return getWorksiteHomes(worksiteId, false); } public Map getWorksiteHomes(Id worksiteId, boolean includeHidden) { return getWorksiteHomes(worksiteId, null, includeHidden); } public Map getWorksiteHomes(Id worksiteId, String currentUserId, boolean includeHidden) { Map<String, StructuredArtifactDefinitionBean> returnMap = new HashMap<String, StructuredArtifactDefinitionBean>(); List<StructuredArtifactDefinitionBean> list = findGlobalHomes(); if (currentUserId == null) list.addAll(findHomes(worksiteId, includeHidden, false)); else list.addAll(findAvailableHomes(worksiteId, currentUserId, includeHidden, false)); for (Iterator iter = list.iterator(); iter.hasNext();) { StructuredArtifactDefinitionBean sad = (StructuredArtifactDefinitionBean) iter.next(); returnMap.put(sad.getId().getValue(), sad); } return returnMap; } /** * @return list of published sads or sads owned by current user */ public List findHomes() { return findHomes(true); } public List findHomes(boolean includeHidden) { return findHomes(true, includeHidden); } public List findHomes(boolean includeGlobal, boolean includeHidden) { // only for the appropriate worksites List sites = getWorksiteManager().getUserSites(); List<StructuredArtifactDefinitionBean> returned = new ArrayList<StructuredArtifactDefinitionBean>(); while (sites.size() > getExpressionMax()) { returned.addAll(findHomes(sites.subList(0, getExpressionMax() - 1), false, includeHidden)); sites.subList(0, getExpressionMax() - 1).clear(); } returned.addAll(findHomes(sites, includeGlobal, includeHidden)); return returned; } public Map findCategorizedHomes(boolean includeHidden) { List homes = findHomes(false, includeHidden); Map<String, List> catHomes = new Hashtable<String, List>(); for (Iterator<StructuredArtifactDefinitionBean> i = homes.iterator();i.hasNext();) { StructuredArtifactDefinitionBean bean = i.next(); List beanList = catHomes.get(bean.getSiteId()); if (beanList == null) { beanList = new ArrayList(); catHomes.put(bean.getSiteId(), beanList); } beanList.add(bean); } return catHomes; } protected List findHomes(List sites, boolean includeGlobal, boolean includeHidden) { String query; Object[] params; if (includeGlobal) { query = "from StructuredArtifactDefinitionBean where ((globalState = ? or (owner = ? and siteId = null)) or " + "((owner = ? or siteState = ?) and siteId in ("; params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), getAuthManager().getAgent(),getAuthManager().getAgent(), new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED)}; } else { query = "from StructuredArtifactDefinitionBean where ((globalState != ? and (owner = ? or siteState = ?) and siteId in ("; params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), getAuthManager().getAgent(), new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED)}; } StringBuffer bufQuery = new StringBuffer(); for (Iterator i = sites.iterator(); i.hasNext();) { Site site = (Site) i.next(); bufQuery.append("'" + site.getId() + "',"); } query += bufQuery.toString(); query += "''))"; if (includeHidden) { query += ")"; } else { query += ") and systemOnly != true"; } return getHibernateTemplate().find(query, params); } /** * Find all homes * @return */ private List<StructuredArtifactDefinitionBean> findAllHomes() { String query = "from StructuredArtifactDefinitionBean"; return getHibernateTemplate().find(query); } public List findBySchema(ContentResource resource) { try { Object[] params = new Object[]{resource.getContent()}; return getHibernateTemplate().findByNamedQuery("findBySchema", params); } catch (ServerOverloadException e) { } return new ArrayList(); } /** * @return list of all published globals or global sad owned by current user or waiting for approval */ public List findGlobalHomes() { Object[] params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), getAuthManager().getAgent()}; return getHibernateTemplate().findByNamedQuery("findGlobalHomes", params); } /** * @param currentWorksiteId * @return list of globally published sads or published sad in currentWorksiteId or sads in * currentWorksiteId owned by current user */ public List findHomes(Id currentWorksiteId) { String queryName = "findHomes"; return findHomes(currentWorksiteId, queryName); } protected List findHomes(Id currentWorksiteId, String queryName) { Object[] params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), currentWorksiteId.getValue(), getAuthManager().getAgent(), new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED)}; return getHibernateTemplate().findByNamedQuery(queryName, params); } public List findHomes(Id currentWorksiteId, boolean includeHidden) { return findHomes(currentWorksiteId, includeHidden, true); } public List findHomes(Id currentWorksiteId, boolean includeHidden, boolean includeGlobal) { if (includeGlobal) { return findHomes(currentWorksiteId, includeHidden?"findHomesIncludeHidden":"findHomes"); } else { return findHomes(currentWorksiteId, includeHidden?"findWorksiteHomesIncludeHidden":"findWorksiteHomes"); } } public List<StructuredArtifactDefinitionBean> findAvailableHomes(Id currentWorksiteId, String currentUserId, boolean includeHidden, boolean includeGlobal) { List<StructuredArtifactDefinitionBean> homes = new ArrayList<StructuredArtifactDefinitionBean>(); List<StructuredArtifactDefinitionBean> filteredHomes = new ArrayList<StructuredArtifactDefinitionBean>(); String queryName = ""; if (includeGlobal) { queryName = includeHidden?"findAvailableHomesIncludeHidden":"findAvailableHomes"; } else { queryName = includeHidden?"findAvailableWorksiteHomesIncludeHidden":"findAvailableWorksiteHomes"; } Object[] params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), currentWorksiteId.getValue(),}; homes = getHibernateTemplate().findByNamedQuery(queryName, params); String siteRef = getWorksiteManager().getSite(currentWorksiteId.getValue()).getReference(); boolean canEdit = getSecurityService().unlock(SharedFunctionConstants.EDIT_ARTIFACT_DEF, siteRef); for (StructuredArtifactDefinitionBean sadb : homes) { // check for perms as well as ownership Agent owner = sadb.getOwner(); if (canEdit || owner.getId().getValue().equals(currentUserId) || sadb.isPublished()) { filteredHomes.add(sadb); } } return filteredHomes; } public StructuredArtifactDefinitionBean loadHome(String type) { return loadHome(getIdManager().getId(type)); } public StructuredArtifactDefinitionBean loadHome(Id id) { return (StructuredArtifactDefinitionBean) getHibernateTemplate().get(StructuredArtifactDefinitionBean.class, id); } public StructuredArtifactDefinitionBean loadHomeByExternalType(String externalType, Id worksiteId) { List homes = (List) getHibernateTemplate().findByNamedQuery("loadHomeByExternalType", new Object[]{ externalType, new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), worksiteId.getValue()}); if (homes.size() == 0) { return null; } if (homes.size() == 1) { return (StructuredArtifactDefinitionBean) homes.get(0); } else { for (Iterator i = homes.iterator(); i.hasNext();) { StructuredArtifactDefinitionBean def = (StructuredArtifactDefinitionBean) i.next(); if (def.getSiteId() != null) { if (def.getSiteId().equals(worksiteId.getValue())) { return def; } } } return (StructuredArtifactDefinitionBean) homes.get(0); } } public StructuredArtifactDefinitionBean save(StructuredArtifactDefinitionBean bean) { return save(bean, true); } public StructuredArtifactDefinitionBean save(StructuredArtifactDefinitionBean bean, boolean updateModTime) { if (!sadExists(bean)) { if (updateModTime) { bean.setModified(new Date(System.currentTimeMillis())); } StructuredArtifactDefinition sad = null; try { if (bean.getId() == null) { loadNode(bean); bean.setCreated(new Date(System.currentTimeMillis())); } else if (bean.getSchemaFile() != null) { loadNode(bean); sad = new StructuredArtifactDefinition(bean); updateExistingArtifacts(sad); } } catch (Exception e) { throw new OspException("Invalid schema", e); } sad = new StructuredArtifactDefinition(bean); bean.setExternalType(sad.getExternalType()); bean.setInstruction(sanitizeInstructions(bean.getInstruction())); bean.setSchemaHash(calculateSchemaHash(bean)); getHibernateTemplate().saveOrUpdate(bean); lockSADFiles(bean); // getHibernateTemplate().saveOrUpdateCopy(bean); } else { throw new PersistenceException("Form name {0} exists", new Object[]{bean.getDescription()}, "description"); } return bean; } /** * There have been issues with hashcodes of the instructions field due to things like carriage returns that seem to get * converted during the form export/import process. Then, on import, a form seems to think it's different from the global form * and creates a new local (site) form. So, this method will pre-convert stuff so that when imported, it'll match up with the original. * @param instructions * @return */ private String sanitizeInstructions(String instructions) { String result = instructions; if (instructions != null) { logger.debug("Original instruction hashcode: " + instructions.hashCode()); Element rootNode = new Element("metaobjForm"); Element attrNode = new Element("instruction"); attrNode.addContent(new CDATA(instructions)); rootNode.addContent(attrNode); Document doc = new Document(rootNode); String docStr = (new XMLOutputter()).outputString(doc); SAXBuilder builder = new SAXBuilder(); try { byte[] bytes = docStr.getBytes(); // for some reason the SAX Builder sometimes won't recognize //these bytes as correct utf-8 characters. So we want to read it in //as utf-8 and spot it back out as utf-8 and this will correct the //bytes. In my test, it added two bytes somewhere in the string. //and adding those two bytes made the string work for saxbuilder. // bytes = (new String(bytes, "UTF-8")).getBytes("UTF-8"); Document document = builder.build(new ByteArrayInputStream(bytes)); Element topNode = document.getRootElement(); result = new String(topNode.getChildTextTrim("instruction").getBytes(), "UTF-8"); } catch (Exception jdome) { logger.error(".sanitizeInstructions", jdome); } logger.debug("Sanitized instruction hashcode: " + result.hashCode()); } return result; } /** * remove all the locks associated with this template */ protected void clearLocks(Id id) { getContentHosting().removeAllLocks(id.getValue()); } /** * locks all the files associated with this template. * @param template */ protected void lockSADFiles(StructuredArtifactDefinitionBean bean){ clearLocks(bean.getId()); if (bean.getAlternateCreateXslt() != null) { getContentHosting().lockObject(bean.getAlternateCreateXslt().getValue(), bean.getId().getValue(), "saving a form definition", true); } if (bean.getAlternateViewXslt() != null) { getContentHosting().lockObject(bean.getAlternateViewXslt().getValue(), bean.getId().getValue(), "saving a form definition", true); } } public void delete(StructuredArtifactDefinitionBean sad) { for (Iterator<FormConsumer> i=getFormConsumers().iterator();i.hasNext();) { if (i.next().checkFormConsumption(sad.getId())) { throw new PersistenceException("unable_to_delete_published", new Object[]{}, "siteState"); } } clearLocks(sad.getId()); getHibernateTemplate().delete(sad); } /** * {@inheritDoc} */ public Collection<FormConsumptionDetail> findFormUsage(StructuredArtifactDefinitionBean sad) { Collection<FormConsumptionDetail> results = new ArrayList<FormConsumptionDetail>(); for (Iterator<FormConsumer> i=getFormConsumers().iterator(); i.hasNext();) { FormConsumer cons = (FormConsumer) i.next(); results.addAll(cons.getFormConsumptionDetails(sad.getId())); } return results; } /** * @return Returns the idManager. */ public IdManager getIdManager() { return idManager; } /** * @param idManager The idManager to set. */ public void setIdManager(IdManager idManager) { this.idManager = idManager; } public boolean isGlobal() { String siteId = getWorksiteManager().getCurrentWorksiteId().getValue(); return isGlobal(siteId); } protected boolean isGlobal(String siteId) { if (getGlobalSites().contains(siteId)) { return true; } Site site = getWorksiteManager().getSite(siteId); if (site.getType() != null && getGlobalSiteTypes().contains(site.getType())) { return true; } return false; } protected Site getCurrentSite() { String siteId = getWorksiteManager().getCurrentWorksiteId().getValue(); return getWorksiteManager().getSite(siteId); } public Collection getRootElements(StructuredArtifactDefinitionBean sad) { try { SchemaNode node = loadNode(sad); return node.getRootChildren(); } catch (Exception e) { throw new OspException("Invalid schema.", e); } } public void validateSchema(StructuredArtifactDefinitionBean sad) { SchemaNode node = null; try { node = loadNode(sad); } catch (Exception e) { throw new OspException("Invlid schema file.", e); } if (node == null) { throw new OspException("Invlid schema file."); } } public StructuredArtifactHomeInterface convertToHome(StructuredArtifactDefinitionBean sad) { return new StructuredArtifactDefinition(sad); } protected SchemaNode loadNode(StructuredArtifactDefinitionBean sad) throws TypeException, IdUnusedException, PermissionException, ServerOverloadException { if (sad.getSchemaFile() != null) { ContentResource resource = getContentHosting().getResource(sad.getSchemaFile().getValue()); sad.setSchema(resource.getContent()); } if (sad.getSchema() == null) { return null; } SchemaFactory schemaFactory = SchemaFactory.getInstance(); return schemaFactory.getSchema(new ByteArrayInputStream(sad.getSchema())); } protected boolean sadExists(StructuredArtifactDefinitionBean sad) throws PersistenceException { String query = "from StructuredArtifactDefinitionBean where description = ? "; List<Object> params = new ArrayList<Object>(); params.add(sad.getDescription()); if (sad.getId() != null) { query += " and id != ? "; params.add(sad.getId()); } if (sad.getSiteId() != null) { query += " and siteId = ? "; params.add(sad.getSiteId()); } else { query += " and siteId is null"; } List sads = getHibernateTemplate().find(query, params.toArray()); return sads.size() > 0; } /** * @param sad * @param artifact * @throws OspException if artifact doesn't validate */ protected void validateAfterTransform(StructuredArtifactDefinition sad, StructuredArtifact artifact) throws OspException { //TODO figure out how to do the validator // StructuredArtifactValidator validator = new StructuredArtifactValidator(); // artifact.setHome(sad); // Errors artifactErrors = new BindExceptionBase(artifact, "bean"); // validator.validate(artifact, artifactErrors); // if (artifactErrors.getErrorCount() > 0) { // StringBuilder buf = new StringBuilder(); // for (Iterator i=artifactErrors.getAllErrors().iterator();i.hasNext();){ // ObjectError error = (ObjectError) i.next(); // buf.append(error.toString() + " "); // } // throw new OspException(buf.toString()); // } } protected void saveAll(StructuredArtifactDefinition sad, Collection artifacts) { for (Iterator i = artifacts.iterator(); i.hasNext();) { StructuredArtifact artifact = (StructuredArtifact) i.next(); try { sad.store(artifact); } catch (PersistenceException e) { logger.error("problem saving artifact with id " + artifact.getId().getValue() + ":" + e); } } } /** * Uses the submitted xsl file to transform the existing artifacts into the schema. * This process puts the artifact home into system only start while is does its work. * This is necessary so that users won't be able to update artifacts while this is going on. * The system transforms every object in memory and validates before writing any artifact back out. * This way if something fails the existing data will stay intact. * <p/> * TODO possible memory issues * TODO all this work need to be atomic * * @param sad * @throws OspException */ protected void updateExistingArtifacts(StructuredArtifactDefinition sad) throws OspException { //if we don't have an xsl file and don't need one, return if (!sad.getRequiresXslFile()) { return; } if (sad.getRequiresXslFile() && (sad.getXslConversionFileId() == null || sad.getXslConversionFileId().getValue().length() == 0)) { throw new OspException("xsl conversion file required"); } // put artifact home in system only state while we do this work. // this along with repository authz prevents someone from updating an artifact // while this is going on StructuredArtifactDefinitionBean currentHome = this.loadHome(sad.getId()); boolean originalSystemOnlyState = currentHome.isSystemOnly(); currentHome.setSystemOnly(true); getHibernateTemplate().saveOrUpdate(currentHome); boolean finished = false; String type = sad.getType().getId().getValue(); Collection artifacts = getArtifactFinder().findByType(type); Collection<StructuredArtifact> modifiedArtifacts = new ArrayList<StructuredArtifact>(); // perform xsl transformations on existing artifacts try { for (Iterator i = artifacts.iterator(); i.hasNext();) { StructuredArtifact artifact = (StructuredArtifact) i.next(); try { transform(sad, artifact); validateAfterTransform(sad, artifact); // don't persist yet, in case error is found in some other artifact modifiedArtifacts.add(artifact); } catch (TransformerException e) { throw new OspException("problem transforming item with id=" + artifact.getId().getValue(), e); } catch (IOException e) { throw new OspException(e); } catch (JDOMException e) { throw new OspException("problem with xsl file: " + e.getMessage(), e); } } finished = true; } finally { // reset systemOnly state back to whatever if was // but only if there was an error if (!originalSystemOnlyState && !finished) { currentHome.setSystemOnly(false); getHibernateTemplate().saveOrUpdate(currentHome); } } // since all artifacts validated go ahead and persist changes saveAll(sad, modifiedArtifacts); } protected Element getStructuredArtifactRootElement(StructuredArtifactDefinition sad, StructuredArtifact artifact) { return sad.getArtifactAsXml(artifact).getChild("structuredData").getChild(sad.getRootNode()); } protected void transform(StructuredArtifactDefinition sad, StructuredArtifact artifact) throws IOException, TransformerException, JDOMException { /* todo transform logger.debug("transforming artifact " + artifact.getId().getValue() + " owned by " + artifact.getOwner().getDisplayName()); JDOMResult result = new JDOMResult(); SAXBuilder builder = new SAXBuilder(); Document xslDoc = builder.build(sad.getXslConversionFileStream()); Transformer transformer = TransformerFactory.newInstance().newTransformer(new JDOMSource(xslDoc)); Element rootElement = getStructuredArtifactRootElement(sad, artifact); transformer.transform(new JDOMSource(rootElement), result); artifact.setBaseElement((Element) result.getResult().get(0)); */ } public AuthenticationManager getAuthManager() { return (AuthenticationManager) ComponentManager.getInstance().get("authManager"); } public AuthorizationFacade getAuthzManager() { return authzManager; } public void setAuthzManager(AuthorizationFacade authzManager) { this.authzManager = authzManager; } public WorksiteManager getWorksiteManager() { return worksiteManager; } public void setWorksiteManager(WorksiteManager worksiteManager) { this.worksiteManager = worksiteManager; } public ToolManager getToolManager() { return toolManager; } public void setToolManager(ToolManager toolManager) { this.toolManager = toolManager; } protected Id getToolId() { Placement placement = toolManager.getCurrentPlacement(); return idManager.getId(placement.getId()); } public void importResources(String fromContext, String toContext, List resourceIds) { // select all this worksites forms and create them for the new worksite Map homes = getWorksiteHomes(getIdManager().getId(fromContext), true); for (Iterator i = homes.entrySet().iterator(); i.hasNext();) { Map.Entry entry = (Map.Entry) i.next(); StructuredArtifactDefinitionBean bean = (StructuredArtifactDefinitionBean) entry.getValue(); if (fromContext.equals(bean.getSiteId())) { getHibernateTemplate().evict(bean); bean.setSiteId(toContext); bean.setId(null); bean.setSiteState(StructuredArtifactDefinitionBean.STATE_UNPUBLISHED); //Check for an existing form if (findBean(bean) == null) { getHibernateTemplate().save(bean); } } } } public ContentHostingService getContentHosting() { return contentHosting; } public void setContentHosting(ContentHostingService contentHosting) { this.contentHosting = contentHosting; } protected void init() throws Exception { logger.info("init()"); // register functions FunctionManager.registerFunction(SharedFunctionConstants.CREATE_ARTIFACT_DEF); FunctionManager.registerFunction(SharedFunctionConstants.EDIT_ARTIFACT_DEF); FunctionManager.registerFunction(SharedFunctionConstants.EXPORT_ARTIFACT_DEF); FunctionManager.registerFunction(SharedFunctionConstants.DELETE_ARTIFACT_DEF); FunctionManager.registerFunction(SharedFunctionConstants.PUBLISH_ARTIFACT_DEF); FunctionManager.registerFunction(SharedFunctionConstants.SUGGEST_GLOBAL_PUBLISH_ARTIFACT_DEF); addConsumer(this); boolean runOnInit = ServerConfigurationService.getBoolean("metaobj.schemahash.runOnInit", false); if (runOnInit) { boolean updateSchemaHashes = ServerConfigurationService.getBoolean("metaobj.schemahash.update", false); verifySchemaHashes(updateSchemaHashes); } if (isAutoDdl()) { updateSchemaHash(); org.sakaiproject.tool.api.Session sakaiSession = SessionManager.getCurrentSession(); String userId = sakaiSession.getUserId(); sakaiSession.setUserId("admin"); sakaiSession.setUserEid("admin"); try { logger.info("Updating base Metaobj XSLT files (auto.ddl is on)."); createResource("/org/sakaiproject/metaobj/shared/control/formCreate.xslt", "formCreate.xslt", "used for default rendering of form add and update", "text/xml", isReplaceViews(), true); createResource("/org/sakaiproject/metaobj/shared/control/formFieldTemplate.xslt", "formFieldTemplate.xslt", "used for default rendering of form fields", "text/xml", isReplaceViews(), true); createResource("/org/sakaiproject/metaobj/shared/control/formView.xslt", "formView.xslt", "used for default rendering of form viewing", "text/xml", isReplaceViews(), true); } finally{ sakaiSession.setUserEid(userId); sakaiSession.setUserId(userId); } } if (isEnableLocksConversion()) { List<StructuredArtifactDefinitionBean> homes = findAllHomes(); for (StructuredArtifactDefinitionBean bean : homes) { lockSADFiles(bean); } } } protected void updateSchemaHash() { List forms = getHibernateTemplate().findByNamedQuery("findByNullSchemaHash"); for (Iterator i = forms.iterator(); i.hasNext();) { StructuredArtifactDefinitionBean bean = (StructuredArtifactDefinitionBean) i.next(); bean.setSchemaHash(calculateSchemaHash(bean)); getHibernateTemplate().saveOrUpdate(bean); } } protected String calculateSchemaHash(StructuredArtifactDefinitionBean bean) { String hashCode = ""; String hashString = ""; if (bean.getSchema() != null) { hashString += new String(bean.getSchema()); } hashString += convertNull2Empty(bean.getDocumentRoot()); hashString += convertNull2Empty(bean.getDescription()); hashString += convertNull2Empty(bean.getInstruction()); hashCode = hashString.hashCode() + ""; logger.debug("Calculating hashcode for bean: " + bean.getDescription() + "(" + bean.getId() + "); OLD:" + bean.getSchemaHash() + "; NEW:" + hashCode); return hashCode; } /** * If the input is null, return an empty string instead, * otherwise return the input * @param input * @return */ private String convertNull2Empty(String input) { String output = ""; if (input!= null) { output = input; } return output; } public void verifySchemaHashes(boolean updateInvalid) { List<StructuredArtifactDefinitionBean> homes = findAllHomes(); int badCount = 0; for (StructuredArtifactDefinitionBean bean : homes) { bean.setInstruction(sanitizeInstructions(bean.getInstruction())); String calcHash = calculateSchemaHash(bean); if (!bean.getSchemaHash().equalsIgnoreCase(calcHash)) { String text = "Form has invalid schema hash: " + bean.getDescription() + "(" + bean.getId() + "); stored: " + bean.getSchemaHash() + "; calc: " + calcHash; logger.warn(text); badCount++; if (updateInvalid) { if (bean.getOwner() == null || bean.getOwner().getId() == null) { text = "Unable to update schema hash because unable to get owner for bean: " + bean.getId(); logger.warn(text); } else { bean.setSchemaHash(calcHash); getHibernateTemplate().saveOrUpdate(bean); text = "Form schema hash has been updated: " + bean.getId(); logger.info(text); } } } } String text = "There are " + badCount + " forms with invalid schema hashes."; logger.warn(text); } public String packageForDownload(Map params, OutputStream out) throws IOException { String[] formIdObj = (String[]) params.get(DOWNLOAD_FORM_ID_PARAM); packageFormForExport(formIdObj[0], out); //Blank filename for now -- no more dangerous, since the request is in the form of a filename return ""; } /** * This is the default method for exporting a form into a stream. This method does check the * form export permission. * @param formId String * @param os OutputStream * @throws IOException */ public void packageFormForExport(String formId, OutputStream os) throws IOException { packageFormForExport(formId, os, true); } /** * This method will export a form into a stream. It has the ability to turn off checking * for the export form permission. * @param formId String * @param os OutputStream * @param checkPermission boolean * @throws IOException */ public void packageFormForExport(String formId, OutputStream os, boolean checkPermission) throws IOException { if (checkPermission) { getAuthzManager().checkPermission(SharedFunctionConstants.EXPORT_ARTIFACT_DEF, getToolId()); } CheckedOutputStream checksum = new CheckedOutputStream(os, new Adler32()); ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum)); StructuredArtifactDefinitionBean bean = loadHome(formId); writeSADtoZip(bean, zos, ""); zos.finish(); zos.flush(); } /** * Given a bean this method will convert it into a new XML document. * This does not put the schema into XML * @param bean StructuredArtifactDefinitionBean * @return Document - XML */ public Document exportSADAsXML(StructuredArtifactDefinitionBean bean) { Element rootNode = new Element("metaobjForm"); rootNode.setAttribute("formatVersion", "2.1"); Element attrNode = new Element("description"); attrNode.addContent(new CDATA(bean.getDescription())); rootNode.addContent(attrNode); attrNode = new Element("instruction"); attrNode.addContent(new CDATA(bean.getInstruction())); rootNode.addContent(attrNode); attrNode = new Element("documentRootNode"); attrNode.addContent(new CDATA(bean.getDocumentRoot())); rootNode.addContent(attrNode); if ( bean.getAlternateCreateXslt() != null ) { attrNode = new Element("altCreateXslt"); attrNode.addContent(new CDATA(bean.getAlternateCreateXslt().getValue())); rootNode.addContent(attrNode); } if ( bean.getAlternateViewXslt() != null ) { attrNode = new Element("altViewXslt"); attrNode.addContent(new CDATA(bean.getAlternateViewXslt().getValue())); rootNode.addContent(attrNode); } return new Document(rootNode); } /** * Given a bean, this method puts it into a stream via UTF-8 encoding * @param bean StructuredArtifactDefinitionBean * @param os OutputStream * @throws IOException */ public void writeSADasXMLtoStream(StructuredArtifactDefinitionBean bean, OutputStream os) throws IOException { Document doc = exportSADAsXML(bean); String docStr = (new XMLOutputter()).outputString(doc); os.write(docStr.getBytes("UTF-8")); } public void writeSADtoZip(StructuredArtifactDefinitionBean bean, ZipOutputStream zos) throws IOException { writeSADtoZip(bean, zos, ""); } public void writeSADtoZip(StructuredArtifactDefinitionBean bean, ZipOutputStream zos, String path) throws IOException { // if the path is a directory without an end slash, then add one if (!path.endsWith("/") && path.length() > 0) { path += "/"; } ZipEntry definitionFile = new ZipEntry(path + "formDefinition.xml"); zos.putNextEntry(definitionFile); writeSADasXMLtoStream(bean, zos); zos.closeEntry(); ZipEntry schemeFile = new ZipEntry(path + "schema.xsd"); zos.putNextEntry(schemeFile); zos.write(bean.getSchema()); zos.closeEntry(); List existingEntries = new ArrayList(); storeFile(zos, bean.getAlternateCreateXslt(), existingEntries); storeFile(zos, bean.getAlternateViewXslt(), existingEntries); } /** * Given a resource id, this parses out the Form from its input stream. * Once the enties are found, they are inserted into the given worksite. * * @param worksiteId Id * @param resourceId an String * @param findExisting */ public boolean importSADResource(Id worksiteId, String resourceId, boolean findExisting) throws IOException, ServerOverloadException, PermissionException, IdUnusedException, ImportException, UnsupportedFileTypeException { String id = getContentHosting().resolveUuid(resourceId); try { ContentResource resource = getContentHosting().getResource(id); MimeType mimeType = new MimeType(resource.getContentType()); if (!mimeType.equals(new MimeType("application/zip")) && !mimeType.equals(new MimeType("application/x-zip-compressed"))) { logger.warn(".importSADResource has identified the mime type as something unsupported: " + mimeType.toString() + "."); logger.warn("The import file must be a zip file for the import to work properly."); logger.warn("It's possible that the browser has identified the mime type incorrectly, so the import may still work."); } InputStream zipContent = resource.streamContent(); StructuredArtifactDefinitionBean bean = importSad(worksiteId, zipContent, findExisting, false); return bean != null; } catch (TypeException te) { logger.error(".importSADResource",te); } return false; } public StructuredArtifactDefinitionBean importSad(Id worksiteId, InputStream in, boolean findExisting, boolean publish) throws IOException, ImportException { return importSad(worksiteId, in, findExisting, publish, true); } public StructuredArtifactDefinitionBean importSad(Id worksiteId, InputStream in, boolean findExisting, boolean publish, boolean foundThrowsException) throws IOException, ImportException { ZipInputStream zis = new ZipInputStream(in); StructuredArtifactDefinitionBean bean = readSADfromZip(zis, worksiteId.getValue(), publish); if (bean != null) { if (findExisting) { StructuredArtifactDefinitionBean found = findBean(bean); if (found != null) { if (foundThrowsException) { throw new ImportException("The Form being imported already exists and has been published"); } else { return found; } } } String origTitle = bean.getDescription(); int index = 0; while (sadExists(bean)) { index++; bean.setDescription(origTitle + " " + index); } try{ save(bean); }catch (OspException e) { throw new OspException(e.getMessage(), origTitle, e); } // doesn't like imported beans in batch mode??? getHibernateTemplate().flush(); } return bean; } /** * * @param bean * @return */ protected StructuredArtifactDefinitionBean findBean(StructuredArtifactDefinitionBean bean) { Object[] params = new Object[]{new Integer(StructuredArtifactDefinitionBean.STATE_PUBLISHED), bean.getSiteId(), bean.getSchemaHash()}; List beans = getHibernateTemplate().findByNamedQuery("findBean", params); //There's an order by on this query so that the global form (if any) will be listed first if (beans.size() > 0) { return (StructuredArtifactDefinitionBean) beans.get(0); } return null; } public StructuredArtifactDefinitionBean readSADfromZip(ZipInputStream zis, String worksite, boolean publish) throws IOException { StructuredArtifactDefinitionBean bean = new StructuredArtifactDefinitionBean(); boolean hasXML = false, hasXSD = false; bean.setCreated(new Date(System.currentTimeMillis())); bean.setModified(bean.getCreated()); bean.setOwner(getAuthManager().getAgent()); bean.setSiteId(worksite); bean.setSiteState(publish ? StructuredArtifactDefinitionBean.STATE_PUBLISHED : StructuredArtifactDefinitionBean.STATE_UNPUBLISHED); if (isGlobal(worksite)) { bean.setGlobalState(publish ? StructuredArtifactDefinitionBean.STATE_PUBLISHED : StructuredArtifactDefinitionBean.STATE_UNPUBLISHED); bean.setSiteId(null); } ZipEntry currentEntry = zis.getNextEntry(); if (currentEntry == null) { return null; } // If the zip was opened and re-zipped, then the directory was // compressed with the files. we need to deal with // the directory if(currentEntry.getName().endsWith("/")) { zis.closeEntry(); currentEntry = zis.getNextEntry(); } try { Hashtable<Id, Id> fileMap = new Hashtable<Id, Id>(); String tempDirName = getIdManager().createId().getValue(); ContentCollectionEdit fileParent = getExpandedFileDir(tempDirName, worksite); boolean gotFile = false; while (currentEntry != null) { logger.debug("current entry name: " + currentEntry.getName()); File entryFile = new File( currentEntry.getName() ); if (entryFile.getName().startsWith(".")) { logger.warn(".readSADfromZip skipping control file: " + currentEntry.getName() ); } else if (currentEntry.getName().endsWith("xml")) { readSADfromXML(bean, zis); hasXML = true; } else if (currentEntry.getName().endsWith("xsd")) { readSADSchemaFromXML(bean, zis); hasXSD = true; } else if (!currentEntry.isDirectory()) { gotFile = true; processFile(currentEntry, zis, fileMap, fileParent); } zis.closeEntry(); currentEntry = zis.getNextEntry(); } if (gotFile) { fileParent.getPropertiesEdit().addProperty( ResourceProperties.PROP_DISPLAY_NAME, bean.getDescription()); getContentHosting().commitCollection(fileParent); } else { getContentHosting().cancelCollection(fileParent); } if (bean.getAlternateCreateXslt() != null) bean.setAlternateCreateXslt((Id)fileMap.get(bean.getAlternateCreateXslt())); if (bean.getAlternateViewXslt() != null) bean.setAlternateViewXslt((Id)fileMap.get(bean.getAlternateViewXslt())); } catch (Exception exp) { logger.error(".readSADFromZip", exp); return null; } bean.setSchemaHash(calculateSchemaHash(bean)); return bean; } /** * This gets the directory in which the import places files into. * * This method gets the current users base collection, creates an imported directory, * then uses the param to create a new directory. * * this uses the bean property importFolderName to name the * * @param origName String * @param siteId Site id to look up * @return ContentCollectionEdit * @throws InconsistentException * @throws PermissionException * @throws IdUsedException * @throws IdInvalidException * @throws IdUnusedException * @throws TypeException */ protected ContentCollectionEdit getExpandedFileDir(String origName, String siteId) throws TypeException, IdUnusedException, PermissionException, IdUsedException, IdInvalidException, InconsistentException { ContentCollection baseCollection = getSiteCollection(siteId); try { //TODO use the bean org.theospi.portfolio.admin.model.IntegrationOption.siteOption // in common/components to get the name and id for this site. ResourceLoader rb = new ResourceLoader("org/sakaiproject/metaobj/registry/messages"); ContentCollectionEdit groupCollection = getContentHosting().addCollection(baseCollection.getId() + IMPORT_BASE_FOLDER_ID); groupCollection.getPropertiesEdit().addProperty(ResourceProperties.PROP_DISPLAY_NAME, rb.getString("form_import_folder")); getContentHosting().commitCollection(groupCollection); } catch (IdUsedException e) { // ignore... it is already there. if (logger.isDebugEnabled()) { logger.debug(e); } } catch (Exception e) { logger.error(".getExpandedFileDir",e); return null; } ContentCollection collection = getContentHosting().getCollection(baseCollection.getId() + IMPORT_BASE_FOLDER_ID + "/"); String childId = collection.getId() + origName; return getContentHosting().addCollection(childId); } /** * gets the current user's resource collection * * @return ContentCollection * @throws TypeException * @throws IdUnusedException * @throws PermissionException */ protected ContentCollection getUserCollection() throws TypeException, IdUnusedException, PermissionException { User user = UserDirectoryService.getCurrentUser(); String userId = user.getId(); String wsId = SiteService.getUserSiteId(userId); String wsCollectionId = getContentHosting().getSiteCollection(wsId); ContentCollection collection = getContentHosting().getCollection(wsCollectionId); return collection; } /** * gets the site's resource collection * * @param siteId Site id to look up * @return ContentCollection * @throws TypeException * @throws IdUnusedException * @throws PermissionException */ protected ContentCollection getSiteCollection(String siteId) throws TypeException, IdUnusedException, PermissionException { String wsCollectionId = getContentHosting().getSiteCollection(siteId); ContentCollection collection = getContentHosting().getCollection(wsCollectionId); return collection; } private StructuredArtifactDefinitionBean readSADfromXML(StructuredArtifactDefinitionBean bean, InputStream inStream) { SAXBuilder builder = new SAXBuilder(); builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // SAK-23245 try { byte[] bytes = readStreamToBytes(inStream); // for some reason the SAX Builder sometimes won't recognize //these bytes as correct utf-8 characters. So we want to read it in //as utf-8 and spot it back out as utf-8 and this will correct the //bytes. In my test, it added two bytes somewhere in the string. //and adding those two bytes made the string work for saxbuilder. // bytes = (new String(bytes, "UTF-8")).getBytes("UTF-8"); Document document = builder.build(new ByteArrayInputStream(bytes)); Element topNode = document.getRootElement(); bean.setDescription(new String(topNode.getChildTextTrim("description").getBytes(), "UTF-8")); bean.setInstruction(new String(topNode.getChildTextTrim("instruction").getBytes(), "UTF-8")); bean.setDocumentRoot(new String(topNode.getChildTextTrim("documentRootNode").getBytes(), "UTF-8")); if (topNode.getChildTextTrim("altCreateXslt") != null) bean.setAlternateCreateXslt(getIdManager().getId(new String(topNode.getChildTextTrim("altCreateXslt").getBytes(), "UTF-8"))); if (topNode.getChildTextTrim("altViewXslt") != null) bean.setAlternateViewXslt(getIdManager().getId(new String(topNode.getChildTextTrim("altViewXslt").getBytes(), "UTF-8"))); } catch (Exception jdome) { logger.error(".readSADfromXML", jdome); return null; } return bean; } private byte[] readStreamToBytes(InputStream inStream) throws IOException { ByteArrayOutputStream bytes = new ByteArrayOutputStream(); byte data[] = new byte[10 * 1024]; int count; while ((count = inStream.read(data, 0, 10 * 1024)) != -1) { bytes.write(data, 0, count); } byte[] tmp = bytes.toByteArray(); bytes.close(); return tmp; } private StructuredArtifactDefinitionBean readSADSchemaFromXML(StructuredArtifactDefinitionBean bean, InputStream inStream) throws IOException { bean.setSchema(readStreamToBytes(inStream)); return bean; } public List getGlobalSites() { return globalSites; } public void setGlobalSites(List globalSites) { this.globalSites = globalSites; } public List getGlobalSiteTypes() { return globalSiteTypes; } public void setGlobalSiteTypes(List globalSiteTypes) { this.globalSiteTypes = globalSiteTypes; } public Element createFormViewXml(String formId, String returnUrl) { formId = getContentHosting().getUuid(formId); Artifact art = getArtifactFinder().load(getIdManager().getId(formId)); return createFormViewXml(art, returnUrl); } public Element createFormViewXml(Artifact art, String returnUrl) { Element root = new Element("formView"); Element data = new Element("formData"); ReadableObjectHome home = (ReadableObjectHome) art.getHome(); if (home instanceof PresentableObjectHome) { data.addContent(((PresentableObjectHome) home).getArtifactAsXml(art)); } root.addContent(data); if (returnUrl != null) { Element returnUrlElement = new Element("returnUrl"); returnUrlElement.addContent(new CDATA(returnUrl)); root.addContent(returnUrlElement); } Element css = new Element("css"); String skin = null; try { skin = getCurrentSite().getSkin(); } catch (NullPointerException npe) { //Couldn't find the site, just use default skin } if (skin == null || skin.length() == 0) { skin = ServerConfigurationService.getString("skin.default"); } String skinRepo = ServerConfigurationService.getString("skin.repo"); Element uri = new Element("uri"); uri.setAttribute("order", "1"); uri.setText(skinRepo + "/tool_base.css"); css.addContent(uri); uri = new Element("uri"); uri.setAttribute("order", "2"); uri.setText(skinRepo + "/" + skin + "/tool.css"); css.addContent(uri); root.addContent(css); return root; } public Element createFormViewXml(ElementBean bean, String returnUrl) { Element root = new Element("formView"); Element data = new Element("formData"); //data.addContent(((PresentableObjectHome) home).getArtifactAsXml(art)); root.addContent(data); if (returnUrl != null) { Element returnUrlElement = new Element("returnUrl"); returnUrlElement.addContent(new CDATA(returnUrl)); root.addContent(returnUrlElement); } Element css = new Element("css"); String skin = null; try { skin = getCurrentSite().getSkin(); } catch (NullPointerException npe) { //Couldn't find the site, just use default skin } if (skin == null || skin.length() == 0) { skin = ServerConfigurationService.getString("skin.default"); } String skinRepo = ServerConfigurationService.getString("skin.repo"); Element uri = new Element("uri"); uri.setText(skinRepo + "/tool_base.css"); css.addContent(uri); uri = new Element("uri"); uri.setText(skinRepo + "/" + skin + "/tool.css"); css.addContent(uri); root.addContent(css); return root; } public InputStream getTransformer(String type, boolean readOnly) { try { String viewLocation = "/group/PortfolioAdmin/system/formCreate.xslt"; StructuredArtifactDefinitionBean sadb = loadHome(type); if (sadb == null) { ToolSession toolSession = SessionManager.getCurrentToolSession(); sadb = (StructuredArtifactDefinitionBean)toolSession.getAttribute(SAD_SESSION_TAG); } if (sadb != null && sadb.getAlternateCreateXslt() != null) { String id = getContentHosting().resolveUuid(sadb.getAlternateCreateXslt().getValue()); if ( id != null ) viewLocation = id; } if (readOnly) { viewLocation = "/group/PortfolioAdmin/system/formView.xslt"; if (sadb != null && sadb.getAlternateViewXslt() != null) { String id = getContentHosting().resolveUuid(sadb.getAlternateViewXslt().getValue()); if ( id != null ) viewLocation = id; } } List refs = new ArrayList(); refs.add(getContentHosting().getReference(viewLocation)); refs.add(getContentHosting().getReference("/group/PortfolioAdmin/system")); Map funcs = new HashMap(); funcs.put(ContentHostingService.EVENT_RESOURCE_READ, refs); funcs.put(ContentHostingService.AUTH_RESOURCE_HIDDEN, refs); getSecurityService().pushAdvisor(new AllowChildrenMapSecurityAdvisor(funcs)); return getContentHosting().getResource(viewLocation).streamContent(); } catch (Exception e) { logger.error(".getTransformer",e); return null; } } public boolean hasHomes() { if (ThreadLocalManager.get(HAS_HOMES_TAG) == null) { ThreadLocalManager.set(HAS_HOMES_TAG, new Boolean(findHomes(false).size() > 0)); } return ((Boolean)ThreadLocalManager.get(HAS_HOMES_TAG)).booleanValue(); } public void addConsumer(FormConsumer consumer) { getFormConsumers().add(consumer); } public ArtifactFinder getArtifactFinder() { return artifactFinder; } public void setArtifactFinder(ArtifactFinder artifactFinder) { this.artifactFinder = artifactFinder; } public int getExpressionMax() { return expressionMax; } public void setExpressionMax(int expressionMax) { this.expressionMax = expressionMax; } protected ByteArrayOutputStream loadResource(String name) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); InputStream is = getClass().getResourceAsStream(name); try { int c = is.read(); while (c != -1) { bos.write(c); c = is.read(); } bos.flush(); } catch (IOException e) { logger.error(".loadResource",e); } finally { try { is.close(); } catch (IOException e) { //can't do anything now.. if (logger.isDebugEnabled()) { logger.debug(e); } } } return bos; } protected String createResource(String resourceLocation, String name, String description, String type, boolean replace, boolean pubview) { ByteArrayOutputStream bos = loadResource(resourceLocation); ContentResource resource; ResourcePropertiesEdit resourceProperties = getContentHosting().newResourceProperties(); resourceProperties.addProperty (ResourceProperties.PROP_DISPLAY_NAME, name); resourceProperties.addProperty (ResourceProperties.PROP_DESCRIPTION, description); resourceProperties.addProperty(ResourceProperties.PROP_CONTENT_ENCODING, "UTF-8"); String folder = "/group/PortfolioAdmin" + SYSTEM_COLLECTION_ID; try { //TODO use the bean org.theospi.portfolio.admin.model.IntegrationOption.siteOption // in common/components to get the name and id for this site. ContentCollectionEdit groupCollection = getContentHosting().addCollection("/group/PortfolioAdmin"); groupCollection.getPropertiesEdit().addProperty(ResourceProperties.PROP_DISPLAY_NAME, "Portfolio Admin"); getContentHosting().commitCollection(groupCollection); } catch (IdUsedException e) { // ignore... it is already there. if (logger.isDebugEnabled()) { logger.debug(e); } } catch (Exception e) { logger.error(".createResource",e); return null; } try { ContentCollectionEdit collection = getContentHosting().addCollection(folder); collection.getPropertiesEdit().addProperty(ResourceProperties.PROP_DISPLAY_NAME, "system"); getContentHosting().commitCollection(collection); } catch (IdUsedException e) { // ignore... it is already there. if (logger.isDebugEnabled()) { logger.debug(e); } } catch (Exception e) { logger.error(".createResource",e); return null; } String resourceId = folder + name; try { if (!replace) { ContentResource testResource = getContentHosting().getResource(resourceId); if (testResource != null) { return testResource.getId(); } } getContentHosting().removeResource(resourceId); } catch (TypeException e) { // should not happen -- requested resource should not be a collection logger.warn(e); } catch (IdUnusedException e) { // ignore, must be new resource if (logger.isDebugEnabled()) { logger.debug(e); } } catch (PermissionException e) { // should not happen - log unexpected error logger.warn(e); } catch (InUseException e) { // should not happen - log unexpected error logger.warn(e); } try { resource = getContentHosting().addResource(name, folder, 1, type, bos.toByteArray(), resourceProperties, NotificationService.NOTI_NONE); getContentHosting().setPubView(resource.getId(), pubview); } catch (IdUniquenessException e) { //Odd case -- tried to add new, but failed; return the existent ID attempted logger.info("Failure trying to write Metaobj file: " + folder + name, e); return resourceId; } catch (Exception e) { logger.error(".createResource",e); return null; } return resource.getId(); } protected void storeFile(ZipOutputStream zos, Id fileId, List existingEntries) throws IOException { if (fileId == null) { return; } try { String userId = SessionManager.getCurrentSessionUserId(); String id = getContentHosting().resolveUuid(fileId.getValue()); String ref = getContentHosting().getReference(id); //getSecurityService().pushAdvisor( // new SimpleSecurityAdvisor(userId, ContentHostingService.EVENT_RESOURCE_READ, ref)); getSecurityService().pushAdvisor(new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }); ContentResource resource = getContentHosting().getResource(id); String newName = resource.getProperties().getProperty( resource.getProperties().getNamePropDisplayName()); String cleanedName = newName.substring(newName.lastIndexOf('\\')+1); if (!existingEntries.contains(fileId)) { existingEntries.add(fileId); storeFileInZip(zos, resource.streamContent(), resource.getContentType() + File.separator + fileId.getValue() + File.separator + cleanedName); } getSecurityService().popAdvisor(); } catch (PermissionException e) { logger.error(".storeFile", e); } catch (IdUnusedException e) { logger.error(".storeFile", e); } catch (TypeException e) { logger.error(".storeFile", e); } catch (ServerOverloadException e) { logger.error(".storeFile", e); } } protected void storeFileInZip(ZipOutputStream zos, InputStream in, String entryName) throws IOException { byte data[] = new byte[1024 * 10]; if (File.separatorChar == '\\') { entryName = entryName.replace('\\', '/'); } ZipEntry newfileEntry = new ZipEntry(entryName); zos.putNextEntry(newfileEntry); BufferedInputStream origin = new BufferedInputStream(in, data.length); int count; while ((count = origin.read(data, 0, data.length)) != -1) { zos.write(data, 0, count); } zos.closeEntry(); in.close(); } protected void processFile(ZipEntry currentEntry, ZipInputStream zis, Hashtable fileMap, ContentCollection fileParent) throws IOException { File file = new File(currentEntry.getName()); // Unclear what the original intention is of checking for a files great-grandparent for mime-type // but for now we'll make sure grand-parent exists to avoid throwing NPE. // In testing, NPE was thrown for __MACOSX files if ( file.getParentFile() == null || file.getParentFile().getParentFile() == null || file.getParentFile().getParentFile().getParentFile() == null ) { logger.warn("StructuredArtifactDefinitionManagerImpl.processFile() found unexpected file "+ currentEntry.getName() ); return; } MimeType mimeType = new MimeType(file.getParentFile().getParentFile().getParentFile().getName(), file.getParentFile().getParentFile().getName()); String contentType = mimeType.getValue(); Id oldId = getIdManager().getId(file.getParentFile().getName()); try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); int c = zis.read(); while (c != -1) { bos.write(c); c = zis.read(); } String fileName = findUniqueFileName(fileParent.getId(), file.getName()); ResourcePropertiesEdit resourceProperties = getContentHosting().newResourceProperties(); resourceProperties.addProperty (ResourceProperties.PROP_DISPLAY_NAME, fileName); ContentResource /*Edit*/ resource; resource = getContentHosting().addResource(fileParent.getId() + fileName, contentType, bos.toByteArray(), resourceProperties, NotificationService.NOTI_NONE); Id newId = getIdManager().getId(getContentHosting().getUuid(resource.getId())); fileMap.put(oldId, newId); } catch (Exception exp) { logger.error(".processFile", exp); } } protected String findUniqueFileName(String id, String name) throws TypeException, PermissionException { String orig = name; String testId = id + name; int current = 0; while (resourceExists(testId)) { current++; int dotPos = orig.lastIndexOf('.'); if (dotPos == -1) { name = orig + current; } else { name = orig.substring(0, dotPos) + "-" + current + orig.substring(dotPos); } testId = id + name; } return name; } protected boolean resourceExists(String returned) throws TypeException, PermissionException { try { return getContentHosting().getResource(returned) != null; } catch (IdUnusedException e) { return false; } } public boolean isReplaceViews() { return replaceViews; } public void setReplaceViews(boolean replaceViews) { this.replaceViews = replaceViews; } public List getFormConsumers() { return formConsumers; } public void setFormConsumers(List formConsumers) { this.formConsumers = formConsumers; } public boolean checkFormConsumption(Id formId) { String type = formId.getValue(); getSecurityService().pushAdvisor(new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }); try { Collection arts = getStructuredArtifactFinder().findByType(type); return arts != null && arts.size() > 0; } finally { getSecurityService().popAdvisor(); } } public Collection<FormConsumptionDetail> getFormConsumptionDetails(Id formId) { Collection<FormConsumptionDetail> results = new ArrayList<FormConsumptionDetail>(); String type = formId.getValue(); getSecurityService().pushAdvisor(new SecurityAdvisor() { public SecurityAdvice isAllowed(String userId, String function, String reference) { return SecurityAdvice.ALLOWED; } }); try { Collection<StructuredArtifact> arts = getStructuredArtifactFinder().findByType(type); String formConsumptionType = messages.getString("content_resource_type"); String formNameText = messages.getString("form_name"); String formOwnerText = messages.getString("form_owner"); for (Iterator<StructuredArtifact> i = arts.iterator(); i.hasNext();) { StructuredArtifact art = (StructuredArtifact) i.next(); Reference ref = EntityManager.newReference(art.getBaseResource().getReference()); String context = ref.getContext(); FormConsumptionDetail fcd = new FormConsumptionDetail( art.getHome().getType().getId().getValue(), context, formConsumptionType, formNameText + art.getDisplayName(), formOwnerText + art.getOwner().getDisplayName()); results.add(fcd); } return results; } finally { getSecurityService().popAdvisor(); } } public void checkFormAccess(String resource_uuid) { String resourceId = getContentHosting().resolveUuid(resource_uuid); boolean allowed = getContentHosting().allowGetResource(resourceId); if (!allowed) return; Artifact art = getArtifactFinder().load(getIdManager().getId(resource_uuid)); PresentableObjectHome home = (PresentableObjectHome)art.getHome(); Element elm = home.getArtifactAsXml(art); List<String> files = new ArrayList<String>(); //try to get all the attachments List<Element> elms = findElementNamesForFileType(elm); for (Element element : elms) { String name = element.getAttributeValue("name"); try { XPath fileAttachPath = XPath.newInstance(".//" + name); List<Element> fileElements = fileAttachPath.selectNodes(elm); for (Element theElm : fileElements) { String file = theElm.getText(); String fileRef = getContentHosting().getReference(file); logger.debug("Pushing " + fileRef + " on advisor stack"); files.add(fileRef); } } catch (JDOMException e) { logger.error("unable to get element", e); } } getSecurityService().pushAdvisor( new AllowMapSecurityAdvisor(ContentHostingService.EVENT_RESOURCE_READ, files)); } /** * Return a list of Element objects from the passed root that are of type xs:anyURI * @param root * @return */ private List<Element> findElementNamesForFileType(Element root) { List<Element> fileElements = new ArrayList<Element>(); try { XPath fileAttachPath = XPath.newInstance(".//element[@type='xs:anyURI']"); fileElements = fileAttachPath.selectNodes(root); } catch (JDOMException e) { logger.error("unable to get element", e); } return fileElements; } public SecurityService getSecurityService() { return securityService; } public void setSecurityService(SecurityService securityService) { this.securityService = securityService; } public ArtifactFinder getStructuredArtifactFinder() { return structuredArtifactFinder; } public void setStructuredArtifactFinder(ArtifactFinder structuredArtifactFinder) { this.structuredArtifactFinder = structuredArtifactFinder; } public boolean isAutoDdl() { return autoDdl; } public void setAutoDdl(boolean autoDdl) { this.autoDdl = autoDdl; } public boolean isEnableLocksConversion() { return enableLocksConversion; } public void setEnableLocksConversion(boolean enableLocksConversion) { this.enableLocksConversion = enableLocksConversion; } }