From b35e44a86771449337c047c47764308a1a125232 Mon Sep 17 00:00:00 2001 From: tosmers Date: Wed, 13 Jan 2016 16:58:46 +0000 Subject: [PATCH] [FEATURE] - adds dependency for 'com.opencsv' to parent-pom.xml and core-pom.xml - adds package exchange to ccm-core for the export-import-routines - adds class ObjectExporter to the exchange-package for the basic export-functionalities - adds dummy package docrepo.exchange.exporter into the exchange package of core - adds ResourceExporter to the dummy package for implementation of the abstact methods of the ObjectExporter git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@3792 8810af33-2d31-482b-a856-94f89814c4df --- ccm-core/pom.xml | 8 +- .../exchange/exporter/ObjectExporter.java | 115 +++++++ .../exchange/exporter/docrepo/BlobObject.java | 147 ++++++++ .../exchange/exporter/docrepo/File.java | 44 +++ .../exchange/exporter/docrepo/Folder.java | 62 ++++ .../exporter/docrepo/RecUpdDocsPortlet.java | 46 +++ .../exchange/exporter/docrepo/Repository.java | 126 +++++++ .../docrepo/RepositoryRepository.java | 95 +++++ .../exchange/exporter/docrepo/Resource.java | 324 ++++++++++++++++++ .../exporter/docrepo/ResourceManager.java | 108 ++++++ .../exporter/docrepo/ResourceRepository.java | 156 +++++++++ .../exchange/exporter/ResourceExporter.java | 98 ++++++ pom.xml | 6 + 13 files changed, 1334 insertions(+), 1 deletion(-) create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/ObjectExporter.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/BlobObject.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/File.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Folder.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RecUpdDocsPortlet.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Repository.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RepositoryRepository.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Resource.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceManager.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceRepository.java create mode 100644 ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/exchange/exporter/ResourceExporter.java diff --git a/ccm-core/pom.xml b/ccm-core/pom.xml index 790dbf8c9..77939b898 100644 --- a/ccm-core/pom.xml +++ b/ccm-core/pom.xml @@ -178,7 +178,13 @@ h2 test - + + + com.opencsv + opencsv + + + diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/ObjectExporter.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/ObjectExporter.java new file mode 100644 index 000000000..b6dc2a927 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/ObjectExporter.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter; + +import com.opencsv.CSVWriter; +import org.apache.commons.lang.NullArgumentException; +import org.apache.log4j.Logger; +import org.libreccm.security.User; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +/** + * Main class for exporting database objects as .csv-textfiles. Subclasses + * are required to implement the method {@code asList} matching their own + * needs. This is necessary, because every object class stored in the + * database has its own parameters which refer sometimes to other object + * classes. But these other object classes do not need to be exported in + * their entirety, only their uuid for later re-identification. + * + * @author Tobias Osmers + * @version 13/01/2016 + */ +public abstract class ObjectExporter { + + private static final Logger log = Logger.getLogger(ObjectExporter.class); + + private String filename = "ccm_ng-defaultExportFilename.csv"; + private char separator = ','; + + //> Begin GETTER & SETTER + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public char getSeparator() { + return separator; + } + + public void setSeparator(char separator) { + this.separator = separator; + } + + //< End GETTER & SETTER + + /** + * Empty constructor. + */ + public ObjectExporter() {} + + /** + * Exports a list of objects of type {@code T}, e.g. a list of + * {@link User}s, as a .csv-textfile with the specified {@code filename}. + * + * @param exportObjects List of objects of type {@code T} to be exported + */ + public void export(List exportObjects) throws NullArgumentException { + CSVWriter csvWriter = null; + if (filename == null) { + throw new NullArgumentException(filename); + } + try { + csvWriter = new CSVWriter(new FileWriter(filename), + separator); + csvWriter.writeAll(asList(exportObjects)); + csvWriter.close(); + } catch (IOException e) { + //Todo: what to do + e.printStackTrace(); + } + } + + /** + * Abstract method to force extending subclasses to implement this + * method, so the needed list for the export is matching their special + * needs. + * + * @param exportObjects List of objects of type {@code T} to be exported + * @return A list of strings containing all database information of the + * wanted object class. + */ + public abstract List asList(List exportObjects); + + /** + * Abstract method to reduce the types of a single export object to + * strings. + * + * @param exportObject A single exportObject + * @return A list of strings representing the parameters of the + * export object + */ + protected abstract String[] reduceToString(T exportObject); +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/BlobObject.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/BlobObject.java new file mode 100644 index 000000000..6a3b379ab --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/BlobObject.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + + +import org.hibernate.validator.constraints.NotEmpty; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Lob; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import java.io.Serializable; +import java.util.Objects; + +/** + * Entity class for a blob object in the doc-repository. Instances of this class + * will be persisted into the database. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity +@Table(schema = "CCM_DOCREPO", name = "BLOB_OBJECTS") +public class BlobObject implements Serializable { + + private static final long serialVersionUID = -7468014879548796218L; + + /** + * The ID/primary key for the {@code BlobObject}. Please note that it is not + * necessary to define an additional ID on classes which extend this class. + */ + @Id + @Column(name = "BLOB_OBJECT_ID") + @GeneratedValue(strategy = GenerationType.AUTO) + private long blobObjectId; + + /** + * The Content of the {@code BlobObject}. + */ + @Column(name = "CONTENT") + @Lob + @NotEmpty + private byte[] content; + + /** + * The {@link Resource} the {@code BlobObject} was assigned to. + */ + @OneToOne(mappedBy = "content") + @NotEmpty + private Resource resource; + + /** + * Constructor. + */ + public BlobObject() {} + + //> Begin GETTER & SETTER + + public long getBlobObjectId() { + return blobObjectId; + } + + public void setBlobObjectId(long blobObjectId) { + this.blobObjectId = blobObjectId; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } + + public Resource getResource() { + return resource; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + //< End GETTER & SETTER + + @Override + public int hashCode() { + int hash = 5; + hash = 61 * hash + (int) (blobObjectId ^ (blobObjectId >>> 32)); + hash = 61 * hash + Objects.hashCode(content); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof BlobObject)) { + return false; + } + + final BlobObject other = (BlobObject) obj; + if (!other.canEqual(this)) { + return false; + } + + return blobObjectId == other.getBlobObjectId() && + Objects.equals(content, other.getContent()); + } + + public boolean canEqual(final Object obj) { + return obj instanceof BlobObject; + } + + @Override + public String toString() { + return String.format("%s{ " + + "blobObjectId = %d, " + + "content = %s, " + + " }", + super.toString(), + blobObjectId, + content.toString()); + } + + +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/File.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/File.java new file mode 100644 index 000000000..5951475a2 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/File.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * Entity class for a file in the doc-repository. Instances will be persisted + * into the database. Instance variables are inherited from {@link Resource}. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity +@Table(schema = "CCM_DOCREPO", name = "FILES") +public class File extends Resource { + + private static final long serialVersionUID = -504220783419811504L; + + /** + * Constructor calls the super-class-constructor of {@link Resource}. + */ + public File() { + super(); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Folder.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Folder.java new file mode 100644 index 000000000..cad360f92 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Folder.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import javax.persistence.Entity; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +/** + * Entity class of a folder in the doc-repository. Instances will be persisted + * into the database. Instance variables are inherited from {@link Resource}. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity +@Table(schema = "CCM_DOCREPO", name = "FOLDERS") +public class Folder extends Resource { + + private static final long serialVersionUID = 1561466556458872622L; + + /** + * The {@link Repository} this {@code Folder} is assigned to as root. + */ + @OneToOne(mappedBy = "rootFolder") + private Repository repository; + + /** + * Constructor calls the super-class-constructor of {@link Resource}. + */ + public Folder() { + super(); + } + + //> Begin GETTER & SETTER + + public Repository getRepository() { + return repository; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + //< End GETTER & SETTER +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RecUpdDocsPortlet.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RecUpdDocsPortlet.java new file mode 100644 index 000000000..41ae4cca2 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RecUpdDocsPortlet.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import org.libreccm.portal.Portlet; + +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * Entity class for a portlet of recent updated documents in the doc-repository. + * Instances will be persisted into the database. Instance variables are inherited + * form {@link Portlet}. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity +@Table(schema = "CCM_DOCREPO", name = "REC_UPD_DOCS_PORTLETS") +public class RecUpdDocsPortlet extends Portlet { + + private static final long serialVersionUID = -4091024367070127101L; + + /** + * Constructor calls the super-class-constructor of {@link Portlet}. + */ + public RecUpdDocsPortlet() { + super(); + } +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Repository.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Repository.java new file mode 100644 index 000000000..dc0ff2f16 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Repository.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import org.hibernate.validator.constraints.NotBlank; +import org.libreccm.security.User; +import org.libreccm.web.CcmApplication; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import java.util.List; + +/** + * Entity class of a repository for documents. Instances will be persisted into + * the database. Instance variables are inherited from {@link CcmApplication}. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity +@Table(schema = "CCM_DOCREPO", name = "REPOSITORIES") +@NamedQueries({ + @NamedQuery(name = "DocRepo.findRepositoriesForOwner", + query = "SELECT r FROM Repository r WHERE r.owner = :owner") +}) +public class Repository extends CcmApplication { + + private static final long serialVersionUID = 6673243021462798036L; + + /** + * Name des {@code Repository}s. + */ + @Column(name = "NAME", length = 512, unique = true, nullable = false) + @NotBlank + private String name; + + /** + * The root of the {@code Repository}. + */ + @OneToOne + @JoinColumn(name = "ROOT_FOLDER_ID", unique = true, nullable = false) + @NotBlank + private Folder rootFolder; + + /** + * The owner of the {@code Repository}. + */ + @OneToOne + @JoinColumn(name = "OWNER_ID", nullable = false) + @NotBlank + private User owner; + + /** + * All {@link Resource}s contained in this {@code Repository}. + */ + @OneToMany(mappedBy = "repository") + private List resources; + + + /** + * Constructor calls the super-class-constructor of {@link CcmApplication}. + */ + public Repository() { + super(); + } + + //> Begin GETTER & SETTER + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Folder getRootFolder() { + return rootFolder; + } + + public void setRootFolder(Folder root_folder) { + this.rootFolder = root_folder; + } + + public User getOwner() { + return owner; + } + + public void setOwner(User owner) { + this.owner = owner; + } + + public List getResources() { + return resources; + } + + public void setResources(List resources) { + this.resources = resources; + } + + //< End GETTER & SETTER + + +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RepositoryRepository.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RepositoryRepository.java new file mode 100644 index 000000000..5bda9b246 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/RepositoryRepository.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import org.libreccm.auditing.AbstractAuditedEntityRepository; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.PermissionChecker; +import org.libreccm.security.User; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Repository class for retrieving, storing and deleting {@code Repository}s. + * + * @author Tobias Osmers + * @version 25/11/2015 + */ +@RequestScoped +public class RepositoryRepository extends + AbstractAuditedEntityRepository { + + @Inject + private EntityManager entityManager; + + @Override + public Long getEntityId(Repository entity) { + return entity.getObjectId(); + } + + @Override + public Class getEntityClass() { + return Repository.class; + } + + @Override + public boolean isNew(Repository entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity to save can't be null."); + } + return entity.getObjectId() == 0; + } + + /** + * Checks if the current subject has permissions grating him the + * privilege to read the requested {@link Repository}(s) and removes the + * ones he is not allowed to access. + * + * @param repositories The requested {@link Resource}s, found in the database + * @return A list of {@link Resource}s the subject is allowed to access + */ + private List permissionFilter(List repositories) { + final CdiUtil cdiUtil = new CdiUtil(); + final PermissionChecker permissionChecker = cdiUtil.findBean( + PermissionChecker.class); + return repositories.stream().filter(repository -> permissionChecker + .isPermitted("read", repository)).collect(Collectors.toList()); + } + + /** + * Retrieve all {@link Repository}s a given {@link User} ownes. + * + * @param owner The owner of the {@link Repository}s + * + * @return The {@link Repository}s owned by the given {@link User} + */ + public List findForOwner(User owner) { + final TypedQuery query = entityManager.createNamedQuery( + "DocRepo.findRepositoriesForOwner", Repository.class); + query.setParameter("owner", owner); + + return permissionFilter(query.getResultList()); + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Resource.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Resource.java new file mode 100644 index 000000000..24f8489c9 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/Resource.java @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import org.hibernate.validator.constraints.NotBlank; +import org.libreccm.core.CcmObject; +import org.libreccm.security.User; + +import javax.activation.MimeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import java.util.Date; +import java.util.List; + + +/** + * Abstract entity class of a resource. Instances will be persisted into the + * database through the inheriting subclasses. + * + * The inheriting subclasses and therefore resources are: {@link File}, + * {@link Folder} + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@Entity(name = "DocRepoResource") +@Table(schema = "CCM_DOCREPO", name = "RESOURCES") +@NamedQueries({ + @NamedQuery(name = "DocRepo.findResourceByPath", + query = "SELECT r FROM DocRepoResource r WHERE " + + "r.path = :pathName"), + @NamedQuery(name = "DocRepo.findResourcesByName", + query = "SELECT r FROM DocRepoResource r WHERE " + + "r.name = :name"), + @NamedQuery(name = "DocRepo.findCreatedResourcesFromUser", + query = "SELECT r FROM DocRepoResource r WHERE " + + "r.creationUser = :user"), + @NamedQuery(name = "DocRepo.findModifiedResourcesFromUser", + query = "SELECT r FROM DocRepoResource r WHERE " + + "r.lastModifiedUser = :user")}) +public abstract class Resource extends CcmObject { + + private static final long serialVersionUID = -910317798106611214L; + + /** + * Name of the {@code Resource}. + */ + @Column(name = "NAME", length = 512, unique = true, nullable = false) + @NotBlank + private String name; + + /** + * Description of the {@code Resource}. + */ + @Column(name = "DESCRIPTION") + private String description; + + /** + * Flag, wheather the {@code Resource} is a {@link Folder} or not. + */ + @Column(name = "IS_FOLDER") + @NotBlank + private boolean isFolder; + + /** + * Path to the {@code Resource}. + */ + @Column(name = "PATH", unique = true) + @NotBlank + private String path; + + /** + * Mime-type of the {@code Resource}. + */ + @Column(name = "MIME_TYPE") + private MimeType mimeType; + + /** + * Size of the {@code Resource}. + */ + @Column(name = "SIZE") + private long size; + + /** + * Content of the {@code Resource} as a {@link BlobObject}. + */ + @OneToOne + @JoinColumn(name = "CONTENT_ID") + private BlobObject content; + + /** + * Creation date of the {@code Resource}. + */ + @Column(name = "CREATION_DATE") + @NotBlank + @Temporal(TemporalType.TIMESTAMP) + private Date creationDate; + + /** + * Date of the latest modification of the {@code Resource}. + */ + @Column(name = "LAST_MODIFIED_DATE") + @NotBlank + @Temporal(TemporalType.TIMESTAMP) + private Date lastModifiedDate; + + /** + * Creation ip of the {@code Resource}. + */ + @Column(name = "CREATION_IP") + private String creationIp; + + /** + * Ip of the latest modification of the {@code Resource}. + */ + @Column(name = "LAST_MODIFIED_IP") + private String lastModifiedIp; + + /** + * The {@link User}, who created the {@code Resource}. + */ + @ManyToOne + @JoinColumn(name = "CREATION_USER_ID") + private User creationUser; + + /** + * The {@link User}, who last modified the {@code Resource}. + */ + @ManyToOne + @JoinColumn(name = "LAST_MODIFIED_USER_ID") + private User lastModifiedUser; + + /** + * The parent-{@code Resource} of the {@code Resource}. + */ + @ManyToOne + @JoinColumn(name = "PARENT_ID") + private Resource parent; + + /** + * The child-{@code Resource}s of the {@code Resource}. + */ + @OneToMany(mappedBy = "parent") + private List immediateChildren; + + /** + * The {@link Repository} containing this {@code Resource}. + */ + @ManyToOne + @JoinColumn(name = "REPOSITORY_ID") + private Repository repository; + + /** + * Constructor calls the super-class-constructor of {@link CcmObject}. + */ + public Resource() { + super(); + } + + //> Begin GETTER & SETTER + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isFolder() { + return isFolder; + } + + public void setIsFolder(boolean isFolder) { + this.isFolder = isFolder; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public MimeType getMimeType() { + return mimeType; + } + + public void setMimeType(MimeType mimeType) { + this.mimeType = mimeType; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public BlobObject getContent() { + return content; + } + + public void setContent(BlobObject content) { + this.content = content; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public Date getLastModifiedDate() { + return lastModifiedDate; + } + + public void setLastModifiedDate(Date lastModifiedDate) { + this.lastModifiedDate = lastModifiedDate; + } + + public String getCreationIp() { + return creationIp; + } + + public void setCreationIp(String creationIp) { + this.creationIp = creationIp; + } + + public String getLastModifiedIp() { + return lastModifiedIp; + } + + public void setLastModifiedIp(String lastModifiedIp) { + this.lastModifiedIp = lastModifiedIp; + } + + public User getCreationUser() { + return creationUser; + } + + public void setCreationUser(User creationUser) { + this.creationUser = creationUser; + } + + public User getLastModifiedUser() { + return lastModifiedUser; + } + + public void setLastModifiedUser(User lastModifiedUser) { + this.lastModifiedUser = lastModifiedUser; + } + + public Resource getParent() { + return parent; + } + + public void setParent(Resource parent) { + this.parent = parent; + } + + public List getImmediateChildren() { + return immediateChildren; + } + + public void setImmediateChildren(List immediateChildren) { + this.immediateChildren = immediateChildren; + } + + public Repository getRepository() { + return repository; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + //< End GETTER & SETTER + + public boolean isRoot() { + return isFolder() && getParent() == null; + } + + public boolean isFile() { + return !isFolder(); + } +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceManager.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceManager.java new file mode 100644 index 000000000..4d1286929 --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceManager.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + +import org.apache.log4j.Logger; +import org.apache.oro.text.perl.Perl5Util; + +import javax.activation.MimetypesFileTypeMap; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; + +/** + * Manager class for complex operations on {@code Resource}-objects. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@RequestScoped +public class ResourceManager { + private static final Logger log = Logger.getLogger(ResourceManager.class); + + @Inject + private ResourceRepository resourceRepository; + + /** + * Copies a given {@link Resource} to a given {@link Folder}. + * + * @param original The {@link Resource} to be copied + * @param folder The {@link Folder} to copy to + */ + public void copyToFolder(Resource original, Folder folder) { + Resource copy = original.isFolder() ? new Folder() : new File(); + copy.setName(original.getName()); + copy.setDescription(original.getDescription()); + copy.setIsFolder(original.isFolder()); + copy.setPath(String.format("%s/%s", folder.getPath(), copy.getName())); + copy.setMimeType(original.getMimeType()); + copy.setSize(original.getSize()); + copy.setContent(original.getContent()); + + copy.setParent(folder); + copy.setImmediateChildren(original.getImmediateChildren()); + + resourceRepository.save(copy); + } + + /** + * Determines weather the given name is a valid new name for the also + * given {@link Resource}. + * + * Verifies that the string only contains valid characters for + * {@link Resource} names. The following name patterns are allowed: + * + * [a-z][A-Z][0-9][-., ] + * + * In addition, names cannot begin with ".", i.e. we do NOT support file + * names like ".profile" at the moment. The current implementation does + * not allow international characters for resource names. + * + * @param name The resource name for validation + * @param resource The resource for which the new name needs to be validated + * + * @return true for a system-valid resource name, otherwise false + */ + public boolean isValidNewResourceName(String name, Resource resource) { + Perl5Util perl5Util = new Perl5Util(); + + final String INVALID_START_PATTERN = "/^[.]+/"; + final String INVALID_NAME_PATTERN = "/[^a-zA-Z0-9\\_\\.\\-\\ ]+/"; + final String EXTENSION_PATTERN = "/^([^\\.].*)(\\.\\w+)$/"; + + // adds an extension if non-existent + if (!perl5Util.match(EXTENSION_PATTERN, name)) { + if (perl5Util.match(EXTENSION_PATTERN, resource.getName())) { + name += perl5Util.group(2); + } + } + + // checks pattern of the name + boolean validName = !(perl5Util.match(INVALID_START_PATTERN, name) || + perl5Util.match(INVALID_NAME_PATTERN, name)); + + // checks duplication of the name; database access (mind performance) + validName &= resourceRepository.findByName(name).isEmpty(); + + // checks that the name corresponds to a compatible MIME type + validName &= new MimetypesFileTypeMap().getContentType(name).equals + (resource.getMimeType().toString()); + + return validName; + } +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceRepository.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceRepository.java new file mode 100644 index 000000000..1f206898b --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/ResourceRepository.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo; + + +import org.libreccm.auditing.AbstractAuditedEntityRepository; +import org.libreccm.cdi.utils.CdiUtil; +import org.libreccm.security.PermissionChecker; +import org.libreccm.security.User; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Repository class for retrieving, storing and deleting {@code Resource}s. + * + * @author Tobias Osmers + * @version 01/10/2015 + */ +@RequestScoped +public class ResourceRepository extends AbstractAuditedEntityRepository { + + @Inject + private EntityManager entityManager; + + @Override + public Long getEntityId(Resource entity) { + return entity.getObjectId(); + } + + @Override + public Class getEntityClass() { + return Resource.class; + } + + @Override + public boolean isNew(Resource entity) { + if (entity == null) { + throw new IllegalArgumentException("Entity to save can't be null."); + } + return entity.getObjectId() == 0; + } + + /** + * Checks if the current subject has permissions grating him the + * privilege to read the requested {@link Resource}(s) and removes the + * ones he is not allowed to access. + * + * @param resources The requested {@link Resource}s, found in the database + * @return A list of {@link Resource}s the subject is allowed to access + */ + private List permissionFilter(List resources) { + final CdiUtil cdiUtil = new CdiUtil(); + final PermissionChecker permissionChecker = cdiUtil.findBean( + PermissionChecker.class); + return resources.stream().filter(resource -> permissionChecker + .isPermitted("read", resource)).collect(Collectors.toList()); + } + + /** + * Checks if the current subject has permissions grating him the + * privilege to read the one requested {@link Resource} and removes it if + * he is not allowed to access. + * + * @param resource The requested {@link Resource}, found in the database + * @return A list of at most one {@link Resource} the subject is allowed to + * access + */ + private Resource permissionFilter(Resource resource) { + return permissionFilter(Arrays.asList(resource)).get(0); + } + + /** + * Retrieve a {@code Resource} by its {@code path}. + * + * @param pathName The {@code path} to the {@code Resource}. + * + * @return The {@code Resource} identified by the given {@code path}, if there is + * such a {@code Resource}, {@code null} if not. + */ + public Resource findByPathName(final String pathName) { + final TypedQuery query = entityManager.createNamedQuery( + "DocRepo.findResourceByPath", Resource.class); + query.setParameter("pathName", pathName); + + return permissionFilter(query.getSingleResult()); + } + + /** + * Retrieve the {@code Resource}s, a given {@link User} created. + * + * @param creator The {@link User}, who created the {@code Resource}s. + * + * @return The {@code Resource}s, created by the given {@link User}, if there + * are such {@code Resource}s, {@code EmptyList} if not. + */ + public List findForCreator(final User creator) { + final TypedQuery query = entityManager.createNamedQuery( + "DocRepo.findCreatedResourcesFromUser", Resource.class); + query.setParameter("user", creator); + + return permissionFilter(query.getResultList()); + } + + /** + * Retrieve the {@code Resource}s, a given {@link User} last modified. + * + * @param modifier The {@link User}, who last modified the {@code Resource}s. + * + * @return The {@code Resource}s, last modified by the given {@link User}, if + * there are such {@code Resource}s, {@code EmptyList} if not. + */ + public List findForModifier(final User modifier) { + final TypedQuery query = entityManager.createNamedQuery( + "DocRepo.findModifiedResourcesFromUser", Resource.class); + query.setParameter("user", modifier); + + return permissionFilter(query.getResultList()); + } + + /** + * Retrieve all {@link Resource}s with the given name. + * + * @param name The name for the searched {@link Resource} + * @return The {@link Resource}s with the given name, if there aren't + * any an {@code EmptyList} + */ + public List findByName(final String name) { + final TypedQuery query = entityManager.createNamedQuery( + "DocRepo.findResourcesByName", Resource.class); + query.setParameter("name", name); + + return permissionFilter(query.getResultList()); + } +} diff --git a/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/exchange/exporter/ResourceExporter.java b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/exchange/exporter/ResourceExporter.java new file mode 100644 index 000000000..aaaea7f5e --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/exchange/exporter/docrepo/exchange/exporter/ResourceExporter.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 LibreCCM Foundation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +package org.libreccm.exchange.exporter.docrepo.exchange; + +import org.libreccm.exchange.exporter.ObjectExporter; +import org.libreccm.exchange.exporter.docrepo.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Exporter class for resources. Implements the abstract method of its super. + * + * @author Tobias Osmers + * @version 13/01/2016 + */ +public class ResourceExporter extends ObjectExporter { + @Override + public List asList(List exportObjects) { + List exportList = new ArrayList<>(); + + exportList.add(new String[]{Resource.class.getName()}); + exportList.add(new String[]{ + "name", + "description", + "isFolder", + "path", + "mimeType", + "size", + "blobObject_ID", + "creationDate", + "lastModifiedDate", + "creationIP", + "lastModifiedIp", + "creator_ID", + "modifier_ID", + "parent_ID", + "repo_ID" + }); + + return exportList.addAll(exportObjects.stream().map( + this::reduceToString).collect(Collectors.toList())) + ? exportList : exportList; + } + + @Override + protected String[] reduceToString(Resource exportObject) { + return new String[] { + // name + exportObject.getName(), + // description + exportObject.getDescription(), + // isFolder + String.valueOf(exportObject.isFolder()), + // path + exportObject.getPath(), + // mimeType + exportObject.getMimeType().toString(), + // size + String.valueOf(exportObject.getSize()), + // blobObject_ID + String.valueOf(exportObject.getContent().getBlobObjectId()), + // creationDate + exportObject.getCreationDate().toString(), + // lastModifiedDate + exportObject.getLastModifiedDate().toString(), + // creationIp + exportObject.getCreationIp(), + // lastModifiedIp + exportObject.getLastModifiedIp(), + // creator_ID + exportObject.getCreationUser().getName(), + // modifier_ID + exportObject.getLastModifiedUser().getName(), + // parent_ID + String.valueOf(exportObject.getParent().getObjectId()), + // repo_ID + String.valueOf(exportObject.getRepository().getObjectId()), + }; + } +} diff --git a/pom.xml b/pom.xml index 365114234..429e74431 100644 --- a/pom.xml +++ b/pom.xml @@ -425,6 +425,12 @@ xml-resolver 1.2 + + + com.opencsv + opencsv + 3.6 +