/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <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 the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <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> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.modules.glossary; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.Iterator; import java.util.List; import org.apache.lucene.document.Document; import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl; import org.olat.core.commons.modules.glossary.GlossaryItemManager; import org.olat.core.gui.media.CleanupAfterDeliveryFileMediaResource; import org.olat.core.gui.media.MediaResource; import org.olat.core.id.OLATResourceable; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; import org.olat.core.util.ZipUtil; import org.olat.core.util.filter.Filter; import org.olat.core.util.filter.FilterFactory; import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.config.CourseConfig; import org.olat.fileresource.FileResourceManager; import org.olat.fileresource.types.GlossaryResource; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryImportExport; import org.olat.repository.RepositoryManager; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.resource.references.Reference; import org.olat.resource.references.ReferenceManager; import org.olat.search.model.OlatDocument; import org.olat.search.service.SearchResourceContext; /** * Description:<br> * Manager to create, delete etc. glossary learning resources. The OLAT glossary * functionality is based on the core framework glossary / textmarker functions. * <P> * <P> * Initial Date: 15.01.2009 <br> * @author Roman Haag, frentix GmbH, roman.haag@frentix.com */ public class GlossaryManagerImpl extends GlossaryManager { private static final String EXPORT_FOLDER_NAME = "glossary"; private ReferenceManager referenceManager; /** * [used by spring] */ private GlossaryManagerImpl(ReferenceManager referenceManager){ INSTANCE = this; this.referenceManager = referenceManager; } /** * Returns the internal glossary folder. * * @param res * @return */ @Override public OlatRootFolderImpl getGlossaryRootFolder(OLATResourceable res) { OlatRootFolderImpl resRoot = FileResourceManager.getInstance().getFileResourceRootImpl(res); if (resRoot == null) return null; VFSItem glossaryRoot = resRoot.resolve(INTERNAL_FOLDER_NAME); if (glossaryRoot == null) { // Glossary has been imported but not yet renamed to the internal folder. // This is ugly but no other way to do since the add resource callback // somehow does not provide this hook? VFSItem unzipped = resRoot.resolve(FileResourceManager.ZIPDIR); if (unzipped == null) { // Should not happen, but since we have no unzipped folder we better // continue with an empty glossary than crashing resRoot.createChildContainer(INTERNAL_FOLDER_NAME); } else { // We do not use the unzipped folder anymore, this was only for import. // We rename it to the internal glossary folder and use it from now on unzipped.rename(INTERNAL_FOLDER_NAME); } glossaryRoot = resRoot.resolve(INTERNAL_FOLDER_NAME); } return (OlatRootFolderImpl) glossaryRoot; } /** * Creates a lucene index document for this glossary * * @param repositoryEntry * @param searchResourceContext * @return Document the index document */ @Override public Document getIndexerDocument(RepositoryEntry repositoryEntry, SearchResourceContext searchResourceContext) { GlossaryItemManager gIMgr = GlossaryItemManager.getInstance(); VFSContainer glossaryFolder = getGlossaryRootFolder(repositoryEntry.getOlatResource()); VFSLeaf glossaryFile = gIMgr.getGlossaryFile(glossaryFolder); if (glossaryFile == null) { return null; } String glossaryContent = gIMgr.getGlossaryContent(glossaryFolder); // strip all html tags Filter htmlTagsFilter = FilterFactory.getHtmlTagsFilter(); glossaryContent = htmlTagsFilter.filter(glossaryContent); // create standard olat index document with this data OlatDocument glossaryDocument = new OlatDocument(); if (repositoryEntry.getInitialAuthor() != null) { glossaryDocument.setAuthor(repositoryEntry.getInitialAuthor()); } if (repositoryEntry.getDisplayname() != null) { glossaryDocument.setTitle(repositoryEntry.getDisplayname()); } if (repositoryEntry.getDescription() != null) { glossaryDocument.setDescription(htmlTagsFilter.filter(repositoryEntry.getDescription())); } glossaryDocument.setContent(glossaryContent); glossaryDocument.setCreatedDate(repositoryEntry.getCreationDate()); glossaryDocument.setLastChange(new Date(glossaryFile.getLastModified())); glossaryDocument.setResourceUrl(searchResourceContext.getResourceUrl()); glossaryDocument.setDocumentType(searchResourceContext.getDocumentType()); glossaryDocument.setCssIcon("o_FileResource-GLOSSARY_icon"); return glossaryDocument.getLuceneDocument(); } /** * Exports the glossary resource to the given export directory * * @param glossarySoftkey * @param exportedDataDir * @return */ @Override public boolean exportGlossary(String glossarySoftkey, File exportedDataDir) { RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntryBySoftkey(glossarySoftkey, false); if (re == null) return false; File fExportBaseDirectory = new File(exportedDataDir, EXPORT_FOLDER_NAME); if (!fExportBaseDirectory.mkdir()) return false; // export properties RepositoryEntryImportExport reImportExport = new RepositoryEntryImportExport(re, fExportBaseDirectory); return reImportExport.exportDoExport(); } /** * Export the glossary as a media resource. The resource name is set to the * resources display name * * @param res * @return */ @Override public MediaResource getAsMediaResource(OLATResourceable res) { RepositoryEntry repoEntry = RepositoryManager.getInstance().lookupRepositoryEntry(res, false); String exportFileName = repoEntry.getDisplayname(); // OO-135 check for special / illegal chars in filename exportFileName = StringHelper.transformDisplayNameToFileSystemName(exportFileName); try { File tmpDir = new File(WebappHelper.getTmpDir()); File fExportZIP = File.createTempFile(exportFileName, ".zip", tmpDir); VFSContainer glossaryRoot = getGlossaryRootFolder(res); ZipUtil.zip(glossaryRoot.getItems(), new LocalFileImpl(fExportZIP), false); return new CleanupAfterDeliveryFileMediaResource(fExportZIP); } catch (IOException e) { logError("Cannot export glossar: " + res, e); return null; } } /** * Creates a glossary resource and creates the necessary folders on disk. The * glossary will be placed in the resources _unizipped dir to make import / * export easier * * @return */ @Override public GlossaryResource createGlossary() { GlossaryResource resource = new GlossaryResource(); VFSContainer rootContainer = FileResourceManager.getInstance().getFileResourceRootImpl(resource); if (rootContainer == null) return null; if (rootContainer.createChildContainer(INTERNAL_FOLDER_NAME) == null) return null; OLATResourceManager rm = OLATResourceManager.getInstance(); OLATResource ores = rm.createOLATResourceInstance(resource); rm.saveOLATResource(ores); return resource; } /** * The import export data container used for course import * * @param importDataDir * @return */ @Override public RepositoryEntryImportExport getRepositoryImportExport(File importDataDir) { File fImportBaseDirectory = new File(importDataDir, EXPORT_FOLDER_NAME); return new RepositoryEntryImportExport(fImportBaseDirectory); } //TODO:RH:gloss change courseconfig, to keep more than 1 single glossary as a list /** * @param res glossary to be deleted */ @Override public void deleteGlossary(OLATResourceable res) { // first remove all references List<Reference> repoRefs = referenceManager.getReferencesTo(res); for (Iterator<Reference> iter = repoRefs.iterator(); iter.hasNext();) { Reference ref = iter.next(); if (ref.getUserdata().equals(GLOSSARY_REPO_REF_IDENTIFYER)) { // remove the reference from the course configuration // TODO:RH:improvement: this should use a callback method or send a general delete // event so that the course can take care of this rather than having it // here hardcoded OLATResource courseResource = ref.getSource(); //ICourse course = CourseFactory.loadCourse(courseResource); ICourse course = CourseFactory.openCourseEditSession(courseResource.getResourceableId()); CourseConfig cc = course.getCourseEnvironment().getCourseConfig(); cc.setGlossarySoftKey(null); CourseFactory.setCourseConfig(course.getResourceableId(), cc); CourseFactory.closeCourseEditSession(course.getResourceableId(),true); // remove reference from the references table referenceManager.delete(ref); } } // now remove the resource itself FileResourceManager.getInstance().deleteFileResource(res); } }