/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) 1999-2007 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <p>
*/
package org.olat.ims.cp;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import org.dom4j.tree.DefaultDocument;
import org.dom4j.tree.DefaultElement;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLATRuntimeException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.CodeHelper;
import org.olat.core.util.FileUtils;
import org.olat.core.util.ZipUtil;
import org.olat.core.util.vfs.LocalFolderImpl;
import org.olat.core.util.vfs.VFSContainer;
import org.olat.core.util.vfs.VFSItem;
import org.olat.core.util.vfs.VFSLeaf;
import org.olat.core.util.vfs.VFSManager;
import org.olat.core.util.xml.XMLParser;
import org.olat.fileresource.FileResourceManager;
import org.olat.ims.cp.objects.CPOrganization;
import org.olat.ims.cp.objects.CPResource;
import org.olat.ims.cp.ui.CPEditMainController;
import org.olat.ims.cp.ui.CPPage;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
/**
* The CP manager implementation.
* <p>
* In many cases, method calls are delegated to the content package object.
*
* <P>
* Initial Date: 04.07.2008 <br>
*
* @author Sergio Trentini
*/
public class CPManagerImpl extends CPManager {
private static final OLog log = Tracing.createLoggerFor(CPEditMainController.class);
private CPManagerImpl() {
super();
}
/**
*
* @see org.olat.ims.cp.CPManager#load(org.olat.core.util.vfs.VFSContainer)
*/
public ContentPackage load(VFSContainer directory, OLATResourceable ores) {
XMLParser parser = new XMLParser();
ContentPackage cp;
VFSLeaf file = (VFSLeaf) directory.resolve("imsmanifest.xml");
if (file != null) {
try {
DefaultDocument doc = (DefaultDocument) parser.parse(file.getInputStream(), false);
cp = new ContentPackage(doc, directory, ores);
// If a wiki is imported or a new cp created, set a unique orga
// identifier.
if (cp.getLastError() == null) {
if (cp.isOLATContentPackage() && CPCore.OLAT_ORGANIZATION_IDENTIFIER.equals(cp.getFirstOrganizationInManifest().getIdentifier())) {
setUniqueOrgaIdentifier(cp);
}
}
} catch (OLATRuntimeException e) {
cp = new ContentPackage(null, directory, ores);
log.error("Reading imsmanifest failed. Dir: " + directory.getName() + ". Ores: " + ores.getResourceableId(), e);
cp.setLastError("Exception reading XML for IMS CP: invalid xml-file ( " + directory.getName() + ")");
}
} else {
cp = new ContentPackage(null, directory, ores);
cp.setLastError("Exception reading XML for IMS CP: IMS-Manifest not found in " + directory.getName());
log.error("IMS manifiest xml couldn't be found in dir " + directory.getName() + " ("+directory+"). Ores: " + ores.getResourceableId());
throw new OLATRuntimeException(CPManagerImpl.class, "The imsmanifest.xml file was not found.", new IOException());
}
return cp;
}
/**
* @see org.olat.ims.cp.CPManager#createNewCP(org.olat.core.id.OLATResourceable)
*/
public ContentPackage createNewCP(OLATResourceable ores, String initalPageTitle) {
// copy template cp to new repo-location
if (copyTemplCP(ores)) {
File cpRoot = FileResourceManager.getInstance().unzipFileResource(ores);
LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
ContentPackage cp = load(vfsWrapper, ores);
// Modify the copy of the template to get a unique identifier
CPOrganization orga = setUniqueOrgaIdentifier(cp);
setOrgaTitleToRepoEntryTitle(ores, orga);
// Also set the translated title of the inital page.
orga.getItems().get(0).setTitle(initalPageTitle);
writeToFile(cp);
return cp;
} else {
log.error("CP couldn't be created. Error when copying template. Ores: " + ores.getResourceableId());
throw new OLATRuntimeException("ERROR while creating new empty cp. an error occured while trying to copy template CP", null);
}
}
/**
* Sets the organization title to the title of the repository entry.
*
* @param ores
* @param orga
*/
private void setOrgaTitleToRepoEntryTitle(OLATResourceable ores, CPOrganization orga) {
// Set the title of the organization to the title of the resource.
RepositoryManager resMgr = RepositoryManager.getInstance();
RepositoryEntry cpEntry = resMgr.lookupRepositoryEntry(ores, false);
if (cpEntry != null) {
String title = cpEntry.getDisplayname();
orga.setTitle(title);
}
}
/**
* Assigns the organization a unique identifier in order to prevent any
* caching issues in the extjs menu tree later.
*
* @param cp
* @return The first organization of the content package.
*/
private CPOrganization setUniqueOrgaIdentifier(ContentPackage cp) {
CPOrganization orga = cp.getFirstOrganizationInManifest();
String newOrgaIdentifier = "olatcp-" + CodeHelper.getForeverUniqueID();
orga.setIdentifier(newOrgaIdentifier);
return orga;
}
public boolean isSingleUsedResource(CPResource res, ContentPackage cp) {
return cp.isSingleUsedResource(res);
}
@Override
public String addBlankPage(ContentPackage cp, String title) {
return cp.addBlankPage(title);
}
@Override
public String addBlankPage(ContentPackage cp, String title, String parentNodeID) {
return cp.addBlankPage(parentNodeID, title);
}
@Override
public void updatePage(ContentPackage cp, CPPage page) {
cp.updatePage(page);
}
/**
* @see org.olat.ims.cp.CPManager#addElement(org.olat.ims.cp.ContentPackage,
* org.dom4j.tree.DefaultElement)
*/
public boolean addElement(ContentPackage cp, DefaultElement newElement) {
return cp.addElement(newElement);
}
/**
* @see org.olat.ims.cp.CPManager#addElement(org.olat.ims.cp.ContentPackage,
* org.dom4j.tree.DefaultElement, java.lang.String)
*/
public boolean addElement(ContentPackage cp, DefaultElement newElement, String parentIdentifier, int position) {
return cp.addElement(newElement, parentIdentifier, position);
}
/**
*
* @see org.olat.ims.cp.CPManager#addElementAfter(org.olat.ims.cp.ContentPackage,
* org.dom4j.tree.DefaultElement, java.lang.String)
*/
public boolean addElementAfter(ContentPackage cp, DefaultElement newElement, String identifier) {
return cp.addElementAfter(newElement, identifier);
}
/**
*
* @see org.olat.ims.cp.CPManager#removeElement(org.olat.ims.cp.ContentPackage,
* java.lang.String)
*/
public void removeElement(ContentPackage cp, String identifier, boolean deleteResource) {
cp.removeElement(identifier, deleteResource);
}
/**
* @see org.olat.ims.cp.CPManager#moveElement(org.olat.ims.cp.ContentPackage,
* java.lang.String, java.lang.String, int)
*/
public void moveElement(ContentPackage cp, String nodeID, String newParentID, int position) {
cp.moveElement(nodeID, newParentID, position);
}
/**
*
* @see org.olat.ims.cp.CPManager#copyElement(org.olat.ims.cp.ContentPackage,
* java.lang.String)
*/
public String copyElement(ContentPackage cp, String sourceID) {
return cp.copyElement(sourceID, sourceID);
}
/**
* @see org.olat.ims.cp.CPManager#getDocument(org.olat.ims.cp.ContentPackage)
*/
public DefaultDocument getDocument(ContentPackage cp) {
return cp.getDocument();
}
public String getItemTitle(ContentPackage cp, String itemID) {
return cp.getItemTitle(itemID);
}
/**
* @see org.olat.ims.cp.CPManager#getElementByIdentifier(org.olat.ims.cp.ContentPackage,
* java.lang.String)
*/
public DefaultElement getElementByIdentifier(ContentPackage cp, String identifier) {
return cp.getElementByIdentifier(identifier);
}
@Override
public CPTreeDataModel getTreeDataModel(ContentPackage cp) {
return cp.buildTreeDataModel();
}
/**
*
* @see org.olat.ims.cp.CPManager#getFirstOrganizationInManifest(org.olat.ims.cp.ContentPackage)
*/
@Override
public CPOrganization getFirstOrganizationInManifest(ContentPackage cp) {
return cp.getFirstOrganizationInManifest();
}
/**
*
* @see org.olat.ims.cp.CPManager#getFirstPageToDisplay(org.olat.ims.cp.ContentPackage)
*/
@Override
public CPPage getFirstPageToDisplay(ContentPackage cp) {
return cp.getFirstPageToDisplay();
}
/**
* @see org.olat.ims.cp.CPManager#WriteToFile(org.olat.ims.cp.ContentPackage)
*/
public void writeToFile(ContentPackage cp) {
cp.writeToFile();
}
/**
* @see org.olat.ims.cp.CPManager#writeToZip(org.olat.ims.cp.ContentPackage)
*/
public VFSLeaf writeToZip(ContentPackage cp) {
OLATResourceable ores = cp.getResourcable();
VFSContainer cpRoot = cp.getRootDir();
VFSContainer oresRoot = FileResourceManager.getInstance().getFileResourceRootImpl(ores);
RepositoryEntry repoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(ores, false);
String zipFileName = "imscp.zip";
if (repoEntry != null) {
String zipName = repoEntry.getResourcename();
if (zipName != null && zipName.endsWith(".zip")) {
zipFileName = zipName;
}
}
// delete old archive and create new one
VFSItem oldArchive = oresRoot.resolve(zipFileName);
if (oldArchive != null) {
oldArchive.delete();
}
ZipUtil.zip(cpRoot.getItems(), oresRoot.createChildLeaf(zipFileName));
VFSLeaf zip = (VFSLeaf) oresRoot.resolve(zipFileName);
return zip;
}
/**
*
* @see org.olat.ims.cp.CPManager#getPageByItemId(org.olat.ims.cp.ContentPackage,
* java.lang.String)
*/
@Override
public String getPageByItemId(ContentPackage cp, String itemIdentifier) {
return cp.getPageByItemId(itemIdentifier);
}
/**
* copies the default,empty, cp template to the new ores-directory
*
* @param ores
* @return
*/
private boolean copyTemplCP(OLATResourceable ores) {
File root = FileResourceManager.getInstance().getFileResourceRoot(ores);
String packageName = ContentPackage.class.getCanonicalName();
String path = packageName.replace('.', '/');
path = path.replace("/ContentPackage", "/_resources/imscp.zip");
path = VFSManager.sanitizePath(path);
URL url = this.getClass().getResource(path);
try {
File f = new File(url.toURI());
if (f.exists() && root.exists()) {
FileUtils.copyFileToDir(f, root);
} else {
log.error("cp template was not copied. Source: " + url + " Target: " + root.getAbsolutePath());
}
} catch (URISyntaxException e) {
log.error("Bad url syntax when copying cp template. url: " + url + " Ores:" + ores.getResourceableId());
return false;
}
return true;
}
}