/* * (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Contributors: * Nuxeo - initial API and implementation * * $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $ */ package org.nuxeo.ecm.webapp.documentsLists; import java.io.Serializable; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.Base64; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.ClientRuntimeException; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.api.DocumentRef; import org.nuxeo.ecm.core.api.IdRef; import org.nuxeo.ecm.core.api.PathRef; import org.nuxeo.ecm.directory.DirectoryException; import org.nuxeo.ecm.directory.Session; import org.nuxeo.ecm.directory.api.DirectoryService; import org.nuxeo.ecm.platform.ui.web.directory.DirectoryHelper; /** * Manage DocumentsLists Persistence. * Uses a SQL Directory as storage Backend. * * @author tiry */ public class DocumentsListsPersistenceManager { private static final String DIR_NAME = "documentsLists"; private static final String ID_SEP = ":"; private static final String DIR_COL_USERID = "userid"; private static final String DIR_COL_LISTID = "listid"; private static final String DIR_COL_REF = "ref"; private static final String DIR_COL_REFTYPE = "reftype"; private static final String DIR_COL_REPO = "repo"; // Hey, you never know ! private static final boolean ENABLE_SANITY_CHECK = true; private static final boolean FIX_SANITY_ERROR = true; private static final Log log = LogFactory.getLog(DocumentsListsPersistenceManager.class); private DirectoryService directoryService; private Session dirSession; private String directorySchema; private static String getIdForEntry(String userName, String listName, DocumentModel doc) { String ref = doc.getRef().toString(); int refType = doc.getRef().type(); String repoId = doc.getRepositoryName(); return getIdForEntry(userName, listName, ref, refType, repoId); } private static String getIdForEntry(String userName, String listName, String ref, int refType, String repoId) { StringBuilder sb = new StringBuilder(); sb.append(listName); sb.append(ID_SEP); sb.append(userName); sb.append(ID_SEP); sb.append(refType); sb.append(ID_SEP); sb.append(ref); sb.append(ID_SEP); sb.append(repoId); byte[] idDigest; try { idDigest = MessageDigest.getInstance("MD5").digest( sb.toString().getBytes()); } catch (NoSuchAlgorithmException e) { // should never append return sb.toString(); } return Base64.encodeBytes(idDigest); } private boolean initPersistentService() { if (dirSession != null) { return true; } if (directoryService == null) { directoryService = DirectoryHelper.getDirectoryService(); if (directoryService == null) { return false; } } try { dirSession = directoryService.open(DIR_NAME); directorySchema = directoryService.getDirectorySchema(DIR_NAME); } catch (ClientException e) { dirSession = null; log.error("Unable to open directory " + DIR_NAME + " : " + e.getMessage()); return false; } return true; } private void releasePersistenceService() { // for now directory sessions are lost during passivation of the DirectoryFacade // this can't be tested on the client side // => release directorySession after each call ... if (directoryService == null) { dirSession = null; return; } if (dirSession != null) { try { dirSession.close(); } catch (Exception e) { // do nothing } } dirSession = null; } private static DocumentModel getDocModel(CoreSession session, String ref, long refType, String repoId) { if (!session.getRepositoryName().equals(repoId)) { log.error("Multiple repository management is not handled in current implementation"); return null; } DocumentRef docRef; if (refType == DocumentRef.ID) { docRef = new IdRef(ref); } else if (refType == DocumentRef.PATH) { docRef = new PathRef(ref); } else { log.error("Unknown reference type"); return null; } DocumentModel doc = null; try { doc = session.getDocument(docRef); } catch (ClientException e) { log.warn("document with ref " + ref + " was not found : " + e.getMessage()); return null; } return doc; } public List<DocumentModel> loadPersistentDocumentsLists( CoreSession currentSession, String userName, String listName) { List<DocumentModel> docList = new ArrayList<DocumentModel>(); if (!initPersistentService()) { return docList; } Map<String, Serializable> filter = new HashMap<String, Serializable>(); filter.put(DIR_COL_LISTID, listName); filter.put(DIR_COL_USERID, userName); DocumentModelList entries = null; try { entries = dirSession.query(filter); } catch (DirectoryException e) { releasePersistenceService(); return docList; } catch (ClientException e) { releasePersistenceService(); return docList; } for (DocumentModel entry : entries) { String ref; long reftype; String repo; try { ref = (String) entry.getProperty(directorySchema, DIR_COL_REF); reftype = (Long) entry.getProperty(directorySchema, DIR_COL_REFTYPE); repo = (String) entry.getProperty(directorySchema, DIR_COL_REPO); } catch (ClientException e1) { releasePersistenceService(); throw new ClientRuntimeException(e1); } DocumentModel doc = getDocModel(currentSession, ref, reftype, repo); if (doc != null) { if (ENABLE_SANITY_CHECK) { if (docList.contains(doc)) { log.warn("Document " + doc.getRef().toString() + " is duplicated in persistent list " + listName); if (FIX_SANITY_ERROR) { try { dirSession.deleteEntry(entry.getId()); } catch (Exception e) { log.warn("Sanity fix failed " + e.getMessage()); } } } else { docList.add(doc); } } else { docList.add(doc); } } else { // not found => do the remove try { dirSession.deleteEntry(entry.getId()); } catch (Exception e) { releasePersistenceService(); log.error("Unable to remove non existing document model entry : ", e); } } } releasePersistenceService(); return docList; } public Boolean addDocumentToPersistentList(String userName, String listName, DocumentModel doc) { if (!initPersistentService()) { return false; } Map<String, Object> fields = new HashMap<String, Object>(); fields.put(DIR_COL_LISTID, listName); fields.put(DIR_COL_USERID, userName); fields.put(DIR_COL_REF, doc.getRef().toString()); fields.put(DIR_COL_REFTYPE, (long) doc.getRef().type()); fields.put(DIR_COL_REPO, doc.getRepositoryName()); String id = getIdForEntry(userName, listName, doc); fields.put("id", id); try { if (ENABLE_SANITY_CHECK) { DocumentModel badEntry = dirSession.getEntry(id); if (badEntry != null) { log.warn("Entry with id " + id + " is already present : please check DB integrity"); if (FIX_SANITY_ERROR) { dirSession.deleteEntry(id); } } } dirSession.createEntry(fields); } catch (Exception e) { log.error("Unable to create entry : " + e.getMessage()); releasePersistenceService(); return false; } releasePersistenceService(); return true; } public Boolean removeDocumentFromPersistentList(String userName, String listName, DocumentModel doc) { if (!initPersistentService()) { return false; } String entryId = getIdForEntry(userName, listName, doc); try { dirSession.deleteEntry(entryId); } catch (Exception e) { releasePersistenceService(); log.error("Unable to delete entry : " + e.getMessage()); return false; } releasePersistenceService(); return true; } public Boolean clearPersistentList(String userName, String listName) { if (!initPersistentService()) { return false; } Map<String, Serializable> filter = new HashMap<String, Serializable>(); filter.put(DIR_COL_LISTID, listName); filter.put(DIR_COL_USERID, userName); try { DocumentModelList entriesToDelete = dirSession.query(filter); for (DocumentModel entry : entriesToDelete) { dirSession.deleteEntry(entry.getId()); } } catch (Exception e) { log.error("Unable to clear DocumentList : " + e.getMessage()); releasePersistenceService(); return false; } releasePersistenceService(); return true; } }