mirror of
https://github.com/sismics/docs.git
synced 2024-12-24 04:03:49 +01:00
Initial commit
This commit is contained in:
parent
41cb6dd9ae
commit
9b74bd8194
15
.gitattributes
vendored
Normal file
15
.gitattributes
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Set default behaviour, in case users don't have core.autocrlf set.
|
||||
* text=auto
|
||||
|
||||
# Explicitly declare text files we want to always be normalized and converted
|
||||
# to native line endings on checkout.
|
||||
*.c text
|
||||
*.h text
|
||||
|
||||
# Declare files that will always have CRLF line endings on checkout.
|
||||
*.sln text eol=crlf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
/*/.classpath
|
||||
/*/.project
|
||||
/*/.settings
|
||||
/*/bin
|
||||
/*/gen
|
||||
/*/target
|
||||
/*/*.iml
|
185
docs-core/pom.xml
Normal file
185
docs-core/pom.xml
Normal file
@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../docs-parent</relativePath>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>docs-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Docs Core</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- Persistence layer dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Other external dependencies -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mindrot</groupId>
|
||||
<artifactId>jbcrypt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ccil.cowan.tagsoup</groupId>
|
||||
<artifactId>tagsoup</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
|
||||
<artifactId>owasp-java-html-sanitizer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-queryparser</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-highlighter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bitlet</groupId>
|
||||
<artifactId>weupnp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<!-- Development profile (active by default) -->
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
<property>
|
||||
<name>env</name>
|
||||
<value>dev</value>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/dev/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Production profile -->
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
</profile>
|
||||
|
||||
<!-- Demo profile -->
|
||||
<profile>
|
||||
<id>demo</id>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/demo/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,13 @@
|
||||
package com.sismics.docs.core.constant;
|
||||
|
||||
/**
|
||||
* Configuration parameters.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public enum ConfigType {
|
||||
/**
|
||||
* Lucene directory storage type.
|
||||
*/
|
||||
LUCENE_DIRECTORY_STORAGE,
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.sismics.docs.core.constant;
|
||||
|
||||
/**
|
||||
* Application constants.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class Constants {
|
||||
/**
|
||||
* Default locale.
|
||||
*/
|
||||
public static final String DEFAULT_LOCALE_ID = "en";
|
||||
|
||||
/**
|
||||
* Default timezone ID.
|
||||
*/
|
||||
public static final String DEFAULT_TIMEZONE_ID = "Europe/London";
|
||||
|
||||
/**
|
||||
* Default theme ID.
|
||||
*/
|
||||
public static final String DEFAULT_THEME_ID = "default.less";
|
||||
|
||||
/**
|
||||
* Administrator's default password ("admin").
|
||||
*/
|
||||
public static final String DEFAULT_ADMIN_PASSWORD = "$2a$05$6Ny3TjrW3aVAL1or2SlcR.fhuDgPKp5jp.P9fBXwVNePgeLqb4i3C";
|
||||
|
||||
/**
|
||||
* RAM Lucene directory storage.
|
||||
*/
|
||||
public static final String LUCENE_DIRECTORY_STORAGE_RAM = "RAM";
|
||||
|
||||
/**
|
||||
* File Lucene directory storage.
|
||||
*/
|
||||
public static final String LUCENE_DIRECTORY_STORAGE_FILE = "FILE";
|
||||
|
||||
/**
|
||||
* Default generic user role.
|
||||
*/
|
||||
public static final String DEFAULT_USER_ROLE = "admin";
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.sismics.docs.core.dao.file.theme;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
|
||||
/**
|
||||
* Theme DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ThemeDao {
|
||||
private final static FilenameFilter CSS_FILTER = new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.endsWith(".css") || name.endsWith(".less");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the list of all themes.
|
||||
*
|
||||
* @return List of themes
|
||||
*/
|
||||
public List<String> findAll() {
|
||||
final File themeDirectory = DirectoryUtil.getThemeDirectory();
|
||||
if (themeDirectory != null) {
|
||||
return Lists.newArrayList(themeDirectory.list(CSS_FILTER));
|
||||
} else {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.sismics.docs.core.model.jpa.AuthenticationToken;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Authentication token DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class AuthenticationTokenDao {
|
||||
/**
|
||||
* Gets an authentication token.
|
||||
*
|
||||
* @param id Authentication token ID
|
||||
* @return Authentication token
|
||||
*/
|
||||
public AuthenticationToken get(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
return em.find(AuthenticationToken.class, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new authentication token.
|
||||
*
|
||||
* @param authenticationToken Authentication token
|
||||
* @return Authentication token ID
|
||||
*/
|
||||
public String create(AuthenticationToken authenticationToken) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
authenticationToken.setId(UUID.randomUUID().toString());
|
||||
authenticationToken.setCreationDate(new Date());
|
||||
em.persist(authenticationToken);
|
||||
|
||||
return authenticationToken.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the authentication token.
|
||||
*
|
||||
* @param authenticationTokenId Authentication token ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public void delete(String authenticationTokenId) throws Exception {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
AuthenticationToken authenticationToken = em.find(AuthenticationToken.class, authenticationTokenId);
|
||||
if (authenticationToken != null) {
|
||||
em.remove(authenticationToken);
|
||||
} else {
|
||||
throw new Exception("Token not found: " + authenticationTokenId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes old short lived tokens.
|
||||
*
|
||||
* @param userId User ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public void deleteOldSessionToken(String userId) {
|
||||
StringBuilder sb = new StringBuilder("delete from T_AUTHENTICATION_TOKEN AS ato ");
|
||||
sb.append(" where ato.AUT_IDUSER_C = :userId and ato.AUT_LONGLASTED_B = :longLasted");
|
||||
sb.append(" and ato.AUT_LASTCONNECTIONDATE_D < :minDate ");
|
||||
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createNativeQuery(sb.toString());
|
||||
q.setParameter("userId", userId);
|
||||
q.setParameter("longLasted", false);
|
||||
q.setParameter("minDate", DateTime.now().minusDays(1).toDate());
|
||||
q.executeUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes old short lived tokens.
|
||||
*
|
||||
* @param id Token id
|
||||
* @throws Exception
|
||||
*/
|
||||
public void updateLastConnectionDate(String id) {
|
||||
StringBuilder sb = new StringBuilder("update T_AUTHENTICATION_TOKEN ato ");
|
||||
sb.append(" set ato.AUT_LASTCONNECTIONDATE_D = :currentDate ");
|
||||
sb.append(" where ato.AUT_ID_C = :id");
|
||||
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createNativeQuery(sb.toString());
|
||||
q.setParameter("currentDate", new Date());
|
||||
q.setParameter("id", id);
|
||||
q.executeUpdate();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
|
||||
import com.sismics.docs.core.constant.ConfigType;
|
||||
import com.sismics.docs.core.model.jpa.Config;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Configuration parameter DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ConfigDao {
|
||||
/**
|
||||
* Gets a configuration parameter by its ID.
|
||||
*
|
||||
* @param id Configuration parameter ID
|
||||
* @return Configuration parameter
|
||||
*/
|
||||
public Config getById(ConfigType id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Prevents from getting parameters outside of a transactional context (e.g. jUnit)
|
||||
if (em == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return em.find(Config.class, id);
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
|
||||
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
|
||||
import com.sismics.docs.core.model.jpa.Document;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedLists;
|
||||
import com.sismics.docs.core.util.jpa.QueryParam;
|
||||
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Document DAO.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class DocumentDao {
|
||||
/**
|
||||
* Creates a new document.
|
||||
*
|
||||
* @param document Document
|
||||
* @return New ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public String create(Document document) {
|
||||
// Create the UUID
|
||||
document.setId(UUID.randomUUID().toString());
|
||||
|
||||
// Create the document
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
document.setCreateDate(new Date());
|
||||
em.persist(document);
|
||||
|
||||
return document.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an active document.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @param userId User ID
|
||||
* @return Document
|
||||
*/
|
||||
public Document getDocument(String id, String userId) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createQuery("select d from Document d where d.id = :id and d.userId = :userId and d.deleteDate is null");
|
||||
q.setParameter("id", id);
|
||||
q.setParameter("userId", userId);
|
||||
return (Document) q.getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a document.
|
||||
*
|
||||
* @param id Document ID
|
||||
*/
|
||||
public void delete(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the document
|
||||
Query q = em.createQuery("select d from Document d where d.id = :id and d.deleteDate is null");
|
||||
q.setParameter("id", id);
|
||||
Document documentDb = (Document) q.getSingleResult();
|
||||
|
||||
// Delete the document
|
||||
Date dateNow = new Date();
|
||||
documentDb.setDeleteDate(dateNow);
|
||||
|
||||
// Delete linked data
|
||||
q = em.createQuery("update File f set f.deleteDate = :dateNow where f.documentId = :documentId and f.deleteDate is null");
|
||||
q.setParameter("documentId", documentDb.getId());
|
||||
q.setParameter("dateNow", dateNow);
|
||||
q.executeUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a document by its ID.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Document
|
||||
*/
|
||||
public Document getById(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
return em.find(Document.class, id);
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches documents by criteria.
|
||||
*
|
||||
* @param paginatedList List of documents (updated by side effects)
|
||||
* @param criteria Search criteria
|
||||
* @return List of document
|
||||
*/
|
||||
public void findByCriteria(PaginatedList<DocumentDto> paginatedList, DocumentCriteria criteria, SortCriteria sortCriteria) {
|
||||
Map<String, Object> parameterMap = new HashMap<String, Object>();
|
||||
|
||||
StringBuilder sb = new StringBuilder("select d.DOC_ID_C c0, d.DOC_TITLE_C c1, d.DOC_DESCRIPTION_C c2, d.DOC_CREATEDATE_D c3");
|
||||
sb.append(" from T_DOCUMENT d ");
|
||||
|
||||
// Adds search criteria
|
||||
List<String> criteriaList = new ArrayList<String>();
|
||||
if (criteria.getUserId() != null) {
|
||||
criteriaList.add("d.DOC_IDUSER_C = :userId");
|
||||
parameterMap.put("userId", criteria.getUserId());
|
||||
}
|
||||
|
||||
if (!criteriaList.isEmpty()) {
|
||||
sb.append(" where ");
|
||||
sb.append(Joiner.on(" and ").join(criteriaList));
|
||||
}
|
||||
|
||||
// Perform the search
|
||||
QueryParam queryParam = new QueryParam(sb.toString(), parameterMap);
|
||||
List<Object[]> l = PaginatedLists.executePaginatedQuery(paginatedList, queryParam, sortCriteria);
|
||||
|
||||
// Assemble results
|
||||
List<DocumentDto> documentDtoList = new ArrayList<DocumentDto>();
|
||||
for (Object[] o : l) {
|
||||
int i = 0;
|
||||
DocumentDto documentDto = new DocumentDto();
|
||||
documentDto.setId((String) o[i++]);
|
||||
documentDto.setTitle((String) o[i++]);
|
||||
documentDto.setDescription((String) o[i++]);
|
||||
documentDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
||||
documentDtoList.add(documentDto);
|
||||
}
|
||||
|
||||
paginatedList.setResultList(documentDtoList);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import com.sismics.docs.core.model.jpa.File;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* File DAO.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class FileDao {
|
||||
/**
|
||||
* Creates a new file.
|
||||
*
|
||||
* @param file File
|
||||
* @return New ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public String create(File file) {
|
||||
// Create the UUID
|
||||
file.setId(UUID.randomUUID().toString());
|
||||
|
||||
// Create the file
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
file.setCreateDate(new Date());
|
||||
em.persist(file);
|
||||
|
||||
return file.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an active file.
|
||||
*
|
||||
* @param id File ID
|
||||
* @return Document
|
||||
*/
|
||||
public File getFile(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
|
||||
q.setParameter("id", id);
|
||||
return (File) q.getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file.
|
||||
*
|
||||
* @param id File ID
|
||||
*/
|
||||
public void delete(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the document
|
||||
Query q = em.createQuery("select f from File f where f.id = :id and f.deleteDate is null");
|
||||
q.setParameter("id", id);
|
||||
File fileDb = (File) q.getSingleResult();
|
||||
|
||||
// Delete the document
|
||||
Date dateNow = new Date();
|
||||
fileDb.setDeleteDate(dateNow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a file by its ID.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Document
|
||||
*/
|
||||
public File getById(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
return em.find(File.class, id);
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get files by document ID.
|
||||
*
|
||||
* @param documentId Document ID
|
||||
* @return List of files
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<File> getByDocumentId(String documentId) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the files
|
||||
Query q = em.createQuery("select f from File f where f.documentId = :documentId and f.deleteDate is null");
|
||||
q.setParameter("documentId", documentId);
|
||||
List<File> files = (List<File>) q.getResultList();
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import com.sismics.docs.core.model.jpa.Locale;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Locale DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class LocaleDao {
|
||||
/**
|
||||
* Gets a locale by its ID.
|
||||
*
|
||||
* @param id Locale ID
|
||||
* @return Locale
|
||||
*/
|
||||
public Locale getById(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
return em.find(Locale.class, id);
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all locales.
|
||||
*
|
||||
* @return List of locales
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Locale> findAll() {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createQuery("select l from Locale l order by l.id");
|
||||
return q.getResultList();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Role base functions DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class RoleBaseFunctionDao {
|
||||
/**
|
||||
* Find the set of base functions of a role.
|
||||
*
|
||||
* @param roleId Role ID
|
||||
* @return Set of base functions
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<String> findByRoleId(String roleId) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
StringBuilder sb = new StringBuilder("select rbf.RBF_IDBASEFUNCTION_C from T_ROLE_BASE_FUNCTION rbf, T_ROLE r");
|
||||
sb.append(" where rbf.RBF_IDROLE_C = :roleId and rbf.RBF_DELETEDATE_D is null");
|
||||
sb.append(" and r.ROL_ID_C = rbf.RBF_IDROLE_C and r.ROL_DELETEDATE_D is null");
|
||||
Query q = em.createNativeQuery(sb.toString());
|
||||
q.setParameter("roleId", roleId);
|
||||
return Sets.newHashSet(q.getResultList());
|
||||
}
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.dto.UserDto;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedLists;
|
||||
import com.sismics.docs.core.util.jpa.QueryParam;
|
||||
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* User DAO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class UserDao {
|
||||
/**
|
||||
* Authenticates an user.
|
||||
*
|
||||
* @param username User login
|
||||
* @param password User password
|
||||
* @return ID of the authenticated user or null
|
||||
*/
|
||||
public String authenticate(String username, String password) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createQuery("select u from User u where u.username = :username and u.deleteDate is null");
|
||||
q.setParameter("username", username);
|
||||
try {
|
||||
User user = (User) q.getSingleResult();
|
||||
if (!BCrypt.checkpw(password, user.getPassword())) {
|
||||
return null;
|
||||
}
|
||||
return user.getId();
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new user.
|
||||
*
|
||||
* @param user User to create
|
||||
* @return User ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public String create(User user) throws Exception {
|
||||
// Create the user UUID
|
||||
user.setId(UUID.randomUUID().toString());
|
||||
|
||||
// Checks for user unicity
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query q = em.createQuery("select u from User u where u.username = :username and u.deleteDate is null");
|
||||
q.setParameter("username", user.getUsername());
|
||||
List<?> l = q.getResultList();
|
||||
if (l.size() > 0) {
|
||||
throw new Exception("AlreadyExistingUsername");
|
||||
}
|
||||
|
||||
user.setCreateDate(new Date());
|
||||
user.setPassword(hashPassword(user.getPassword()));
|
||||
user.setTheme(Constants.DEFAULT_THEME_ID);
|
||||
em.persist(user);
|
||||
|
||||
return user.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a user.
|
||||
*
|
||||
* @param user User to update
|
||||
* @return Updated user
|
||||
*/
|
||||
public User update(User user) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the user
|
||||
Query q = em.createQuery("select u from User u where u.id = :id and u.deleteDate is null");
|
||||
q.setParameter("id", user.getId());
|
||||
User userFromDb = (User) q.getSingleResult();
|
||||
|
||||
// Update the user
|
||||
userFromDb.setLocaleId(user.getLocaleId());
|
||||
userFromDb.setEmail(user.getEmail());
|
||||
userFromDb.setTheme(user.getTheme());
|
||||
userFromDb.setFirstConnection(user.isFirstConnection());
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user password.
|
||||
*
|
||||
* @param user User to update
|
||||
* @return Updated user
|
||||
*/
|
||||
public User updatePassword(User user) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the user
|
||||
Query q = em.createQuery("select u from User u where u.id = :id and u.deleteDate is null");
|
||||
q.setParameter("id", user.getId());
|
||||
User userFromDb = (User) q.getSingleResult();
|
||||
|
||||
// Update the user
|
||||
userFromDb.setPassword(hashPassword(user.getPassword()));
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a user by its ID.
|
||||
*
|
||||
* @param id User ID
|
||||
* @return User
|
||||
*/
|
||||
public User getById(String id) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
return em.find(User.class, id);
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an active user by its username.
|
||||
*
|
||||
* @param username User's username
|
||||
* @return User
|
||||
*/
|
||||
public User getActiveByUsername(String username) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
Query q = em.createQuery("select u from User u where u.username = :username and u.deleteDate is null");
|
||||
q.setParameter("username", username);
|
||||
return (User) q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an active user by its password recovery token.
|
||||
*
|
||||
* @param passwordResetKey Password recovery token
|
||||
* @return User
|
||||
*/
|
||||
public User getActiveByPasswordResetKey(String passwordResetKey) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
try {
|
||||
Query q = em.createQuery("select u from User u where u.passwordResetKey = :passwordResetKey and u.deleteDate is null");
|
||||
q.setParameter("passwordResetKey", passwordResetKey);
|
||||
return (User) q.getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a user.
|
||||
*
|
||||
* @param username User's username
|
||||
*/
|
||||
public void delete(String username) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
// Get the user
|
||||
Query q = em.createQuery("select u from User u where u.username = :username and u.deleteDate is null");
|
||||
q.setParameter("username", username);
|
||||
User userFromDb = (User) q.getSingleResult();
|
||||
|
||||
// Delete the user
|
||||
Date dateNow = new Date();
|
||||
userFromDb.setDeleteDate(dateNow);
|
||||
|
||||
// Delete linked data
|
||||
q = em.createQuery("delete from AuthenticationToken at where at.userId = :userId");
|
||||
q.setParameter("userId", userFromDb.getId());
|
||||
q.executeUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the user's password.
|
||||
*
|
||||
* @param password Clear password
|
||||
* @return Hashed password
|
||||
*/
|
||||
protected String hashPassword(String password) {
|
||||
return BCrypt.hashpw(password, BCrypt.gensalt());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all users.
|
||||
*
|
||||
* @param paginatedList List of users (updated by side effects)
|
||||
* @param sortCriteria Sort criteria
|
||||
*/
|
||||
public void findAll(PaginatedList<UserDto> paginatedList, SortCriteria sortCriteria) {
|
||||
Map<String, Object> parameterMap = new HashMap<String, Object>();
|
||||
StringBuilder sb = new StringBuilder("select u.USE_ID_C as c0, u.USE_USERNAME_C as c1, u.USE_EMAIL_C as c2, u.USE_CREATEDATE_D as c3, u.USE_IDLOCALE_C as c4");
|
||||
sb.append(" from T_USER u ");
|
||||
|
||||
// Add search criterias
|
||||
List<String> criteriaList = new ArrayList<String>();
|
||||
criteriaList.add("u.USE_DELETEDATE_D is null");
|
||||
|
||||
if (!criteriaList.isEmpty()) {
|
||||
sb.append(" where ");
|
||||
sb.append(Joiner.on(" and ").join(criteriaList));
|
||||
}
|
||||
|
||||
// Perform the search
|
||||
QueryParam queryParam = new QueryParam(sb.toString(), parameterMap);
|
||||
List<Object[]> l = PaginatedLists.executePaginatedQuery(paginatedList, queryParam, sortCriteria);
|
||||
|
||||
// Assemble results
|
||||
List<UserDto> userDtoList = new ArrayList<UserDto>();
|
||||
for (Object[] o : l) {
|
||||
int i = 0;
|
||||
UserDto userDto = new UserDto();
|
||||
userDto.setId((String) o[i++]);
|
||||
userDto.setUsername((String) o[i++]);
|
||||
userDto.setEmail((String) o[i++]);
|
||||
userDto.setCreateTimestamp(((Timestamp) o[i++]).getTime());
|
||||
userDto.setLocaleId((String) o[i++]);
|
||||
userDtoList.add(userDto);
|
||||
}
|
||||
paginatedList.setResultList(userDtoList);
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.sismics.docs.core.dao.jpa.criteria;
|
||||
|
||||
|
||||
/**
|
||||
* Document criteria.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class DocumentCriteria {
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Getter of userId.
|
||||
*
|
||||
* @return userId
|
||||
*/
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of userId.
|
||||
*
|
||||
* @param userId userId
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.sismics.docs.core.dao.jpa.dto;
|
||||
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* Document DTO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class DocumentDto {
|
||||
/**
|
||||
* Document ID.
|
||||
*/
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Title.
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
private Long createTimestamp;
|
||||
|
||||
/**
|
||||
* Getter de id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter de id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter de title.
|
||||
*
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter de title.
|
||||
*
|
||||
* @param title title
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter de description.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter de description.
|
||||
*
|
||||
* @param description description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter de createTimestamp.
|
||||
*
|
||||
* @return the createTimestamp
|
||||
*/
|
||||
public Long getCreateTimestamp() {
|
||||
return createTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createTimestamp.
|
||||
*
|
||||
* @param createTimestamp createTimestamp
|
||||
*/
|
||||
public void setCreateTimestamp(Long createTimestamp) {
|
||||
this.createTimestamp = createTimestamp;
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
package com.sismics.docs.core.dao.jpa.dto;
|
||||
|
||||
/**
|
||||
* User DTO.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class UserDto {
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Locale ID.
|
||||
*/
|
||||
private String localeId;
|
||||
|
||||
/**
|
||||
* Username.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Email address.
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* Creation date of this user.
|
||||
*/
|
||||
private Long createTimestamp;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of localeId.
|
||||
*
|
||||
* @return localeId
|
||||
*/
|
||||
public String getLocaleId() {
|
||||
return localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of localeId.
|
||||
*
|
||||
* @param localeId localeId
|
||||
*/
|
||||
public void setLocaleId(String localeId) {
|
||||
this.localeId = localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of username.
|
||||
*
|
||||
* @return username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of username.
|
||||
*
|
||||
* @param username username
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of email.
|
||||
*
|
||||
* @return email
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of email.
|
||||
*
|
||||
* @param email email
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createTimestamp.
|
||||
*
|
||||
* @return createTimestamp
|
||||
*/
|
||||
public Long getCreateTimestamp() {
|
||||
return createTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createTimestamp.
|
||||
*
|
||||
* @param createTimestamp createTimestamp
|
||||
*/
|
||||
public void setCreateTimestamp(Long createTimestamp) {
|
||||
this.createTimestamp = createTimestamp;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.sismics.docs.core.dao.lucene;
|
||||
|
||||
|
||||
/**
|
||||
* Lucene Article DAO.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class ArticleDao {
|
||||
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package com.sismics.docs.core.dao.lucene;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache 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.apache.org/licenses/LICENSE-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.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
import org.apache.lucene.analysis.TokenStream;
|
||||
import org.apache.lucene.analysis.charfilter.HTMLStripCharFilter;
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilter;
|
||||
import org.apache.lucene.analysis.core.StopAnalyzer;
|
||||
import org.apache.lucene.analysis.core.StopFilter;
|
||||
import org.apache.lucene.analysis.standard.ClassicAnalyzer;
|
||||
import org.apache.lucene.analysis.standard.ClassicTokenizer;
|
||||
import org.apache.lucene.analysis.standard.StandardFilter;
|
||||
import org.apache.lucene.analysis.standard.StandardTokenizer;
|
||||
import org.apache.lucene.analysis.util.CharArraySet;
|
||||
import org.apache.lucene.analysis.util.StopwordAnalyzerBase;
|
||||
import org.apache.lucene.util.Version;
|
||||
|
||||
/**
|
||||
* Filters {@link StandardTokenizer} with {@link StandardFilter}, {@link
|
||||
* LowerCaseFilter} and {@link StopFilter}, using a list of
|
||||
* English stop words.
|
||||
*
|
||||
* <a name="version"/>
|
||||
* <p>You must specify the required {@link Version}
|
||||
* compatibility when creating StandardAnalyzer:
|
||||
* <ul>
|
||||
* <li> As of 3.4, Hiragana and Han characters are no longer wrongly split
|
||||
* from their combining characters. If you use a previous version number,
|
||||
* you get the exact broken behavior for backwards compatibility.
|
||||
* <li> As of 3.1, StandardTokenizer implements Unicode text segmentation,
|
||||
* and StopFilter correctly handles Unicode 4.0 supplementary characters
|
||||
* in stopwords. {@link ClassicTokenizer} and {@link ClassicAnalyzer}
|
||||
* are the pre-3.1 implementations of StandardTokenizer and
|
||||
* StandardAnalyzer.
|
||||
* <li> As of 2.9, StopFilter preserves position increments
|
||||
* <li> As of 2.4, Tokens incorrectly identified as acronyms
|
||||
* are corrected (see <a href="https://issues.apache.org/jira/browse/LUCENE-1068">LUCENE-1068</a>)
|
||||
* </ul>
|
||||
*/
|
||||
public final class DocsStandardAnalyzer extends StopwordAnalyzerBase {
|
||||
|
||||
/** Default maximum allowed token length */
|
||||
public static final int DEFAULT_MAX_TOKEN_LENGTH = 255;
|
||||
|
||||
private int maxTokenLength = DEFAULT_MAX_TOKEN_LENGTH;
|
||||
|
||||
/** An unmodifiable set containing some common English words that are usually not
|
||||
useful for searching. */
|
||||
public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
|
||||
|
||||
/** Builds an analyzer with the given stop words.
|
||||
* @param matchVersion Lucene version to match See {@link
|
||||
* <a href="#version">above</a>}
|
||||
* @param stopWords stop words */
|
||||
public DocsStandardAnalyzer(Version matchVersion, CharArraySet stopWords) {
|
||||
super(matchVersion, stopWords);
|
||||
}
|
||||
|
||||
/** Builds an analyzer with the default stop words ({@link
|
||||
* #STOP_WORDS_SET}).
|
||||
* @param matchVersion Lucene version to match See {@link
|
||||
* <a href="#version">above</a>}
|
||||
*/
|
||||
public DocsStandardAnalyzer(Version matchVersion) {
|
||||
this(matchVersion, STOP_WORDS_SET);
|
||||
}
|
||||
|
||||
/** Builds an analyzer with the stop words from the given reader.
|
||||
* @see WordlistLoader#getWordSet(Reader, Version)
|
||||
* @param matchVersion Lucene version to match See {@link
|
||||
* <a href="#version">above</a>}
|
||||
* @param stopwords Reader to read stop words from */
|
||||
public DocsStandardAnalyzer(Version matchVersion, Reader stopwords) throws IOException {
|
||||
this(matchVersion, loadStopwordSet(stopwords, matchVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set maximum allowed token length. If a token is seen
|
||||
* that exceeds this length then it is discarded. This
|
||||
* setting only takes effect the next time tokenStream or
|
||||
* tokenStream is called.
|
||||
*/
|
||||
public void setMaxTokenLength(int length) {
|
||||
maxTokenLength = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #setMaxTokenLength
|
||||
*/
|
||||
public int getMaxTokenLength() {
|
||||
return maxTokenLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenStreamComponents createComponents(final String fieldName, final Reader reader) {
|
||||
final StandardTokenizer src = new StandardTokenizer(matchVersion, reader);
|
||||
src.setMaxTokenLength(maxTokenLength);
|
||||
TokenStream tok = new StandardFilter(matchVersion, src);
|
||||
tok = new LowerCaseFilter(matchVersion, tok);
|
||||
tok = new StopFilter(matchVersion, tok, stopwords);
|
||||
return new TokenStreamComponents(src, tok) {
|
||||
@Override
|
||||
protected void setReader(final Reader reader) throws IOException {
|
||||
src.setMaxTokenLength(DocsStandardAnalyzer.this.maxTokenLength);
|
||||
super.setReader(reader);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reader initReader(String fieldName, Reader reader) {
|
||||
if (fieldName.equals("title") || fieldName.equals("description")) {
|
||||
return new HTMLStripCharFilter(super.initReader(fieldName, reader));
|
||||
}
|
||||
return super.initReader(fieldName, reader);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.sismics.docs.core.listener.sync;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.eventbus.DeadEvent;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
/**
|
||||
* Listener for all unprocessed events.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class DeadEventListener {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(DeadEventListener.class);
|
||||
|
||||
/**
|
||||
* Process every dead event.
|
||||
*
|
||||
* @param deadEvent Catchall event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onDeadEvent(DeadEvent deadEvent) {
|
||||
log.error("Dead event catched: " + deadEvent.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
package com.sismics.docs.core.model.context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.lucene.store.Directory;
|
||||
|
||||
import com.google.common.eventbus.AsyncEventBus;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.sismics.docs.core.constant.ConfigType;
|
||||
import com.sismics.docs.core.dao.jpa.ConfigDao;
|
||||
import com.sismics.docs.core.listener.sync.DeadEventListener;
|
||||
import com.sismics.docs.core.model.jpa.Config;
|
||||
import com.sismics.docs.core.service.IndexingService;
|
||||
import com.sismics.util.EnvironmentUtil;
|
||||
|
||||
/**
|
||||
* Global application context.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class AppContext {
|
||||
/**
|
||||
* Singleton instance.
|
||||
*/
|
||||
private static AppContext instance;
|
||||
|
||||
/**
|
||||
* Event bus.
|
||||
*/
|
||||
private EventBus eventBus;
|
||||
|
||||
/**
|
||||
* Generic asynchronous event bus.
|
||||
*/
|
||||
private EventBus asyncEventBus;
|
||||
|
||||
/**
|
||||
* Indexing service.
|
||||
*/
|
||||
private IndexingService indexingService;
|
||||
|
||||
/**
|
||||
* Lucene directory.
|
||||
*/
|
||||
private Directory luceneDirectory;
|
||||
|
||||
/**
|
||||
* Asynchronous executors.
|
||||
*/
|
||||
private List<ExecutorService> asyncExecutorList;
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private AppContext() {
|
||||
resetEventBus();
|
||||
|
||||
ConfigDao configDao = new ConfigDao();
|
||||
Config luceneStorageConfig = configDao.getById(ConfigType.LUCENE_DIRECTORY_STORAGE);
|
||||
indexingService = new IndexingService(luceneStorageConfig != null ? luceneStorageConfig.getValue() : null);
|
||||
indexingService.startAndWait();
|
||||
|
||||
luceneDirectory = indexingService.getDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)-initializes the event buses.
|
||||
*/
|
||||
private void resetEventBus() {
|
||||
eventBus = new EventBus();
|
||||
eventBus.register(new DeadEventListener());
|
||||
|
||||
asyncExecutorList = new ArrayList<ExecutorService>();
|
||||
|
||||
asyncEventBus = newAsyncEventBus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single instance of the application context.
|
||||
*
|
||||
* @return Application context
|
||||
*/
|
||||
public static AppContext getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AppContext();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for termination of all asynchronous events.
|
||||
* /!\ Must be used only in unit tests and never a multi-user environment.
|
||||
*/
|
||||
public void waitForAsync() {
|
||||
if (EnvironmentUtil.isUnitTest()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (ExecutorService executor : asyncExecutorList) {
|
||||
// Shutdown executor, don't accept any more tasks (can cause error with nested events)
|
||||
try {
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(60, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
resetEventBus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new asynchronous event bus.
|
||||
*
|
||||
* @return Async event bus
|
||||
*/
|
||||
private EventBus newAsyncEventBus() {
|
||||
if (EnvironmentUtil.isUnitTest()) {
|
||||
return new EventBus();
|
||||
} else {
|
||||
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<Runnable>());
|
||||
asyncExecutorList.add(executor);
|
||||
return new AsyncEventBus(executor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of eventBus.
|
||||
*
|
||||
* @return eventBus
|
||||
*/
|
||||
public EventBus getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of asyncEventBus.
|
||||
*
|
||||
* @return asyncEventBus
|
||||
*/
|
||||
public EventBus getAsyncEventBus() {
|
||||
return asyncEventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of feedService.
|
||||
*
|
||||
* @return feedService
|
||||
*/
|
||||
public IndexingService getIndexingService() {
|
||||
return indexingService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of- luceneDirectory.
|
||||
*
|
||||
* @return the luceneDirectory
|
||||
*/
|
||||
public Directory getLuceneDirectory() {
|
||||
return luceneDirectory;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Authentication token entity.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_AUTHENTICATION_TOKEN")
|
||||
public class AuthenticationToken {
|
||||
/**
|
||||
* Token.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "AUT_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
@Column(name = "AUT_IDUSER_C", nullable = false, length = 36)
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Remember the user next time (long lasted session).
|
||||
*/
|
||||
@Column(name = "AUT_LONGLASTED_B", nullable = false)
|
||||
private boolean longLasted;
|
||||
|
||||
/**
|
||||
* Token creation date.
|
||||
*/
|
||||
@Column(name = "AUT_CREATIONDATE_D", nullable = false)
|
||||
private Date creationDate;
|
||||
|
||||
/**
|
||||
* Last connection date using this token.
|
||||
*/
|
||||
@Column(name = "AUT_LASTCONNECTIONDATE_D")
|
||||
private Date lastConnectionDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of userId.
|
||||
*
|
||||
* @return userId
|
||||
*/
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of userId.
|
||||
*
|
||||
* @param userId userId
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of longLasted.
|
||||
*
|
||||
* @return longLasted
|
||||
*/
|
||||
public boolean isLongLasted() {
|
||||
return longLasted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of longLasted.
|
||||
*
|
||||
* @param longLasted longLasted
|
||||
*/
|
||||
public void setLongLasted(boolean longLasted) {
|
||||
this.longLasted = longLasted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of creationDate.
|
||||
*
|
||||
* @return creationDate
|
||||
*/
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of creationDate.
|
||||
*
|
||||
* @param creationDate creationDate
|
||||
*/
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of lastConnectionDate.
|
||||
*
|
||||
* @return lastConnectionDate
|
||||
*/
|
||||
public Date getLastConnectionDate() {
|
||||
return lastConnectionDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of lastConnectionDate.
|
||||
*
|
||||
* @param lastConnectionDate lastConnectionDate
|
||||
*/
|
||||
public void setLastConnectionDate(Date lastConnectionDate) {
|
||||
this.lastConnectionDate = lastConnectionDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", "**hidden**")
|
||||
.add("userId", userId)
|
||||
.add("longLasted", longLasted)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Base function entity.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_BASE_FUNCTION")
|
||||
public class BaseFunction {
|
||||
/**
|
||||
* Base function ID (ex: "ADMIN").
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "BAF_ID_C", length = 10)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.sismics.docs.core.constant.ConfigType;
|
||||
|
||||
/**
|
||||
* Configuration parameter entity.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_CONFIG")
|
||||
public class Config {
|
||||
/**
|
||||
* Configuration parameter ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "CFG_ID_C", length = 50)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ConfigType id;
|
||||
|
||||
/**
|
||||
* Configuration parameter value.
|
||||
*/
|
||||
@Column(name = "CFG_VALUE_C", length = 250)
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public ConfigType getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(ConfigType id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of value.
|
||||
*
|
||||
* @return value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of value.
|
||||
*
|
||||
* @param value value
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Document entity.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_DOCUMENT")
|
||||
public class Document {
|
||||
/**
|
||||
* Document ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "DOC_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
@Column(name = "DOC_IDUSER_C", nullable = false, length = 36)
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* Title.
|
||||
*/
|
||||
@Column(name = "DOC_TITLE_C", length = 100)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* Description.
|
||||
*/
|
||||
@Column(name = "DOC_DESCRIPTION_C", length = 4000)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
@Column(name = "DOC_CREATEDATE_D", nullable = false)
|
||||
private Date createDate;
|
||||
|
||||
/**
|
||||
* Deletion date.
|
||||
*/
|
||||
@Column(name = "DOC_DELETEDATE_D")
|
||||
private Date deleteDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of userId.
|
||||
*
|
||||
* @return the userId
|
||||
*/
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of userId.
|
||||
*
|
||||
* @param userId userId
|
||||
*/
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of title.
|
||||
*
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of title.
|
||||
*
|
||||
* @param title title
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of description.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of description.
|
||||
*
|
||||
* @param description description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createDate.
|
||||
*
|
||||
* @return the createDate
|
||||
*/
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createDate.
|
||||
*
|
||||
* @param createDate createDate
|
||||
*/
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of deleteDate.
|
||||
*
|
||||
* @return the deleteDate
|
||||
*/
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of deleteDate.
|
||||
*
|
||||
* @param deleteDate deleteDate
|
||||
*/
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* File entity.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_FILE")
|
||||
public class File {
|
||||
/**
|
||||
* File ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "FIL_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Document ID.
|
||||
*/
|
||||
@Column(name = "FIL_IDDOC_C", nullable = false, length = 36)
|
||||
private String documentId;
|
||||
|
||||
/**
|
||||
* Document ID.
|
||||
*/
|
||||
@Column(name = "FIL_MIMETYPE_C", length = 100)
|
||||
private String mimeType;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
@Column(name = "FIL_CREATEDATE_D", nullable = false)
|
||||
private Date createDate;
|
||||
|
||||
/**
|
||||
* Deletion date.
|
||||
*/
|
||||
@Column(name = "FIL_DELETEDATE_D")
|
||||
private Date deleteDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of documentId.
|
||||
*
|
||||
* @return the documentId
|
||||
*/
|
||||
public String getDocumentId() {
|
||||
return documentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of documentId.
|
||||
*
|
||||
* @param documentId documentId
|
||||
*/
|
||||
public void setDocumentId(String documentId) {
|
||||
this.documentId = documentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of mimeType.
|
||||
*
|
||||
* @return the mimeType
|
||||
*/
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of mimeType.
|
||||
*
|
||||
* @param mimeType mimeType
|
||||
*/
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createDate.
|
||||
*
|
||||
* @return the createDate
|
||||
*/
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createDate.
|
||||
*
|
||||
* @param createDate createDate
|
||||
*/
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of deleteDate.
|
||||
*
|
||||
* @return the deleteDate
|
||||
*/
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of deleteDate.
|
||||
*
|
||||
* @param deleteDate deleteDate
|
||||
*/
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Locale entity.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_LOCALE")
|
||||
public class Locale {
|
||||
/**
|
||||
* Locale ID (ex: fr_FR).
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "LOC_ID_C", length = 10)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Role (set of base functions).
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_ROLE")
|
||||
public class Role {
|
||||
/**
|
||||
* Role ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "ROL_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Role name.
|
||||
*/
|
||||
@Column(name = "ROL_NAME_C", nullable = false, length = 50)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
@Column(name = "ROL_CREATEDATE_D", nullable = false)
|
||||
private Date createDate;
|
||||
|
||||
/**
|
||||
* Deletion date.
|
||||
*/
|
||||
@Column(name = "ROL_DELETEDATE_D")
|
||||
private Date deleteDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of name.
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of name.
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createDate.
|
||||
*
|
||||
* @return createDate
|
||||
*/
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createDate.
|
||||
*
|
||||
* @param createDate createDate
|
||||
*/
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of deleteDate.
|
||||
*
|
||||
* @return deleteDate
|
||||
*/
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of deleteDate.
|
||||
*
|
||||
* @param deleteDate deleteDate
|
||||
*/
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("name", name)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Role base function.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_ROLE_BASE_FUNCTION")
|
||||
public class RoleBaseFunction {
|
||||
/**
|
||||
* Role base function ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "RBF_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Role ID.
|
||||
*/
|
||||
@Column(name = "RBF_IDROLE_C", nullable = false, length = 36)
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* Base function ID.
|
||||
*/
|
||||
@Column(name = "RBF_IDBASEFUNCTION_C", nullable = false, length = 36)
|
||||
private String baseFunctionId;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
@Column(name = "RBF_CREATEDATE_D", nullable = false)
|
||||
private Date createDate;
|
||||
|
||||
/**
|
||||
* Deletion date.
|
||||
*/
|
||||
@Column(name = "RBF_DELETEDATE_D")
|
||||
private Date deleteDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of roleId.
|
||||
*
|
||||
* @return roleId
|
||||
*/
|
||||
public String getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of roleId.
|
||||
*
|
||||
* @param roleId roleId
|
||||
*/
|
||||
public void setRoleId(String roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of baseFunctionId.
|
||||
*
|
||||
* @return baseFunctionId
|
||||
*/
|
||||
public String getBaseFunctionId() {
|
||||
return baseFunctionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of baseFunctionId.
|
||||
*
|
||||
* @param baseFunctionId baseFunctionId
|
||||
*/
|
||||
public void setBaseFunctionId(String baseFunctionId) {
|
||||
this.baseFunctionId = baseFunctionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createDate.
|
||||
*
|
||||
* @return createDate
|
||||
*/
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createDate.
|
||||
*
|
||||
* @param createDate createDate
|
||||
*/
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of deleteDate.
|
||||
*
|
||||
* @return deleteDate
|
||||
*/
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of deleteDate.
|
||||
*
|
||||
* @param deleteDate deleteDate
|
||||
*/
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("userId", roleId)
|
||||
.add("baseFunctionId", baseFunctionId)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
package com.sismics.docs.core.model.jpa;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* User entity.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "T_USER")
|
||||
public class User {
|
||||
/**
|
||||
* User ID.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "USE_ID_C", length = 36)
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Locale ID.
|
||||
*/
|
||||
@Column(name = "USE_IDLOCALE_C", nullable = false, length = 10)
|
||||
private String localeId;
|
||||
|
||||
/**
|
||||
* Role ID.
|
||||
*/
|
||||
@Column(name = "USE_IDROLE_C", nullable = false, length = 36)
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* User's username.
|
||||
*/
|
||||
@Column(name = "USE_USERNAME_C", nullable = false, length = 50)
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* User's password.
|
||||
*/
|
||||
@Column(name = "USE_PASSWORD_C", nullable = false, length = 100)
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* Email address.
|
||||
*/
|
||||
@Column(name = "USE_EMAIL_C", nullable = false, length = 100)
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* Theme.
|
||||
*/
|
||||
@Column(name = "USE_THEME_C", nullable = false, length = 100)
|
||||
private String theme;
|
||||
|
||||
/**
|
||||
* True if the user hasn't dismissed the first connection screen.
|
||||
*/
|
||||
@Column(name = "USE_FIRSTCONNECTION_B", nullable = false)
|
||||
private boolean firstConnection;
|
||||
|
||||
/**
|
||||
* Creation date.
|
||||
*/
|
||||
@Column(name = "USE_CREATEDATE_D", nullable = false)
|
||||
private Date createDate;
|
||||
|
||||
/**
|
||||
* Deletion date.
|
||||
*/
|
||||
@Column(name = "USE_DELETEDATE_D")
|
||||
private Date deleteDate;
|
||||
|
||||
/**
|
||||
* Getter of id.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of localeId.
|
||||
*
|
||||
* @return localeId
|
||||
*/
|
||||
public String getLocaleId() {
|
||||
return localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of localeId.
|
||||
*
|
||||
* @param localeId localeId
|
||||
*/
|
||||
public void setLocaleId(String localeId) {
|
||||
this.localeId = localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of roleId.
|
||||
*
|
||||
* @return roleId
|
||||
*/
|
||||
public String getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of roleId.
|
||||
*
|
||||
* @param roleId roleId
|
||||
*/
|
||||
public void setRoleId(String roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of username.
|
||||
*
|
||||
* @return username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of username.
|
||||
*
|
||||
* @param username username
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of password.
|
||||
*
|
||||
* @return password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of password.
|
||||
*
|
||||
* @param password password
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of email.
|
||||
*
|
||||
* @return email
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of email.
|
||||
*
|
||||
* @param email email
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of theme.
|
||||
*
|
||||
* @return theme
|
||||
*/
|
||||
public String getTheme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of theme.
|
||||
*
|
||||
* @param theme theme
|
||||
*/
|
||||
public void setTheme(String theme) {
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of firstConnection.
|
||||
*
|
||||
* @return firstConnection
|
||||
*/
|
||||
public boolean isFirstConnection() {
|
||||
return firstConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of firstConnection.
|
||||
*
|
||||
* @param firstConnection firstConnection
|
||||
*/
|
||||
public void setFirstConnection(boolean firstConnection) {
|
||||
this.firstConnection = firstConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of createDate.
|
||||
*
|
||||
* @return createDate
|
||||
*/
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of createDate.
|
||||
*
|
||||
* @param createDate createDate
|
||||
*/
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of deleteDate.
|
||||
*
|
||||
* @return deleteDate
|
||||
*/
|
||||
public Date getDeleteDate() {
|
||||
return deleteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of deleteDate.
|
||||
*
|
||||
* @param deleteDate deleteDate
|
||||
*/
|
||||
public void setDeleteDate(Date deleteDate) {
|
||||
this.deleteDate = deleteDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("id", id)
|
||||
.add("username", username)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package com.sismics.docs.core.service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.store.RAMDirectory;
|
||||
import org.apache.lucene.store.SimpleFSDirectory;
|
||||
import org.apache.lucene.store.SimpleFSLockFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.util.concurrent.AbstractScheduledService;
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.model.context.AppContext;
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
|
||||
/**
|
||||
* Indexing service.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class IndexingService extends AbstractScheduledService {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(IndexingService.class);
|
||||
|
||||
/**
|
||||
* Lucene directory.
|
||||
*/
|
||||
private Directory directory;
|
||||
|
||||
/**
|
||||
* Lucene storage config.
|
||||
*/
|
||||
private String luceneStorageConfig;
|
||||
|
||||
public IndexingService(String luceneStorageConfig) {
|
||||
this.luceneStorageConfig = luceneStorageConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp() {
|
||||
// RAM directory storage by default
|
||||
if (luceneStorageConfig == null || luceneStorageConfig.equals(Constants.LUCENE_DIRECTORY_STORAGE_RAM)) {
|
||||
directory = new RAMDirectory();
|
||||
log.info("Using RAM Lucene storage");
|
||||
} else if (luceneStorageConfig.equals(Constants.LUCENE_DIRECTORY_STORAGE_FILE)) {
|
||||
File luceneDirectory = DirectoryUtil.getLuceneDirectory();
|
||||
log.info("Using file Lucene storage: {}", luceneDirectory);
|
||||
try {
|
||||
directory = new SimpleFSDirectory(luceneDirectory, new SimpleFSLockFactory());
|
||||
} catch (IOException e) {
|
||||
log.error("Error initializing Lucene index", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() {
|
||||
Directory luceneIndex = AppContext.getInstance().getLuceneDirectory();
|
||||
if (luceneIndex != null) {
|
||||
try {
|
||||
luceneIndex.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Error closing Lucene index", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runOneIteration() throws Exception {
|
||||
TransactionUtil.handle(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// NOP
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Scheduler scheduler() {
|
||||
return Scheduler.newFixedDelaySchedule(0, 1, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of directory.
|
||||
*
|
||||
* @return the directory
|
||||
*/
|
||||
public Directory getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import com.sismics.docs.core.constant.ConfigType;
|
||||
import com.sismics.docs.core.dao.jpa.ConfigDao;
|
||||
import com.sismics.docs.core.model.jpa.Config;
|
||||
|
||||
/**
|
||||
* Configuration parameter utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ConfigUtil {
|
||||
/**
|
||||
* Returns the textual value of a configuration parameter.
|
||||
*
|
||||
* @param configType Type of the configuration parameter
|
||||
* @return Textual value of the configuration parameter
|
||||
* @throws IllegalStateException Configuration parameter undefined
|
||||
*/
|
||||
public static String getConfigStringValue(ConfigType configType) {
|
||||
ConfigDao configDao = new ConfigDao();
|
||||
Config config = configDao.getById(configType);
|
||||
if (config == null) {
|
||||
throw new IllegalStateException("Config parameter not found: " + configType);
|
||||
}
|
||||
return config.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configuration resource bundle.
|
||||
*
|
||||
* @return Resource bundle
|
||||
*/
|
||||
public static ResourceBundle getConfigBundle() {
|
||||
return ResourceBundle.getBundle("config");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer value of a configuration parameter.
|
||||
*
|
||||
* @param configType Type of the configuration parameter
|
||||
* @return Integer value of the configuration parameter
|
||||
* @throws IllegalStateException Configuration parameter undefined
|
||||
*/
|
||||
public static int getConfigIntegerValue(ConfigType configType) {
|
||||
String value = getConfigStringValue(configType);
|
||||
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boolean value of a configuration parameter.
|
||||
*
|
||||
* @param configType Type of the configuration parameter
|
||||
* @return Boolean value of the configuration parameter
|
||||
* @throws IllegalStateException Configuration parameter undefined
|
||||
*/
|
||||
public static boolean getConfigBooleanValue(ConfigType configType) {
|
||||
String value = getConfigStringValue(configType);
|
||||
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.sismics.util.EnvironmentUtil;
|
||||
|
||||
/**
|
||||
* Utilities to gain access to the storage directories used by the application.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class DirectoryUtil {
|
||||
/**
|
||||
* Returns the base data directory.
|
||||
*
|
||||
* @return Base data directory
|
||||
*/
|
||||
public static File getBaseDataDirectory() {
|
||||
File baseDataDir = null;
|
||||
if (EnvironmentUtil.getWebappRoot() != null) {
|
||||
// We are in a webapp environment
|
||||
if (StringUtils.isNotBlank(EnvironmentUtil.getDocsHome())) {
|
||||
// If the docs.home property is set then use it
|
||||
baseDataDir = new File(EnvironmentUtil.getDocsHome());
|
||||
if (!baseDataDir.isDirectory()) {
|
||||
baseDataDir.mkdirs();
|
||||
}
|
||||
} else {
|
||||
// Use the base of the Webapp directory
|
||||
baseDataDir = new File(EnvironmentUtil.getWebappRoot() + File.separator + "sismicsdocs");
|
||||
if (!baseDataDir.isDirectory()) {
|
||||
baseDataDir.mkdirs();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (baseDataDir == null) {
|
||||
// Or else (for unit testing), use a temporary directory
|
||||
baseDataDir = new File(System.getProperty("java.io.tmpdir"));
|
||||
}
|
||||
|
||||
return baseDataDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database directory.
|
||||
*
|
||||
* @return Database directory.
|
||||
*/
|
||||
public static File getDbDirectory() {
|
||||
return getDataSubDirectory("db");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lucene indexes directory.
|
||||
*
|
||||
* @return Lucene indexes directory.
|
||||
*/
|
||||
public static File getLuceneDirectory() {
|
||||
return getDataSubDirectory("lucene");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the storage directory.
|
||||
*
|
||||
* @return Storage directory.
|
||||
*/
|
||||
public static File getStorageDirectory() {
|
||||
return getDataSubDirectory("storage");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the log directory.
|
||||
*
|
||||
* @return Log directory.
|
||||
*/
|
||||
public static File getLogDirectory() {
|
||||
return getDataSubDirectory("log");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the themes directory.
|
||||
*
|
||||
* @return Theme directory.
|
||||
*/
|
||||
public static File getThemeDirectory() {
|
||||
String webappRoot = EnvironmentUtil.getWebappRoot();
|
||||
File themeDir = null;
|
||||
if (webappRoot != null) {
|
||||
themeDir = new File(webappRoot + File.separator + "style" + File.separator + "theme");
|
||||
} else {
|
||||
themeDir = new File(DirectoryUtil.class.getResource("/style/theme").getFile());
|
||||
}
|
||||
if (themeDir != null && themeDir.isDirectory()) {
|
||||
return themeDir;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a subdirectory of the base data directory
|
||||
*
|
||||
* @return Subdirectory
|
||||
*/
|
||||
private static File getDataSubDirectory(String subdirectory) {
|
||||
File baseDataDir = getBaseDataDirectory();
|
||||
File faviconDirectory = new File(baseDataDir.getPath() + File.separator + subdirectory);
|
||||
if (!faviconDirectory.isDirectory()) {
|
||||
faviconDirectory.mkdirs();
|
||||
}
|
||||
return faviconDirectory;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Entity manager utils.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class EntityManagerUtil {
|
||||
/**
|
||||
* Flush the entity manager session.
|
||||
*/
|
||||
public static void flush() {
|
||||
ThreadLocalContext.get().getEntityManager().flush();
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.IndexWriterConfig;
|
||||
import org.apache.lucene.index.SerialMergeScheduler;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.Version;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.dao.lucene.DocsStandardAnalyzer;
|
||||
import com.sismics.docs.core.model.context.AppContext;
|
||||
|
||||
/**
|
||||
* Lucene utils.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class LuceneUtil {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(LuceneUtil.class);
|
||||
|
||||
/**
|
||||
* Encapsulate a process into a Lucene context.
|
||||
*
|
||||
* @param runnable
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void handle(LuceneRunnable runnable) {
|
||||
// Standard analyzer
|
||||
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_42, new DocsStandardAnalyzer(Version.LUCENE_42));
|
||||
|
||||
// Merge sequentially, because Lucene writing is already done asynchronously
|
||||
config.setMergeScheduler(new SerialMergeScheduler());
|
||||
|
||||
// Creating index writer
|
||||
Directory directory = AppContext.getInstance().getLuceneDirectory();
|
||||
IndexWriter indexWriter = null;
|
||||
try {
|
||||
indexWriter = new IndexWriter(directory, config);
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot create IndexWriter", e);
|
||||
}
|
||||
|
||||
// Unlock index if needed
|
||||
try {
|
||||
if (IndexWriter.isLocked(directory)) {
|
||||
IndexWriter.unlock(directory);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot unlock Lucene directory", e);
|
||||
}
|
||||
|
||||
try {
|
||||
runnable.run(indexWriter);
|
||||
} catch (Exception e) {
|
||||
log.error("Error in running index writing transaction", e);
|
||||
try {
|
||||
indexWriter.rollback();
|
||||
} catch (IOException e1) {
|
||||
log.error("Cannot rollback index writing transaction", e1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
indexWriter.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Cannot close IndexWriter", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lucene runnable.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public interface LuceneRunnable {
|
||||
/**
|
||||
* Code to run in a Lucene context.
|
||||
*
|
||||
* @param indexWriter
|
||||
* @throws Exception
|
||||
*/
|
||||
public abstract void run(IndexWriter indexWriter) throws Exception;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* Stream utilities.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
public class StreamUtil {
|
||||
|
||||
/**
|
||||
* Detects if the stream is gzipped, and returns a uncompressed stream according to this.
|
||||
*
|
||||
* @param is InputStream
|
||||
* @return InputStream
|
||||
* @throws IOException
|
||||
*/
|
||||
public static InputStream detectGzip(InputStream is) throws IOException {
|
||||
PushbackInputStream pb = new PushbackInputStream(is, 2);
|
||||
byte [] signature = new byte[2];
|
||||
pb.read(signature);
|
||||
pb.unread(signature);
|
||||
if(signature[0] == (byte) GZIPInputStream.GZIP_MAGIC && signature[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8)) {
|
||||
return new GZIPInputStream(pb);
|
||||
} else {
|
||||
return pb;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
import com.sismics.util.jpa.EMF;
|
||||
|
||||
/**
|
||||
* Database transaction utils.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TransactionUtil {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(TransactionUtil.class);
|
||||
|
||||
/**
|
||||
* Encapsulate a process into a transactionnal context.
|
||||
*
|
||||
* @param runnable
|
||||
*/
|
||||
public static void handle(Runnable runnable) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
|
||||
if (em != null) {
|
||||
// We are already in a transactional context, nothing to do
|
||||
runnable.run();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
em = EMF.get().createEntityManager();
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot create entity manager", e);
|
||||
}
|
||||
ThreadLocalContext context = ThreadLocalContext.get();
|
||||
context.setEntityManager(em);
|
||||
EntityTransaction tx = em.getTransaction();
|
||||
tx.begin();
|
||||
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (Exception e) {
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
log.error("An exception occured, rolling back current transaction", e);
|
||||
|
||||
// If an unprocessed error comes up, rollback the transaction
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception ce) {
|
||||
log.error("Error closing entity manager", ce);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
// No error in the current request : commit the transaction
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
em.getTransaction().commit();
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Error closing entity manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the current transaction, and flushes the changes to the database.
|
||||
*/
|
||||
public static void commit() {
|
||||
EntityTransaction tx = ThreadLocalContext.get().getEntityManager().getTransaction();
|
||||
tx.commit();
|
||||
tx.begin();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.sismics.docs.core.util;
|
||||
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
|
||||
/**
|
||||
* Utilitaires sur les utilisateurs.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class UserUtil {
|
||||
/**
|
||||
* Retourne the user's username.
|
||||
*
|
||||
* @param user User
|
||||
* @return User name
|
||||
*/
|
||||
public static String getUserName(User user) {
|
||||
return user.getUsername();
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package com.sismics.docs.core.util.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Paginated list.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class PaginatedList<T> {
|
||||
/**
|
||||
* Size of a page.
|
||||
*/
|
||||
private int limit;
|
||||
|
||||
/**
|
||||
* Offset of the page (in number of records).
|
||||
*/
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* Total number of records.
|
||||
*/
|
||||
private int resultCount;
|
||||
|
||||
/**
|
||||
* List of records of the current page.
|
||||
*/
|
||||
private List<T> resultList;
|
||||
|
||||
/**
|
||||
* Constructor of PaginatedList.
|
||||
*
|
||||
* @param pageSize Page size
|
||||
* @param offset Offset
|
||||
*/
|
||||
public PaginatedList(int pageSize, int offset) {
|
||||
this.limit = pageSize;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of resultCount.
|
||||
*
|
||||
* @return resultCount
|
||||
*/
|
||||
public int getResultCount() {
|
||||
return resultCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of resultCount.
|
||||
*
|
||||
* @param resultCount resultCount
|
||||
*/
|
||||
public void setResultCount(int resultCount) {
|
||||
this.resultCount = resultCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of resultList.
|
||||
*
|
||||
* @return resultList
|
||||
*/
|
||||
public List<T> getResultList() {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of resultList.
|
||||
*
|
||||
* @param resultList resultList
|
||||
*/
|
||||
public void setResultList(List<T> resultList) {
|
||||
this.resultList = resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of limit.
|
||||
*
|
||||
* @return limit
|
||||
*/
|
||||
public int getLimit() {
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of offset.
|
||||
*
|
||||
* @return offset
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package com.sismics.docs.core.util.jpa;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Query;
|
||||
|
||||
/**
|
||||
* Utilities for paginated lists.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class PaginatedLists {
|
||||
/**
|
||||
* Default size of a page.
|
||||
*/
|
||||
private static final int DEFAULT_PAGE_SIZE = 10;
|
||||
|
||||
/**
|
||||
* Maximum size of a page.
|
||||
*/
|
||||
private static final int MAX_PAGE_SIZE = 100;
|
||||
|
||||
/**
|
||||
* Constructs a paginated list.
|
||||
*
|
||||
* @param pageSize Size of the page
|
||||
* @param offset Offset of the page
|
||||
* @return Paginated list
|
||||
*/
|
||||
public static <E> PaginatedList<E> create(Integer pageSize, Integer offset) {
|
||||
if (pageSize == null) {
|
||||
pageSize = DEFAULT_PAGE_SIZE;
|
||||
}
|
||||
if (offset == null) {
|
||||
offset = 0;
|
||||
}
|
||||
if (pageSize > MAX_PAGE_SIZE) {
|
||||
pageSize = MAX_PAGE_SIZE;
|
||||
}
|
||||
return new PaginatedList<E>(pageSize, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a paginated list with default parameters.
|
||||
*
|
||||
* @return Paginated list
|
||||
*/
|
||||
public static <E> PaginatedList<E> create() {
|
||||
return create(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a native count(*) request to count the number of results.
|
||||
*
|
||||
* @param paginatedList Paginated list object containing parameters, and into which results are added by side effects
|
||||
* @param queryParam Query parameters
|
||||
*/
|
||||
public static <E> void executeCountQuery(PaginatedList<E> paginatedList, QueryParam queryParam) {
|
||||
StringBuilder sb = new StringBuilder("select count(*) as result_count from (");
|
||||
sb.append(queryParam.getQueryString());
|
||||
sb.append(") as t1");
|
||||
|
||||
QueryParam countQueryParam = new QueryParam(sb.toString(), queryParam.getParameterMap());
|
||||
|
||||
Query q = QueryUtil.getNativeQuery(countQueryParam);
|
||||
|
||||
Number resultCount = (Number) q.getSingleResult();
|
||||
paginatedList.setResultCount(resultCount.intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query and returns the data of the currunt page.
|
||||
*
|
||||
* @param em EntityManager
|
||||
* @param paginatedList Paginated list object containing parameters, and into which results are added by side effects
|
||||
* @param queryParam Query parameters
|
||||
* @return List of results
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <E> List<Object[]> executeResultQuery(PaginatedList<E> paginatedList, QueryParam queryParam) {
|
||||
Query q = QueryUtil.getNativeQuery(queryParam);
|
||||
|
||||
q.setFirstResult(paginatedList.getOffset());
|
||||
q.setMaxResults(paginatedList.getLimit());
|
||||
return q.getResultList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a paginated request with 2 native queries (one to count the number of results, and one to return the page).
|
||||
*
|
||||
* @param paginatedList Paginated list object containing parameters, and into which results are added by side effects
|
||||
* @param queryParam Query parameters
|
||||
* @return List of results
|
||||
*/
|
||||
public static <E> List<Object[]> executePaginatedQuery(PaginatedList<E> paginatedList, QueryParam queryParam) {
|
||||
executeCountQuery(paginatedList, queryParam);
|
||||
return executeResultQuery(paginatedList, queryParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a paginated request with 2 native queries (one to count the number of results, and one to return the page).
|
||||
*
|
||||
* @param paginatedList Paginated list object containing parameters, and into which results are added by side effects
|
||||
* @param queryParam Query parameters
|
||||
* @param sortCriteria Sort criteria
|
||||
* @return List of results
|
||||
*/
|
||||
public static <E> List<Object[]> executePaginatedQuery(PaginatedList<E> paginatedList, QueryParam queryParam, SortCriteria sortCriteria) {
|
||||
StringBuilder sb = new StringBuilder(queryParam.getQueryString());
|
||||
sb.append(" order by c");
|
||||
sb.append(sortCriteria.getColumn());
|
||||
sb.append(sortCriteria.isAsc() ? " asc" : " desc");
|
||||
|
||||
QueryParam sortedQueryParam = new QueryParam(sb.toString(), queryParam.getParameterMap());
|
||||
|
||||
executeCountQuery(paginatedList, sortedQueryParam);
|
||||
return executeResultQuery(paginatedList, sortedQueryParam);
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.sismics.docs.core.util.jpa;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Query parameters.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class QueryParam {
|
||||
|
||||
/**
|
||||
* Query string.
|
||||
*/
|
||||
private String queryString;
|
||||
|
||||
/**
|
||||
* Query parameters.
|
||||
*/
|
||||
private Map<String, Object> parameterMap;
|
||||
|
||||
/**
|
||||
* Constructor of QueryParam.
|
||||
*
|
||||
* @param queryString Query string
|
||||
* @param parameterMap Query parameters
|
||||
*/
|
||||
public QueryParam(String queryString, Map<String, Object> parameterMap) {
|
||||
this.queryString = queryString;
|
||||
this.parameterMap = parameterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of queryString.
|
||||
*
|
||||
* @return queryString
|
||||
*/
|
||||
public String getQueryString() {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of parameterMap.
|
||||
*
|
||||
* @return parameterMap
|
||||
*/
|
||||
public Map<String, Object> getParameterMap() {
|
||||
return parameterMap;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.sismics.docs.core.util.jpa;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
|
||||
/**
|
||||
* Query utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class QueryUtil {
|
||||
|
||||
/**
|
||||
* Creates a native query from the query parameters.
|
||||
*
|
||||
* @param queryParam Query parameters
|
||||
* @return Native query
|
||||
*/
|
||||
public static Query getNativeQuery(QueryParam queryParam) {
|
||||
EntityManager em = ThreadLocalContext.get().getEntityManager();
|
||||
Query query = em.createNativeQuery(queryParam.getQueryString());
|
||||
for (Entry<String, Object> entry : queryParam.getParameterMap().entrySet()) {
|
||||
query.setParameter(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return query;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.sismics.docs.core.util.jpa;
|
||||
|
||||
/**
|
||||
* Sort criteria of a query.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class SortCriteria {
|
||||
/**
|
||||
* Index of the column to sort (first is 0).
|
||||
*/
|
||||
private int column;
|
||||
|
||||
/**
|
||||
* Sort in increasing order (or else decreasing).
|
||||
*/
|
||||
private boolean asc = true;
|
||||
|
||||
/**
|
||||
* Constructor of sortCriteria.
|
||||
*/
|
||||
public SortCriteria(Integer column, Boolean asc) {
|
||||
if (column != null) {
|
||||
this.column = column;
|
||||
}
|
||||
if (asc != null) {
|
||||
this.asc = asc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of column.
|
||||
*
|
||||
* @return column
|
||||
*/
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of asc.
|
||||
*
|
||||
* @return asc
|
||||
*/
|
||||
public boolean isAsc() {
|
||||
return asc;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package com.sismics.docs.core.util.math;
|
||||
|
||||
|
||||
/**
|
||||
* Classe utilitaire pour les calculs
|
||||
*
|
||||
* @author bgamard
|
||||
*
|
||||
*/
|
||||
public class MathUtil {
|
||||
|
||||
/**
|
||||
* Arrondi à 2 décimales près
|
||||
*
|
||||
* @param d Nombre à arrondir
|
||||
* @return Nombre arrondi
|
||||
*/
|
||||
public static Double round(Double d) {
|
||||
return Math.round(d * 100.0) / 100.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contraint une valeur entre min et max.
|
||||
*
|
||||
* @param value Valeur
|
||||
* @param min Minimum
|
||||
* @param max Maximum
|
||||
* @return Valeur contrainte
|
||||
*/
|
||||
public static double clip(double value, double min, double max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
}
|
||||
if (value > max) {
|
||||
return max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpole une valeur entre deux points.
|
||||
*
|
||||
* @param x Valeur à interpoler
|
||||
* @param x1 Point 1 (x)
|
||||
* @param y1 Point 1 (y)
|
||||
* @param x2 Point 2 (x)
|
||||
* @param y2 Point 2 (y)
|
||||
* @return Valeur interpolée
|
||||
*/
|
||||
public static double interpolate(double x, double x1, double y1, double x2, double y2) {
|
||||
double alpha = (x - x1) / (x2 - x1);
|
||||
|
||||
return y1 * (1 - alpha) + y2 * alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un Double depuis un Number.
|
||||
*
|
||||
* @param number Number
|
||||
* @return Double
|
||||
*/
|
||||
public static Double getDoubleFromNumber(Number number) {
|
||||
if (number == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return number.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un Integer depuis un Number.
|
||||
*
|
||||
* @param number Number
|
||||
* @return Integer
|
||||
*/
|
||||
public static Integer getIntegerFromNumber(Number number) {
|
||||
if (number == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return number.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un Long depuis un Number.
|
||||
*
|
||||
* @param number Number
|
||||
* @return Long
|
||||
*/
|
||||
public static Long getLongFromNumber(Number number) {
|
||||
if (number == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return number.longValue();
|
||||
}
|
||||
}
|
227
docs-core/src/main/java/com/sismics/util/DateUtil.java
Normal file
227
docs-core/src/main/java/com/sismics/util/DateUtil.java
Normal file
@ -0,0 +1,227 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Date utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
private final static ImmutableMap<String, String> TIMEZONE_CODE_MAP = new ImmutableMap.Builder<String, String>()
|
||||
.put(" ACDT", " +10:30")
|
||||
.put(" ACST", " +09:30")
|
||||
.put(" ACT", " +08")
|
||||
.put(" ADT", " −03")
|
||||
.put(" AEDT", " +11")
|
||||
.put(" AEST", " +10")
|
||||
.put(" AFT", " +04:30")
|
||||
.put(" AKDT", " −08")
|
||||
.put(" AKST", " −09")
|
||||
.put(" AMST", " +05")
|
||||
.put(" AMT", " +04")
|
||||
.put(" ART", " −03")
|
||||
// .put(" AST", " +03")
|
||||
.put(" AST", " −04")
|
||||
.put(" AWDT", " +09")
|
||||
.put(" AWST", " +08")
|
||||
.put(" AZOST", " −01")
|
||||
.put(" AZT", " +04")
|
||||
.put(" BDT", " +08")
|
||||
.put(" BIOT", " +06")
|
||||
.put(" BIT", " −12")
|
||||
.put(" BOT", " −04")
|
||||
.put(" BRT", " −03")
|
||||
// .put(" BST", " +06")
|
||||
.put(" BST", " +01")
|
||||
.put(" BTT", " +06")
|
||||
.put(" CAT", " +02")
|
||||
.put(" CCT", " +06:30")
|
||||
.put(" CDT", " −05")
|
||||
// .put(" CDT", " −04")
|
||||
.put(" CEDT", " +02")
|
||||
.put(" CEST", " +02")
|
||||
.put(" CET", " +01")
|
||||
.put(" CHADT", " +13:45")
|
||||
.put(" CHAST", " +12:45")
|
||||
.put(" CHOT", " −08")
|
||||
.put(" ChST", " +10")
|
||||
.put(" CHUT", " +10")
|
||||
.put(" CIST", " −08")
|
||||
.put(" CIT", " +08")
|
||||
.put(" CKT", " −10")
|
||||
.put(" CLST", " −03")
|
||||
.put(" CLT", " −04")
|
||||
.put(" COST", " −04")
|
||||
.put(" COT", " −05")
|
||||
.put(" CST", " −06")
|
||||
// .put(" CST", " +08")
|
||||
// .put(" CST", " +09:30")
|
||||
// .put(" CST", " +10:30")
|
||||
// .put(" CST", " −05")
|
||||
.put(" CT", " +08")
|
||||
.put(" CVT", " −01")
|
||||
.put(" CWST", " +08:45")
|
||||
.put(" CXT", " +07")
|
||||
.put(" DAVT", " +07")
|
||||
.put(" DDUT", " +10")
|
||||
.put(" DFT", " +01")
|
||||
.put(" EASST", " −05")
|
||||
.put(" EAST", " −06")
|
||||
.put(" EAT", " +03")
|
||||
// .put(" ECT", " −04")
|
||||
.put(" ECT", " −05")
|
||||
.put(" EDT", " −04")
|
||||
.put(" EEDT", " +03")
|
||||
.put(" EEST", " +03")
|
||||
.put(" EET", " +02")
|
||||
.put(" EGST", " +00")
|
||||
.put(" EGT", " −01")
|
||||
.put(" EIT", " +09")
|
||||
.put(" EST", " −05")
|
||||
// .put(" EST", " +10")
|
||||
.put(" FET", " +03")
|
||||
.put(" FJT", " +12")
|
||||
.put(" FKST", " −03")
|
||||
.put(" FKT", " −04")
|
||||
.put(" FNT", " −02")
|
||||
.put(" GALT", " −06")
|
||||
.put(" GAMT", " −09")
|
||||
.put(" GET", " +04")
|
||||
.put(" GFT", " −03")
|
||||
.put(" GILT", " +12")
|
||||
.put(" GIT", " −09")
|
||||
.put(" GMT", " ")
|
||||
// .put(" GST", " −02")
|
||||
.put(" GST", " +04")
|
||||
.put(" GYT", " −04")
|
||||
.put(" HADT", " −09")
|
||||
.put(" HAEC", " +02")
|
||||
.put(" HAST", " −10")
|
||||
.put(" HKT", " +08")
|
||||
.put(" HMT", " +05")
|
||||
.put(" HOVT", " +07")
|
||||
.put(" HST", " −10")
|
||||
.put(" ICT", " +07")
|
||||
.put(" IDT", " +03")
|
||||
.put(" IOT", " +03")
|
||||
.put(" IRDT", " +08")
|
||||
.put(" IRKT", " +09")
|
||||
.put(" IRST", " +03:30")
|
||||
.put(" IST", " +05:30")
|
||||
// .put(" IST", " +01")
|
||||
// .put(" IST", " +02")
|
||||
// .put(" JST", " +09")
|
||||
.put(" KGT", " +06")
|
||||
.put(" KOST", " +11")
|
||||
.put(" KRAT", " +07")
|
||||
.put(" KST", " +09")
|
||||
.put(" LHST", " +10:30")
|
||||
// .put(" LHST", " +11")
|
||||
.put(" LINT", " +14")
|
||||
.put(" MAGT", " +12")
|
||||
.put(" MART", " −09:30")
|
||||
.put(" MAWT", " +05")
|
||||
.put(" MDT", " −06")
|
||||
.put(" MET", " +01")
|
||||
.put(" MEST", " +02")
|
||||
.put(" MHT", " +12")
|
||||
.put(" MIST", " +11")
|
||||
.put(" MIT", " −09:30")
|
||||
.put(" MMT", " +06:30")
|
||||
.put(" MSK", " +04")
|
||||
// .put(" MST", " +08")
|
||||
.put(" MST", " −07")
|
||||
// .put(" MST", " +06:30")
|
||||
.put(" MUT", " +04")
|
||||
.put(" MVT", " +05")
|
||||
.put(" MYT", " +08")
|
||||
.put(" NCT", " +11")
|
||||
.put(" NDT", " −02:30")
|
||||
.put(" NFT", " +11:30")
|
||||
.put(" NPT", " +05:45")
|
||||
.put(" NST", " −03:30")
|
||||
.put(" NT", " −03:30")
|
||||
.put(" NUT", " −11:30")
|
||||
.put(" NZDT", " +13")
|
||||
.put(" NZST", " +12")
|
||||
.put(" OMST", " +06")
|
||||
.put(" ORAT", " +05")
|
||||
.put(" PDT", " −07")
|
||||
.put(" PET", " −05")
|
||||
.put(" PETT", " +12")
|
||||
.put(" PGT", " +10")
|
||||
.put(" PHOT", " +13")
|
||||
.put(" PHT", " +08")
|
||||
.put(" PKT", " +05")
|
||||
.put(" PMDT", " −02")
|
||||
.put(" PMST", " −03")
|
||||
.put(" PONT", " +11")
|
||||
.put(" PST", " −08")
|
||||
// .put(" PST", " +08")
|
||||
.put(" RET", " +04")
|
||||
.put(" ROTT", " −03")
|
||||
.put(" SAKT", " +11")
|
||||
.put(" SAMT", " +04")
|
||||
.put(" SAST", " +02")
|
||||
.put(" SBT", " +11")
|
||||
.put(" SCT", " +04")
|
||||
.put(" SGT", " +08")
|
||||
.put(" SLT", " +05:30")
|
||||
.put(" SRT", " −03")
|
||||
.put(" SST", " −11")
|
||||
// .put(" SST", " +08")
|
||||
.put(" SYOT", " +03")
|
||||
.put(" TAHT", " −10")
|
||||
.put(" THA", " +07")
|
||||
.put(" TFT", " +05")
|
||||
.put(" TJT", " +05")
|
||||
.put(" TKT", " +14")
|
||||
.put(" TLT", " +09")
|
||||
.put(" TMT", " +05")
|
||||
.put(" TOT", " +13")
|
||||
.put(" TVT", " +12")
|
||||
.put(" UCT", " ")
|
||||
.put(" ULAT", " +08")
|
||||
.put(" UTC", " ")
|
||||
.put(" UYST", " −02")
|
||||
.put(" UYT", " −03")
|
||||
.put(" UZT", " +05")
|
||||
.put(" VET", " −04:30")
|
||||
.put(" VLAT", " +10")
|
||||
.put(" VOLT", " +04")
|
||||
.put(" VOST", " +06")
|
||||
.put(" VUT", " +11")
|
||||
.put(" WAKT", " +12")
|
||||
.put(" WAST", " +02")
|
||||
.put(" WAT", " +01")
|
||||
.put(" WEDT", " +01")
|
||||
.put(" WEST", " +01")
|
||||
.put(" WET", " ")
|
||||
.put(" WST", " +08")
|
||||
.put(" YAKT", " +09")
|
||||
.put(" YEKT", " +05")
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Try to guess the timezone code, and replace it with a timezone offset.
|
||||
* Note: JodaTime can guess a few codes already, they didn't include all codes since they are not standardized.
|
||||
* This method should only be used in last resort.
|
||||
*
|
||||
* @param date Formated date, supposedly ending with a timezone code
|
||||
* @return Date with the code replaced by its offset if there is a match
|
||||
*/
|
||||
public static String guessTimezoneOffset(String date) {
|
||||
for (Entry<String, String> entry : TIMEZONE_CODE_MAP.entrySet()) {
|
||||
String code = entry.getKey();
|
||||
String offset = entry.getValue();
|
||||
if (date.endsWith(code)) {
|
||||
return date.substring(0, date.length() - code.length()) + offset;
|
||||
}
|
||||
}
|
||||
return date;
|
||||
}
|
||||
}
|
106
docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java
Normal file
106
docs-core/src/main/java/com/sismics/util/EnvironmentUtil.java
Normal file
@ -0,0 +1,106 @@
|
||||
package com.sismics.util;
|
||||
|
||||
/**
|
||||
* Environment properties utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class EnvironmentUtil {
|
||||
|
||||
private static String OS = System.getProperty("os.name").toLowerCase();
|
||||
|
||||
private static String TEST_ENV = System.getProperty("test");
|
||||
|
||||
private static String WINDOWS_APPDATA = System.getenv("APPDATA");
|
||||
|
||||
private static String MAC_OS_USER_HOME = System.getProperty("user.home");
|
||||
|
||||
private static String DOCS_HOME = System.getProperty("docs.home");
|
||||
|
||||
/**
|
||||
* Web application root.
|
||||
*/
|
||||
private static String webappRoot;
|
||||
|
||||
/**
|
||||
* Returns true if running under Microsoft Windows.
|
||||
*
|
||||
* @return Running under Microsoft Windows
|
||||
*/
|
||||
public static boolean isWindows() {
|
||||
return OS.indexOf("win") >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if running under Mac OS.
|
||||
*
|
||||
* @return Running under Mac OS
|
||||
*/
|
||||
public static boolean isMacOs() {
|
||||
return OS.indexOf("mac") >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if running under UNIX.
|
||||
*
|
||||
* @return Running under UNIX
|
||||
*/
|
||||
public static boolean isUnix() {
|
||||
return OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we are in a unit testing environment.
|
||||
*
|
||||
* @return Unit testing environment
|
||||
*/
|
||||
public static boolean isUnitTest() {
|
||||
return webappRoot == null ||
|
||||
TEST_ENV != null && "true".equals(TEST_ENV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MS Windows AppData directory of this user.
|
||||
*
|
||||
* @return AppData directory
|
||||
*/
|
||||
public static String getWindowsAppData() {
|
||||
return WINDOWS_APPDATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Mac OS home directory of this user.
|
||||
*
|
||||
* @return Home directory
|
||||
*/
|
||||
public static String getMacOsUserHome() {
|
||||
return MAC_OS_USER_HOME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the home directory of DOCS (e.g. /var/docs).
|
||||
*
|
||||
* @return Home directory
|
||||
*/
|
||||
public static String getDocsHome() {
|
||||
return DOCS_HOME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of webappRoot.
|
||||
*
|
||||
* @return webappRoot
|
||||
*/
|
||||
public static String getWebappRoot() {
|
||||
return webappRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of webappRoot.
|
||||
*
|
||||
* @param webappRoot webappRoot
|
||||
*/
|
||||
public static void setWebappRoot(String webappRoot) {
|
||||
EnvironmentUtil.webappRoot = webappRoot;
|
||||
}
|
||||
}
|
93
docs-core/src/main/java/com/sismics/util/HttpUtil.java
Normal file
93
docs-core/src/main/java/com/sismics/util/HttpUtil.java
Normal file
@ -0,0 +1,93 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* HTTP request utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class HttpUtil {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);
|
||||
|
||||
/**
|
||||
* Loads the content of an URL into a string.
|
||||
*
|
||||
* @param url URL to load
|
||||
* @return Contents of the resource
|
||||
*/
|
||||
public static String readUrlIntoString(URL url) {
|
||||
URLConnection connection;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
connection = url.openConnection();
|
||||
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String inputLine;
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
sb.append(inputLine);
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (IOException e) {
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error("Error reading URL", e);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String postUrl(URL url, String data) throws IOException {
|
||||
OutputStreamWriter wr = null;
|
||||
BufferedReader rd = null;
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDoOutput(true);
|
||||
wr = new OutputStreamWriter(conn.getOutputStream());
|
||||
wr.write(data);
|
||||
wr.flush();
|
||||
|
||||
// Get the response
|
||||
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line = null;
|
||||
while ((line = rd.readLine()) != null) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
} finally {
|
||||
if (wr != null) {
|
||||
try {
|
||||
wr.close();
|
||||
} catch (IOException e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
if (rd != null) {
|
||||
try {
|
||||
rd.close();
|
||||
} catch (IOException e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
111
docs-core/src/main/java/com/sismics/util/JsonValidationUtil.java
Normal file
111
docs-core/src/main/java/com/sismics/util/JsonValidationUtil.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
|
||||
/**
|
||||
* JSON validation utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class JsonValidationUtil {
|
||||
|
||||
/**
|
||||
* Checks if the JSON node contains the properties (not null).
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonRequired(JsonNode n, String name) throws Exception {
|
||||
if (!n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the property is a JSON object.
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @param required Property required
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonObject(JsonNode n, String name, boolean required) throws Exception {
|
||||
if (required && !n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (n.has(name) && !n.path(name).isObject()) {
|
||||
throw new Exception(MessageFormat.format("{0} must be a JSON object", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the property is a number.
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @param required Property required
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonNumber(JsonNode n, String name, boolean required) throws Exception {
|
||||
if (required && !n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (n.has(name) && !n.path(name).isNumber()) {
|
||||
throw new Exception(MessageFormat.format("{0} must be a number", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the property is a long.
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @param required Property required
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonLong(JsonNode n, String name, boolean required) throws Exception {
|
||||
if (required && !n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (n.has(name) && !n.path(name).isLong()) {
|
||||
throw new Exception(MessageFormat.format("{0} must be a long", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the property is a string.
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @param required Property required
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonString(JsonNode n, String name, boolean required) throws Exception {
|
||||
if (required && !n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (n.has(name) && !n.path(name).isTextual()) {
|
||||
throw new Exception(MessageFormat.format("{0} must be a string", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the property is an array.
|
||||
*
|
||||
* @param s JSON node to check
|
||||
* @param name Name of the property
|
||||
* @param required Property required
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateJsonArray(JsonNode n, String name, boolean required) throws Exception {
|
||||
if (required && !n.has(name)) {
|
||||
throw new Exception(MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (n.has(name) && !n.path(name).isArray()) {
|
||||
throw new Exception(MessageFormat.format("{0} must be an array", name));
|
||||
}
|
||||
}
|
||||
}
|
63
docs-core/src/main/java/com/sismics/util/LocaleUtil.java
Normal file
63
docs-core/src/main/java/com/sismics/util/LocaleUtil.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.LocaleDao;
|
||||
|
||||
/**
|
||||
* Locale utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class LocaleUtil {
|
||||
/**
|
||||
* Returns the locale from its language / country code (ex: fr_FR).
|
||||
*
|
||||
* @param localeCode Locale code
|
||||
* @return Locate instance
|
||||
*/
|
||||
public static final Locale getLocale(String localeCode) {
|
||||
String[] localeCodeArray = localeCode.split("_");
|
||||
String language = localeCodeArray[0];
|
||||
String country = "";
|
||||
String variant = "";
|
||||
if (localeCodeArray.length >= 2) {
|
||||
country = localeCodeArray[1];
|
||||
}
|
||||
if (localeCodeArray.length >= 3) {
|
||||
variant = localeCodeArray[2];
|
||||
}
|
||||
return new Locale(language, country, variant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the ID of the locale from the HTTP Accept-Language header.
|
||||
*
|
||||
* @param HTTP header
|
||||
* @return Locale ID
|
||||
*/
|
||||
public static String getLocaleIdFromAcceptLanguage(String acceptLanguageHeader) {
|
||||
String localeId = null;
|
||||
if (StringUtils.isNotBlank(acceptLanguageHeader)) {
|
||||
acceptLanguageHeader = acceptLanguageHeader.replaceAll("-", "_");
|
||||
localeId = acceptLanguageHeader.split(",")[0];
|
||||
}
|
||||
if (StringUtils.isNotBlank(localeId)) {
|
||||
LocaleDao localeDao = new LocaleDao();
|
||||
com.sismics.docs.core.model.jpa.Locale locale = localeDao.getById(localeId);
|
||||
if (locale != null) {
|
||||
localeId = locale.getId();
|
||||
} else {
|
||||
// The client provided an unknown locale
|
||||
localeId = Constants.DEFAULT_LOCALE_ID;
|
||||
}
|
||||
}
|
||||
if (StringUtils.isBlank(localeId)) {
|
||||
localeId = Constants.DEFAULT_LOCALE_ID;
|
||||
}
|
||||
return localeId;
|
||||
}
|
||||
}
|
43
docs-core/src/main/java/com/sismics/util/MessageUtil.java
Normal file
43
docs-core/src/main/java/com/sismics/util/MessageUtil.java
Normal file
@ -0,0 +1,43 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Message utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class MessageUtil {
|
||||
/**
|
||||
* Returns a message formated in the specified locale.
|
||||
* Returns **key** if no message is set for this key.
|
||||
*
|
||||
* @param locale Locale
|
||||
* @param key Message key
|
||||
* @param args Arguments of the message
|
||||
* @return Formated message
|
||||
*/
|
||||
public static String getMessage(Locale locale, String key, Object... args) {
|
||||
ResourceBundle resources = ResourceBundle.getBundle("messages", locale);
|
||||
String message = null;
|
||||
try {
|
||||
message = resources.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
message = "**" + key + "**";
|
||||
}
|
||||
return MessageFormat.format(message, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource bundle containing messages for the locale.
|
||||
*
|
||||
* @param locale Locale to use
|
||||
* @return Resource bundle
|
||||
*/
|
||||
public static ResourceBundle getMessage(Locale locale) {
|
||||
return ResourceBundle.getBundle("messages", locale);
|
||||
}
|
||||
}
|
101
docs-core/src/main/java/com/sismics/util/ResourceUtil.java
Normal file
101
docs-core/src/main/java/com/sismics/util/ResourceUtil.java
Normal file
@ -0,0 +1,101 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Resource utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ResourceUtil {
|
||||
|
||||
/**
|
||||
* List files inside a directory. The path can be a directory on the filesystem, or inside a JAR.
|
||||
*
|
||||
* @param clazz Class
|
||||
* @param path Path
|
||||
* @param filter Filter
|
||||
* @return List of files
|
||||
* @throws URISyntaxException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<String> list(Class<?> clazz, String path, FilenameFilter filter) throws URISyntaxException, IOException {
|
||||
// Path is a directory on the filesystem
|
||||
URL dirUrl = clazz.getResource(path);
|
||||
if (dirUrl != null && dirUrl.getProtocol().equals("file")) {
|
||||
return Arrays.asList(new File(dirUrl.toURI()).list(filter));
|
||||
}
|
||||
|
||||
// Path is a directory inside the same JAR as clazz
|
||||
if (dirUrl == null) {
|
||||
String className = clazz.getName().replace(".", "/") + ".class";
|
||||
dirUrl = clazz.getClassLoader().getResource(className);
|
||||
}
|
||||
|
||||
if (dirUrl.getProtocol().equals("jar")) {
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
if (!path.endsWith("/")) {
|
||||
path = path + "/";
|
||||
}
|
||||
|
||||
// Extract the JAR path
|
||||
String jarPath = dirUrl.getPath().substring(5, dirUrl.getPath().indexOf("!"));
|
||||
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
|
||||
|
||||
Enumeration<JarEntry> entries = jar.entries();
|
||||
Set<String> fileSet = new HashSet<String>();
|
||||
while (entries.hasMoreElements()) {
|
||||
// Filter according to the path
|
||||
String entryName = entries.nextElement().getName();
|
||||
if (!entryName.startsWith(path)) {
|
||||
continue;
|
||||
}
|
||||
String name = entryName.substring(path.length());
|
||||
if (!"".equals(name)) {
|
||||
// If it is a subdirectory, just return the directory name
|
||||
int checkSubdir = name.indexOf("/");
|
||||
if (checkSubdir >= 0) {
|
||||
name = name.substring(0, checkSubdir);
|
||||
}
|
||||
|
||||
if (filter == null || filter.accept(null, name)) {
|
||||
fileSet.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Lists.newArrayList(fileSet);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(MessageFormat.format("Cannot list files for URL {0}", dirUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* List files inside a directory. The path can be a directory on the filesystem, or inside a JAR.
|
||||
*
|
||||
* @param clazz Class
|
||||
* @param path Path
|
||||
* @return List of files
|
||||
* @throws URISyntaxException
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<String> list(Class<?> clazz, String path) throws URISyntaxException, IOException {
|
||||
return list(clazz, path, null);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.sismics.util.context;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* Context associated to a user request, and stored in a ThreadLocal.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ThreadLocalContext {
|
||||
/**
|
||||
* ThreadLocal to store the context.
|
||||
*/
|
||||
public static final ThreadLocal<ThreadLocalContext> threadLocalContext = new ThreadLocal<ThreadLocalContext>();
|
||||
|
||||
/**
|
||||
* Entity manager.
|
||||
*/
|
||||
private EntityManager entityManager;
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private ThreadLocalContext() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of this thread context.
|
||||
*
|
||||
* @return Thread local context
|
||||
*/
|
||||
public static ThreadLocalContext get() {
|
||||
ThreadLocalContext context = threadLocalContext.get();
|
||||
if (context == null) {
|
||||
context = new ThreadLocalContext();
|
||||
threadLocalContext.set(context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up the instance of this thread context.
|
||||
*/
|
||||
public static void cleanup() {
|
||||
threadLocalContext.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true only if the entity manager is defined.
|
||||
*
|
||||
* @return Condition
|
||||
*/
|
||||
public boolean isInTransactionalContext() {
|
||||
return entityManager != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of entityManager.
|
||||
*
|
||||
* @return entityManager
|
||||
*/
|
||||
public EntityManager getEntityManager() {
|
||||
return entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of entityManager.
|
||||
*
|
||||
* @param entityManager entityManager
|
||||
*/
|
||||
public void setEntityManager(EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
}
|
231
docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java
Normal file
231
docs-core/src/main/java/com/sismics/util/jpa/DbOpenHelper.java
Normal file
@ -0,0 +1,231 @@
|
||||
package com.sismics.util.jpa;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Writer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.internal.FormatStyle;
|
||||
import org.hibernate.engine.jdbc.internal.Formatter;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.tool.hbm2ddl.ConnectionHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.sismics.docs.core.util.ConfigUtil;
|
||||
import com.sismics.util.ResourceUtil;
|
||||
|
||||
/**
|
||||
* A helper to update the database incrementally.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public abstract class DbOpenHelper {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(DbOpenHelper.class);
|
||||
|
||||
private final ConnectionHelper connectionHelper;
|
||||
|
||||
private final SqlStatementLogger sqlStatementLogger;
|
||||
|
||||
private final List<Exception> exceptions = new ArrayList<Exception>();
|
||||
|
||||
private Formatter formatter;
|
||||
|
||||
private boolean haltOnError;
|
||||
|
||||
private Statement stmt;
|
||||
|
||||
public DbOpenHelper(ServiceRegistry serviceRegistry) throws HibernateException {
|
||||
final JdbcServices jdbcServices = serviceRegistry.getService(JdbcServices.class);
|
||||
connectionHelper = new SuppliedConnectionProviderConnectionHelper(jdbcServices.getConnectionProvider());
|
||||
|
||||
sqlStatementLogger = jdbcServices.getSqlStatementLogger();
|
||||
formatter = (sqlStatementLogger.isFormat() ? FormatStyle.DDL : FormatStyle.NONE).getFormatter();
|
||||
}
|
||||
|
||||
public void open() {
|
||||
log.info("Opening database and executing incremental updates");
|
||||
|
||||
Connection connection = null;
|
||||
Writer outputFileWriter = null;
|
||||
|
||||
exceptions.clear();
|
||||
|
||||
try {
|
||||
try {
|
||||
connectionHelper.prepare(true);
|
||||
connection = connectionHelper.getConnection();
|
||||
} catch (SQLException sqle) {
|
||||
exceptions.add(sqle);
|
||||
log.error("Unable to get database metadata", sqle);
|
||||
throw sqle;
|
||||
}
|
||||
|
||||
// Check if database is already created
|
||||
Integer oldVersion = null;
|
||||
try {
|
||||
stmt = connection.createStatement();
|
||||
ResultSet result = stmt.executeQuery("select c.CFG_VALUE_C from T_CONFIG c where c.CFG_ID_C='DB_VERSION'");
|
||||
if (result.next()) {
|
||||
String oldVersionStr = result.getString(1);
|
||||
oldVersion = Integer.parseInt(oldVersionStr);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().contains("object not found")) {
|
||||
log.info("Unable to get database version: Table T_CONFIG not found");
|
||||
} else {
|
||||
log.error("Unable to get database version", e);
|
||||
}
|
||||
} finally {
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
stmt = null;
|
||||
}
|
||||
}
|
||||
|
||||
stmt = connection.createStatement();
|
||||
if (oldVersion == null) {
|
||||
// Execute creation script
|
||||
log.info("Executing initial schema creation script");
|
||||
onCreate();
|
||||
oldVersion = 0;
|
||||
}
|
||||
|
||||
// Execute update script
|
||||
ResourceBundle configBundle = ConfigUtil.getConfigBundle();
|
||||
Integer currentVersion = Integer.parseInt(configBundle.getString("db.version"));
|
||||
log.info(MessageFormat.format("Found database version {0}, new version is {1}, executing database incremental update scripts", oldVersion, currentVersion));
|
||||
onUpgrade(oldVersion, currentVersion);
|
||||
log.info("Database upgrade complete");
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
log.error("Unable to complete schema update", e);
|
||||
} finally {
|
||||
try {
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
stmt = null;
|
||||
}
|
||||
connectionHelper.release();
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
log.error("Unable to close connection", e);
|
||||
}
|
||||
try {
|
||||
if (outputFileWriter != null) {
|
||||
outputFileWriter.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
exceptions.add(e);
|
||||
log.error("Unable to close connection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all upgrade scripts in ascending order for a given version.
|
||||
*
|
||||
* @param version Version number
|
||||
* @throws Exception
|
||||
*/
|
||||
protected void executeAllScript(final int version) throws Exception {
|
||||
List<String> fileNameList = ResourceUtil.list(getClass(), "/db/update/", new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
String versionString = String.format("%03d", version);
|
||||
return name.matches("dbupdate-" + versionString + "-\\d+\\.sql");
|
||||
}
|
||||
});
|
||||
Collections.sort(fileNameList);
|
||||
|
||||
for (String fileName : fileNameList) {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(MessageFormat.format("Executing script: {0}", fileName));
|
||||
}
|
||||
InputStream is = getClass().getResourceAsStream("/db/update/" + fileName);
|
||||
executeScript(is);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a SQL script. All statements must be one line only.
|
||||
*
|
||||
* @param inputScript Script to execute
|
||||
* @throws IOException
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void executeScript(InputStream inputScript) throws IOException, SQLException {
|
||||
List<String> lines = CharStreams.readLines(new InputStreamReader(inputScript));
|
||||
|
||||
for (String sql : lines) {
|
||||
if (Strings.isNullOrEmpty(sql) || sql.startsWith("--")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String formatted = formatter.format(sql);
|
||||
try {
|
||||
log.debug(formatted);
|
||||
stmt.executeUpdate(formatted);
|
||||
} catch (SQLException e) {
|
||||
if (haltOnError) {
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
stmt = null;
|
||||
}
|
||||
throw new JDBCException("Error during script execution", e);
|
||||
}
|
||||
exceptions.add(e);
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error("Error executing SQL statement: {}", sql);
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onCreate() throws Exception;
|
||||
|
||||
public abstract void onUpgrade(int oldVersion, int newVersion) throws Exception;
|
||||
|
||||
/**
|
||||
* Returns a List of all Exceptions which occured during the export.
|
||||
*
|
||||
* @return A List containig the Exceptions occured during the export
|
||||
*/
|
||||
public List<?> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
public void setHaltOnError(boolean haltOnError) {
|
||||
this.haltOnError = haltOnError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the output SQL statements.
|
||||
*
|
||||
* @param format True to format
|
||||
*/
|
||||
public void setFormat(boolean format) {
|
||||
this.formatter = (format ? FormatStyle.DDL : FormatStyle.NONE).getFormatter();
|
||||
}
|
||||
}
|
111
docs-core/src/main/java/com/sismics/util/jpa/EMF.java
Normal file
111
docs-core/src/main/java/com/sismics/util/jpa/EMF.java
Normal file
@ -0,0 +1,111 @@
|
||||
package com.sismics.util.jpa;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
|
||||
/**
|
||||
* Entity manager factory.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public final class EMF {
|
||||
private static final Logger log = LoggerFactory.getLogger(EMF.class);
|
||||
|
||||
private static EntityManagerFactory emfInstance;
|
||||
|
||||
static {
|
||||
try {
|
||||
Map<Object, Object> properties = getEntityManagerProperties();
|
||||
|
||||
Environment.verifyProperties(properties);
|
||||
ConfigurationHelper.resolvePlaceHolders(properties);
|
||||
ServiceRegistry reg = new ServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();
|
||||
|
||||
DbOpenHelper openHelper = new DbOpenHelper(reg) {
|
||||
|
||||
@Override
|
||||
public void onCreate() throws Exception {
|
||||
executeAllScript(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(int oldVersion, int newVersion) throws Exception {
|
||||
for (int version = oldVersion + 1; version <= newVersion; version++) {
|
||||
executeAllScript(version);
|
||||
}
|
||||
}
|
||||
};
|
||||
openHelper.open();
|
||||
|
||||
emfInstance = Persistence.createEntityManagerFactory("transactions-optional", getEntityManagerProperties());
|
||||
|
||||
} catch (Throwable t) {
|
||||
log.error("Error creating EMF", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<Object, Object> getEntityManagerProperties() {
|
||||
// Use properties file if exists
|
||||
try {
|
||||
URL hibernatePropertiesUrl = EMF.class.getResource("/hibernate.properties");
|
||||
if (hibernatePropertiesUrl != null) {
|
||||
log.info("Configuring EntityManager from hibernate.properties");
|
||||
|
||||
InputStream is = hibernatePropertiesUrl.openStream();
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
return properties;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading hibernate.properties", e);
|
||||
}
|
||||
|
||||
// Use environment parameters
|
||||
log.info("Configuring EntityManager from environment parameters");
|
||||
Map<Object, Object> props = new HashMap<Object, Object>();
|
||||
props.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver");
|
||||
File dbDirectory = DirectoryUtil.getDbDirectory();
|
||||
String dbFile = dbDirectory.getAbsoluteFile() + File.separator + "docs";
|
||||
props.put("hibernate.connection.url", "jdbc:hsqldb:file:" + dbFile + ";hsqldb.write_delay=false;shutdown=true");
|
||||
props.put("hibernate.connection.username", "sa");
|
||||
props.put("hibernate.hbm2ddl.auto", "none");
|
||||
props.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
|
||||
props.put("hibernate.show_sql", "false");
|
||||
props.put("hibernate.format_sql", "false");
|
||||
props.put("hibernate.max_fetch_depth", "5");
|
||||
props.put("hibernate.cache.use_second_level_cache", "false");
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private EMF() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of EMF.
|
||||
*
|
||||
* @return Instance of EMF
|
||||
*/
|
||||
public static EntityManagerFactory get() {
|
||||
return emfInstance;
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sismics.util.jpa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.tool.hbm2ddl.ConnectionHelper;
|
||||
|
||||
/**
|
||||
* A {@link ConnectionHelper} implementation based on an internally
|
||||
* built and managed {@link ConnectionProvider}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class ManagedProviderConnectionHelper implements ConnectionHelper {
|
||||
private Properties cfgProperties;
|
||||
private StandardServiceRegistryImpl serviceRegistry;
|
||||
private Connection connection;
|
||||
|
||||
public ManagedProviderConnectionHelper(Properties cfgProperties) {
|
||||
this.cfgProperties = cfgProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(boolean needsAutoCommit) throws SQLException {
|
||||
serviceRegistry = createServiceRegistry(cfgProperties);
|
||||
connection = serviceRegistry.getService(ConnectionProvider.class).getConnection();
|
||||
if (needsAutoCommit && !connection.getAutoCommit()) {
|
||||
connection.commit();
|
||||
connection.setAutoCommit(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static StandardServiceRegistryImpl createServiceRegistry(Properties properties) {
|
||||
Environment.verifyProperties(properties);
|
||||
ConfigurationHelper.resolvePlaceHolders(properties);
|
||||
return (StandardServiceRegistryImpl) new ServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() throws SQLException {
|
||||
try {
|
||||
releaseConnection();
|
||||
} finally {
|
||||
releaseServiceRegistry();
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseConnection() throws SQLException {
|
||||
if (connection != null) {
|
||||
try {
|
||||
new SqlExceptionHelper().logAndClearWarnings(connection);
|
||||
} finally {
|
||||
try {
|
||||
serviceRegistry.getService(ConnectionProvider.class).closeConnection(connection);
|
||||
} finally {
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseServiceRegistry() {
|
||||
if (serviceRegistry != null) {
|
||||
try {
|
||||
serviceRegistry.destroy();
|
||||
} finally {
|
||||
serviceRegistry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.sismics.util.jpa;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.ejb.HibernateEntityManagerFactory;
|
||||
|
||||
/**
|
||||
* Hibernate session utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public final class SessionUtil {
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private SessionUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the current session.
|
||||
*
|
||||
* @return Instance of the current session
|
||||
*/
|
||||
public static Session getCurrentSession() {
|
||||
SessionFactory sessionFactory = ((HibernateEntityManagerFactory) EMF.get()).getSessionFactory();
|
||||
return sessionFactory.getCurrentSession();
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
package com.sismics.util.jpa;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.tool.hbm2ddl.ConnectionHelper;
|
||||
|
||||
/**
|
||||
* A {@link ConnectionHelper} implementation based on a provided
|
||||
* {@link ConnectionProvider}. Essentially, ensures that the connection
|
||||
* gets cleaned up, but that the provider itself remains usable since it
|
||||
* was externally provided to us.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class SuppliedConnectionProviderConnectionHelper implements ConnectionHelper {
|
||||
private ConnectionProvider provider;
|
||||
private Connection connection;
|
||||
private boolean toggleAutoCommit;
|
||||
|
||||
public SuppliedConnectionProviderConnectionHelper(ConnectionProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(boolean needsAutoCommit) throws SQLException {
|
||||
connection = provider.getConnection();
|
||||
toggleAutoCommit = needsAutoCommit && !connection.getAutoCommit();
|
||||
if ( toggleAutoCommit ) {
|
||||
try {
|
||||
connection.commit();
|
||||
}
|
||||
catch( Throwable ignore ) {
|
||||
// might happen with a managed connection
|
||||
}
|
||||
connection.setAutoCommit( true );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() throws SQLException {
|
||||
// we only release the connection
|
||||
if ( connection != null ) {
|
||||
new SqlExceptionHelper().logAndClearWarnings( connection );
|
||||
if ( toggleAutoCommit ) {
|
||||
connection.setAutoCommit( false );
|
||||
}
|
||||
provider.closeConnection( connection );
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.sismics.util.log4j;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* Log search criteria.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class LogCriteria {
|
||||
|
||||
/**
|
||||
* Logging level (DEBUG, WARN)...
|
||||
*/
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* Logger name / tag.
|
||||
*/
|
||||
private String tag;
|
||||
|
||||
/**
|
||||
* Message logged.
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Getter of level.
|
||||
*
|
||||
* @return level
|
||||
*/
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of level.
|
||||
*
|
||||
* @param level level
|
||||
*/
|
||||
public void setLevel(String level) {
|
||||
this.level = StringUtils.lowerCase(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of tag.
|
||||
*
|
||||
* @return tag
|
||||
*/
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of tag.
|
||||
*
|
||||
* @param tag tag
|
||||
*/
|
||||
public void setTag(String tag) {
|
||||
this.tag = StringUtils.lowerCase(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of message.
|
||||
*
|
||||
* @return message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of message.
|
||||
*
|
||||
* @param message message
|
||||
*/
|
||||
public void setMessage(String message) {
|
||||
this.message = StringUtils.lowerCase(message);
|
||||
}
|
||||
}
|
79
docs-core/src/main/java/com/sismics/util/log4j/LogEntry.java
Normal file
79
docs-core/src/main/java/com/sismics/util/log4j/LogEntry.java
Normal file
@ -0,0 +1,79 @@
|
||||
package com.sismics.util.log4j;
|
||||
|
||||
/**
|
||||
* Log entry.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class LogEntry {
|
||||
/**
|
||||
* Time stamp.
|
||||
*/
|
||||
private long timestamp;
|
||||
|
||||
/**
|
||||
* Logging level (DEBUG, WARN)...
|
||||
*/
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* Logger name / tag.
|
||||
*/
|
||||
private String tag;
|
||||
|
||||
/**
|
||||
* Message logged.
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Constructor of LogEntry.
|
||||
*
|
||||
* @param timestamp Timestamp
|
||||
* @param level Logging level (DEBUG, WARN)...
|
||||
* @param tag Logger name / tag
|
||||
* @param message Message logged
|
||||
*/
|
||||
public LogEntry(long timestamp, String level, String tag, String message) {
|
||||
this.timestamp = timestamp;
|
||||
this.level = level;
|
||||
this.tag = tag;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of timestamp.
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of level.
|
||||
*
|
||||
* @return level
|
||||
*/
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of tag.
|
||||
*
|
||||
* @return tag
|
||||
*/
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of message.
|
||||
*
|
||||
* @return message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.sismics.util.log4j;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.apache.log4j.AppenderSkeleton;
|
||||
import org.apache.log4j.helpers.LogLog;
|
||||
import org.apache.log4j.spi.LoggingEvent;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||
|
||||
/**
|
||||
* Memory appender for Log4J.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class MemoryAppender extends AppenderSkeleton {
|
||||
|
||||
/**
|
||||
* Maximum size of the queue.
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* Queue of log entries.
|
||||
*/
|
||||
private final Queue<LogEntry> logQueue = new ConcurrentLinkedQueue<LogEntry>();
|
||||
|
||||
@Override
|
||||
public boolean requiresLayout() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void append(LoggingEvent event) {
|
||||
// TODO Don't use size()
|
||||
while (logQueue.size() > size) {
|
||||
logQueue.remove();
|
||||
}
|
||||
if (closed) {
|
||||
LogLog.warn("This appender is already closed, cannot append event.");
|
||||
return;
|
||||
}
|
||||
|
||||
String loggerName = getLoggerName(event);
|
||||
|
||||
LogEntry logEntry = new LogEntry(System.currentTimeMillis(), event.getLevel().toString(), loggerName, event.getMessage().toString());
|
||||
logQueue.add(logEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the class name of the logger, without the package name.
|
||||
*
|
||||
* @param event Event
|
||||
* @return Class name
|
||||
*/
|
||||
private String getLoggerName(LoggingEvent event) {
|
||||
int index = event.getLoggerName().lastIndexOf('.');
|
||||
|
||||
return (index > -1) ?
|
||||
event.getLoggerName().substring(index + 1) :
|
||||
event.getLoggerName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of logList.
|
||||
*
|
||||
* @return logList
|
||||
*/
|
||||
public Queue<LogEntry> getLogList() {
|
||||
return logQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of size.
|
||||
*
|
||||
* @param size size
|
||||
*/
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find some logs.
|
||||
*
|
||||
* @param criteria Search criteria
|
||||
* @param list Paginated list (modified by side effect)
|
||||
*/
|
||||
public void find(LogCriteria criteria, PaginatedList<LogEntry> list) {
|
||||
List<LogEntry> logEntryList = new LinkedList<LogEntry>();
|
||||
final String level = criteria.getLevel();
|
||||
final String tag = criteria.getTag();
|
||||
final String message = criteria.getMessage();
|
||||
int resultCount = 0;
|
||||
for (Iterator<LogEntry> it = logQueue.iterator(); it.hasNext();) {
|
||||
LogEntry logEntry = it.next();
|
||||
if ((level == null || logEntry.getLevel().toLowerCase().equals(level)) &&
|
||||
(tag == null || logEntry.getTag().toLowerCase().equals(tag)) &&
|
||||
(message == null || logEntry.getMessage().toLowerCase().contains(message))) {
|
||||
logEntryList.add(logEntry);
|
||||
resultCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int fromIndex = logEntryList.size() - list.getOffset() - list.getLimit();
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
}
|
||||
int toIndex = logEntryList.size() - list.getOffset();
|
||||
if (toIndex > logEntryList.size()) {
|
||||
toIndex = logEntryList.size();
|
||||
}
|
||||
List<LogEntry> logEntrySubList = Lists.reverse(logEntryList.subList(fromIndex, toIndex));
|
||||
list.setResultCount(resultCount);
|
||||
list.setResultList(logEntrySubList);
|
||||
}
|
||||
}
|
19
docs-core/src/main/java/com/sismics/util/mime/MimeType.java
Normal file
19
docs-core/src/main/java/com/sismics/util/mime/MimeType.java
Normal file
@ -0,0 +1,19 @@
|
||||
package com.sismics.util.mime;
|
||||
|
||||
/**
|
||||
* A collection of MIME types.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class MimeType {
|
||||
|
||||
public static final String IMAGE_X_ICON = "image/x-icon";
|
||||
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String APPLICATION_ZIP = "application/zip";
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.sismics.util.mime;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.PushbackInputStream;
|
||||
|
||||
/**
|
||||
* Utility to check MIME types.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class MimeTypeUtil {
|
||||
/**
|
||||
* Try to guess the MIME type of a file by its magic number (header).
|
||||
*
|
||||
* @param file File to inspect
|
||||
* @return MIME type
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String guessMimeType(InputStream is) throws Exception {
|
||||
byte[] headerBytes = new byte[64];
|
||||
PushbackInputStream pb = new PushbackInputStream(is, headerBytes.length);
|
||||
int readCount = pb.read(headerBytes);
|
||||
pb.unread(headerBytes);
|
||||
|
||||
if (readCount <= 0) {
|
||||
throw new Exception("Cannot read input file");
|
||||
}
|
||||
String header = new String(headerBytes, "US-ASCII");
|
||||
|
||||
if (header.startsWith("PK")) {
|
||||
return MimeType.APPLICATION_ZIP;
|
||||
} else if (header.startsWith("GIF87a") || header.startsWith("GIF89a")) {
|
||||
return MimeType.IMAGE_GIF;
|
||||
} else if (headerBytes[0] == ((byte) 0xff) && headerBytes[1] == ((byte) 0xd8)) {
|
||||
return MimeType.IMAGE_JPEG;
|
||||
} else if (headerBytes[0] == ((byte) 0x89) && headerBytes[1] == ((byte) 0x50) && headerBytes[2] == ((byte) 0x4e) && headerBytes[3] == ((byte) 0x47) &&
|
||||
headerBytes[4] == ((byte) 0x0d) && headerBytes[5] == ((byte) 0x0a) && headerBytes[6] == ((byte) 0x1a) && headerBytes[7] == ((byte) 0x0a)) {
|
||||
return MimeType.IMAGE_PNG;
|
||||
} else if (headerBytes[0] == ((byte) 0x00) && headerBytes[1] == ((byte) 0x00) && headerBytes[2] == ((byte) 0x01) && headerBytes[3] == ((byte) 0x00)) {
|
||||
return MimeType.IMAGE_X_ICON;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
17
docs-core/src/main/resources/META-INF/persistence.xml
Normal file
17
docs-core/src/main/resources/META-INF/persistence.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
|
||||
version="2.0">
|
||||
<persistence-unit name="transactions-optional" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||
|
||||
<class>com.sismics.docs.core.model.jpa.AuthenticationToken</class>
|
||||
<class>com.sismics.docs.core.model.jpa.BaseFunction</class>
|
||||
<class>com.sismics.docs.core.model.jpa.Config</class>
|
||||
<class>com.sismics.docs.core.model.jpa.Locale</class>
|
||||
<class>com.sismics.docs.core.model.jpa.User</class>
|
||||
<class>com.sismics.docs.core.model.jpa.RoleBaseFunction</class>
|
||||
<class>com.sismics.docs.core.model.jpa.Document</class>
|
||||
</persistence-unit>
|
||||
</persistence>
|
1
docs-core/src/main/resources/config.properties
Normal file
1
docs-core/src/main/resources/config.properties
Normal file
@ -0,0 +1 @@
|
||||
db.version=0
|
24
docs-core/src/main/resources/db/update/dbupdate-000-0.sql
Normal file
24
docs-core/src/main/resources/db/update/dbupdate-000-0.sql
Normal file
@ -0,0 +1,24 @@
|
||||
create memory table T_AUTHENTICATION_TOKEN ( AUT_ID_C varchar(36) not null, AUT_IDUSER_C varchar(36) not null, AUT_LONGLASTED_B bit not null, AUT_CREATIONDATE_D datetime not null, AUT_LASTCONNECTIONDATE_D datetime, primary key (AUT_ID_C) );
|
||||
create memory table T_BASE_FUNCTION ( BAF_ID_C varchar(20) not null, primary key (BAF_ID_C) );
|
||||
create cached table T_FILE ( FIL_ID_C varchar(36) not null, FIL_IDDOC_C varchar(36) not null, FIL_MIMETYPE_C varchar(100) not null, FIL_CREATEDATE_D datetime, FIL_DELETEDATE_D datetime, primary key (FIL_ID_C) );
|
||||
create memory table T_CONFIG ( CFG_ID_C varchar(50) not null, CFG_VALUE_C varchar(250) not null, primary key (CFG_ID_C) );
|
||||
create memory table T_LOCALE ( LOC_ID_C varchar(10) not null, primary key (LOC_ID_C) );
|
||||
create cached table T_DOCUMENT ( DOC_ID_C varchar(36) not null, DOC_IDUSER_C varchar(36) not null, DOC_TITLE_C varchar(100) not null, DOC_DESCRIPTION_C varchar(4000), DOC_CREATEDATE_D datetime, DOC_DELETEDATE_D datetime, primary key (DOC_ID_C) );
|
||||
create memory table T_USER ( USE_ID_C varchar(36) not null, USE_IDLOCALE_C varchar(10) not null, USE_IDROLE_C varchar(36) not null, USE_USERNAME_C varchar(50) not null, USE_PASSWORD_C varchar(60) not null, USE_EMAIL_C varchar(100) not null, USE_THEME_C varchar(100) not null, USE_FIRSTCONNECTION_B bit not null, USE_CREATEDATE_D datetime not null, USE_DELETEDATE_D datetime, primary key (USE_ID_C) );
|
||||
create memory table T_ROLE ( ROL_ID_C varchar(36) not null, ROL_NAME_C varchar(36) not null, ROL_CREATEDATE_D datetime not null, ROL_DELETEDATE_D datetime, primary key (ROL_ID_C) );
|
||||
create memory table T_ROLE_BASE_FUNCTION ( RBF_ID_C varchar(36) not null, RBF_IDROLE_C varchar(36) not null, RBF_IDBASEFUNCTION_C varchar(20) not null, RBF_CREATEDATE_D datetime not null, RBF_DELETEDATE_D datetime, primary key (RBF_ID_C) );
|
||||
alter table T_AUTHENTICATION_TOKEN add constraint FK_AUT_IDUSER_C foreign key (AUT_IDUSER_C) references T_USER (USE_ID_C) on delete restrict on update restrict;
|
||||
alter table T_DOCUMENT add constraint FK_DOC_IDUSER_C foreign key (DOC_IDUSER_C) references T_USER (USE_ID_C) on delete restrict on update restrict;
|
||||
alter table T_FILE add constraint FK_FIL_IDDOC_C foreign key (FIL_IDDOC_C) references T_DOCUMENT (DOC_ID_C) on delete restrict on update restrict;
|
||||
alter table T_USER add constraint FK_USE_IDLOCALE_C foreign key (USE_IDLOCALE_C) references T_LOCALE (LOC_ID_C) on delete restrict on update restrict;
|
||||
alter table T_USER add constraint FK_USE_IDROLE_C foreign key (USE_IDROLE_C) references T_ROLE (ROL_ID_C) on delete restrict on update restrict;
|
||||
alter table T_ROLE_BASE_FUNCTION add constraint FK_RBF_IDROLE_C foreign key (RBF_IDROLE_C) references T_ROLE (ROL_ID_C) on delete restrict on update restrict;
|
||||
alter table T_ROLE_BASE_FUNCTION add constraint FK_RBF_IDBASEFUNCTION_C foreign key (RBF_IDBASEFUNCTION_C) references T_BASE_FUNCTION (BAF_ID_C) on delete restrict on update restrict;
|
||||
insert into T_CONFIG(CFG_ID_C, CFG_VALUE_C) values('DB_VERSION', '0');
|
||||
insert into T_CONFIG(CFG_ID_C, CFG_VALUE_C) values('LUCENE_DIRECTORY_STORAGE', 'FILE');
|
||||
insert into T_BASE_FUNCTION(BAF_ID_C) values('ADMIN');
|
||||
insert into T_LOCALE(LOC_ID_C) values('en');
|
||||
insert into T_LOCALE(LOC_ID_C) values('fr');
|
||||
insert into T_ROLE(ROL_ID_C, ROL_NAME_C, ROL_CREATEDATE_D) values('admin', 'Admin', NOW());
|
||||
insert into T_ROLE_BASE_FUNCTION(RBF_ID_C, RBF_IDROLE_C, RBF_IDBASEFUNCTION_C, RBF_CREATEDATE_D) values('admin_ADMIN', 'admin', 'ADMIN', NOW());
|
||||
insert into T_USER(USE_ID_C, USE_IDLOCALE_C, USE_IDROLE_C, USE_USERNAME_C, USE_PASSWORD_C, USE_EMAIL_C, USE_THEME_C, USE_FIRSTCONNECTION_B, USE_CREATEDATE_D) values('admin', 'en', 'admin', 'admin', '$2a$05$6Ny3TjrW3aVAL1or2SlcR.fhuDgPKp5jp.P9fBXwVNePgeLqb4i3C', 'admin@localhost', 'default.less', true, NOW());
|
@ -0,0 +1,31 @@
|
||||
package com.sismics.docs;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
import com.sismics.util.jpa.EMF;
|
||||
|
||||
/**
|
||||
* Base class of tests with a transactional context.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public abstract class BaseTransactionalTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// Initialize the entity manager
|
||||
EntityManager em = EMF.get().createEntityManager();
|
||||
ThreadLocalContext context = ThreadLocalContext.get();
|
||||
context.setEntityManager(em);
|
||||
EntityTransaction tx = em.getTransaction();
|
||||
tx.begin();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.sismics.docs.core.dao.jpa;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sismics.docs.BaseTransactionalTest;
|
||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
|
||||
/**
|
||||
* Tests the persistance layer.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TestJpa extends BaseTransactionalTest {
|
||||
@Test
|
||||
public void testJpa() throws Exception {
|
||||
// Create a user
|
||||
UserDao userDao = new UserDao();
|
||||
User user = new User();
|
||||
user.setUsername("username");
|
||||
user.setEmail("toto@docs.com");
|
||||
user.setLocaleId("fr");
|
||||
user.setRoleId("admin");
|
||||
String id = userDao.create(user);
|
||||
|
||||
TransactionUtil.commit();
|
||||
|
||||
// Search a user by his ID
|
||||
user = userDao.getById(id);
|
||||
Assert.assertNotNull(user);
|
||||
Assert.assertEquals("toto@docs.com", user.getEmail());
|
||||
}
|
||||
}
|
18
docs-core/src/test/java/com/sismics/util/TestDateUtil.java
Normal file
18
docs-core/src/test/java/com/sismics/util/TestDateUtil.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test of the date utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TestDateUtil {
|
||||
|
||||
@Test
|
||||
public void guessTimezoneCodeTest() throws Exception {
|
||||
Assert.assertEquals("Thu, 04 APR 2013 20:37:27 +10", DateUtil.guessTimezoneOffset("Thu, 04 APR 2013 20:37:27 AEST"));
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.sismics.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test of the resource utils.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TestResourceUtil {
|
||||
|
||||
@Test
|
||||
public void listFilesTest() throws Exception {
|
||||
List<String> fileList = ResourceUtil.list(Test.class, "/junit/framework");
|
||||
Assert.assertTrue(fileList.contains("Test.class"));
|
||||
|
||||
fileList = ResourceUtil.list(Test.class, "/junit/framework/");
|
||||
Assert.assertTrue(fileList.contains("Test.class"));
|
||||
|
||||
fileList = ResourceUtil.list(Test.class, "junit/framework/");
|
||||
Assert.assertTrue(fileList.contains("Test.class"));
|
||||
|
||||
fileList = ResourceUtil.list(Test.class, "junit/framework/");
|
||||
Assert.assertTrue(fileList.contains("Test.class"));
|
||||
}
|
||||
}
|
10
docs-core/src/test/resources/hibernate.properties
Normal file
10
docs-core/src/test/resources/hibernate.properties
Normal file
@ -0,0 +1,10 @@
|
||||
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
|
||||
hibernate.connection.url=jdbc:hsqldb:mem:dùs
|
||||
hibernate.connection.username=sa
|
||||
hibernate.connection.password=
|
||||
hibernate.hbm2ddl.auto=none
|
||||
hibernate.dialect=org.hibernate.dialect.HSQLDialect
|
||||
hibernate.show_sql=true
|
||||
hibernate.format_sql=false
|
||||
hibernate.max_fetch_depth=5
|
||||
hibernate.cache.use_second_level_cache=false
|
8
docs-core/src/test/resources/log4j.properties
Normal file
8
docs-core/src/test/resources/log4j.properties
Normal file
@ -0,0 +1,8 @@
|
||||
log4j.rootCategory=DEBUG, CONSOLE, MEMORY
|
||||
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n
|
||||
log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender
|
||||
log4j.appender.MEMORY.size=1000
|
||||
|
||||
log4j.logger.com.sismics=DEBUG
|
453
docs-parent/pom.xml
Normal file
453
docs-parent/pom.xml
Normal file
@ -0,0 +1,453 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>Docs Parent</name>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.6</maven.compiler.source>
|
||||
<maven.compiler.target>1.6</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- Dependencies version (external) -->
|
||||
<org.apache.commons.commons-compress.version>1.5</org.apache.commons.commons-compress.version>
|
||||
<commons-lang.commons-lang.version>2.6</commons-lang.commons-lang.version>
|
||||
<commons-io.commons-io.version>2.1</commons-io.commons-io.version>
|
||||
<com.google.guava.guava.version>14.0</com.google.guava.guava.version>
|
||||
<log4j.log4j.version>1.2.16</log4j.log4j.version>
|
||||
<org.slf4j.version>1.6.4</org.slf4j.version>
|
||||
<org.slf4j.jcl-over-slf4j.version>1.6.6</org.slf4j.jcl-over-slf4j.version>
|
||||
<junit.junit.version>4.7</junit.junit.version>
|
||||
<org.hsqldb.hsqldb.version>2.2.9</org.hsqldb.hsqldb.version>
|
||||
<com.sun.jersey.version>1.17</com.sun.jersey.version>
|
||||
<org.mindrot.jbcrypt>0.3m</org.mindrot.jbcrypt>
|
||||
<org.subethamail.subethasmtp.version>3.1.6</org.subethamail.subethasmtp.version>
|
||||
<org.subethamail.subethasmtp-wiser.version>1.2</org.subethamail.subethasmtp-wiser.version>
|
||||
<org.codehaus.jettison.jettison.version>1.1</org.codehaus.jettison.jettison.version>
|
||||
<org.ccil.cowan.tagsoup.tagsoup.version>1.2.1</org.ccil.cowan.tagsoup.tagsoup.version>
|
||||
<com.googlecode.owasp-java-html-sanitizer.owasp-java-html-sanitizer.version>r156</com.googlecode.owasp-java-html-sanitizer.owasp-java-html-sanitizer.version>
|
||||
<org.apache.lucene.version>4.2.0</org.apache.lucene.version>
|
||||
<jgoodies.forms.version>1.0.5</jgoodies.forms.version>
|
||||
<org.bitlet.weupnp.version>0.1.2</org.bitlet.weupnp.version>
|
||||
|
||||
<com.sun.grizzly.version>1.9.18-m</com.sun.grizzly.version>
|
||||
<org.hibernate.hibernate.version>4.1.0.Final</org.hibernate.hibernate.version>
|
||||
<commons-dbcp.version>1.4</commons-dbcp.version>
|
||||
<joda-time.joda-time.version>2.2</joda-time.joda-time.version>
|
||||
<org.codehaus.jackson.jackson.version>1.7.1</org.codehaus.jackson.jackson.version>
|
||||
|
||||
<org.eclipse.jetty.jetty-server.version>8.1.10.v20130312</org.eclipse.jetty.jetty-server.version>
|
||||
<org.eclipse.jetty.jetty-webapp.version>8.1.10.v20130312</org.eclipse.jetty.jetty-webapp.version>
|
||||
<org.eclipse.jetty.jetty-servlet.version>8.1.10.v20130312</org.eclipse.jetty.jetty-servlet.version>
|
||||
<org.mortbay.jetty.servlet-api.version>3.0.20100224</org.mortbay.jetty.servlet-api.version>
|
||||
|
||||
<!-- Plugins version -->
|
||||
<org.apache.maven.plugins.maven-antrun-plugin.version>1.7</org.apache.maven.plugins.maven-antrun-plugin.version>
|
||||
<org.apache.maven.plugins.maven-dependency-plugin.version>2.7</org.apache.maven.plugins.maven-dependency-plugin.version>
|
||||
<org.apache.maven.plugins.maven-eclipse-plugin.version>2.8</org.apache.maven.plugins.maven-eclipse-plugin.version>
|
||||
<org.apache.maven.plugins.maven-jar-plugin.version>2.4</org.apache.maven.plugins.maven-jar-plugin.version>
|
||||
<org.apache.maven.plugins.maven-release-plugin.version>2.4.1</org.apache.maven.plugins.maven-release-plugin.version>
|
||||
<org.apache.maven.plugins.maven-resources-plugin.version>2.6</org.apache.maven.plugins.maven-resources-plugin.version>
|
||||
<org.apache.maven.plugins.maven-war-plugin.version>2.2</org.apache.maven.plugins.maven-war-plugin.version>
|
||||
<org.codehaus.cargo.cargo-maven2-plugin.version>1.2.0</org.codehaus.cargo.cargo-maven2-plugin.version>
|
||||
<org.codehaus.mojo.rpm-maven-plugin.version>2.1-alpha-2</org.codehaus.mojo.rpm-maven-plugin.version>
|
||||
<org.codehaus.mojo.nsis-maven-plugin.version>1.0-SNAPSHOT</org.codehaus.mojo.nsis-maven-plugin.version>
|
||||
<org.codehaus.mojo.osxappbundle-maven-plugin.version>1.0-alpha-2</org.codehaus.mojo.osxappbundle-maven-plugin.version>
|
||||
<org.mortbay.jetty.jetty-maven-plugin.version>8.1.2.v20120308</org.mortbay.jetty.jetty-maven-plugin.version>
|
||||
<org.vafer.jdeb.version>1.0.1</org.vafer.jdeb.version>
|
||||
<com.samaxes.maven.minify-maven-plugin.version>1.7</com.samaxes.maven.minify-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:https://github.com/sismics/docs.git</connection>
|
||||
<developerConnection>scm:git:https://github.com/docs/docs.git</developerConnection>
|
||||
<url>scm:git:https://github.com/sismics/docs.git</url>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-antrun-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-dependency-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-eclipse-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-jar-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-release-plugin.version}</version>
|
||||
<configuration>
|
||||
<tagNameFormat>@{project.version}</tagNameFormat>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-resources-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>${org.apache.maven.plugins.maven-war-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.cargo</groupId>
|
||||
<artifactId>cargo-maven2-plugin</artifactId>
|
||||
<version>${org.codehaus.cargo.cargo-maven2-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>${org.mortbay.jetty.jetty-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.samaxes.maven</groupId>
|
||||
<artifactId>minify-maven-plugin</artifactId>
|
||||
<version>${com.samaxes.maven.minify-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.vafer</groupId>
|
||||
<artifactId>jdeb</artifactId>
|
||||
<version>${org.vafer.jdeb.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>rpm-maven-plugin</artifactId>
|
||||
<version>${org.codehaus.mojo.rpm-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>nsis-maven-plugin</artifactId>
|
||||
<version>${org.codehaus.mojo.nsis-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>osxappbundle-maven-plugin</artifactId>
|
||||
<version>${org.codehaus.mojo.osxappbundle-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<modules>
|
||||
<module>../docs-core</module>
|
||||
<module>../docs-web-common</module>
|
||||
<module>../docs-web</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web-common</artifactId>
|
||||
<type>test-jar</type>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${org.eclipse.jetty.jetty-server.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${org.eclipse.jetty.jetty-webapp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${org.eclipse.jetty.jetty-servlet.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>${org.mortbay.jetty.servlet-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>${org.apache.commons.commons-compress.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commons-lang.commons-lang.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons-io.commons-io.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${com.google.guava.guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<version>${org.codehaus.jackson.jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<version>${org.codehaus.jackson.jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j.log4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${org.slf4j.jcl-over-slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.junit.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mindrot</groupId>
|
||||
<artifactId>jbcrypt</artifactId>
|
||||
<version>${org.mindrot.jbcrypt}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
<version>${com.sun.jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-bundle</artifactId>
|
||||
<version>${com.sun.jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
<version>${com.sun.jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
<version>${com.sun.jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.grizzly</groupId>
|
||||
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||
<version>${com.sun.grizzly.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.jersey-test-framework</groupId>
|
||||
<artifactId>jersey-test-framework-grizzly2</artifactId>
|
||||
<version>${com.sun.jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>${org.hsqldb.hsqldb.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>${org.hibernate.hibernate.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>${org.hibernate.hibernate.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
<version>${commons-dbcp.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time.joda-time.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.subethamail</groupId>
|
||||
<artifactId>subethasmtp-wiser</artifactId>
|
||||
<version>${org.subethamail.subethasmtp-wiser.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jettison</groupId>
|
||||
<artifactId>jettison</artifactId>
|
||||
<version>${org.codehaus.jettison.jettison.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.oauth-client</groupId>
|
||||
<artifactId>google-oauth-client</artifactId>
|
||||
<version>${com.google.oauth-client.google-oauth-client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.apis</groupId>
|
||||
<artifactId>google-api-services-oauth2</artifactId>
|
||||
<version>${com.google.apis.google-api-services-oauth2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.http-client</groupId>
|
||||
<artifactId>google-http-client-jackson2</artifactId>
|
||||
<version>${com.google.http-client.google-http-client-jackson2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ccil.cowan.tagsoup</groupId>
|
||||
<artifactId>tagsoup</artifactId>
|
||||
<version>${org.ccil.cowan.tagsoup.tagsoup.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
|
||||
<artifactId>owasp-java-html-sanitizer</artifactId>
|
||||
<version>${com.googlecode.owasp-java-html-sanitizer.owasp-java-html-sanitizer.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-core</artifactId>
|
||||
<version>${org.apache.lucene.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-common</artifactId>
|
||||
<version>${org.apache.lucene.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-queryparser</artifactId>
|
||||
<version>${org.apache.lucene.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-highlighter</artifactId>
|
||||
<version>${org.apache.lucene.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jgoodies</groupId>
|
||||
<artifactId>forms</artifactId>
|
||||
<version>${jgoodies.forms.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bitlet</groupId>
|
||||
<artifactId>weupnp</artifactId>
|
||||
<version>${org.bitlet.weupnp.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<pluginRepositories>
|
||||
<!-- Codehause Snapshots (NSIS) -->
|
||||
<pluginRepository>
|
||||
<id>Codehaus Snapshots</id>
|
||||
<url>http://nexus.codehaus.org/snapshots/</url>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<releases>
|
||||
<enabled>true</enabled> <!-- Workaround for MNG-2974 -->
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
130
docs-web-common/pom.xml
Normal file
130
docs-web-common/pom.xml
Normal file
@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../docs-parent</relativePath>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>docs-web-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Docs Web Commons</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- Dependencies to Docs -->
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies to Jersey -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-bundle</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Other external dependencies -->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.grizzly</groupId>
|
||||
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.jersey-test-framework</groupId>
|
||||
<artifactId>jersey-test-framework-grizzly2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.subethamail</groupId>
|
||||
<artifactId>subethasmtp-wiser</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<!-- Install test jar -->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,54 @@
|
||||
package com.sismics.rest.exception;
|
||||
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Jersey exception encapsulating an error from the client (BAD_REQUEST).
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ClientException extends WebApplicationException {
|
||||
/**
|
||||
* Serial UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(ClientException.class);
|
||||
|
||||
/**
|
||||
* Constructor of ClientException.
|
||||
*
|
||||
* @param type Error type (e.g. AlreadyExistingEmail, ValidationError)
|
||||
* @param message Human readable error message
|
||||
* @param e Readable error message
|
||||
* @throws JSONException
|
||||
*/
|
||||
public ClientException(String type, String message, Exception e) throws JSONException {
|
||||
this(type, message);
|
||||
log.error(type + ": " + message, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of ClientException.
|
||||
*
|
||||
* @param type Error type (e.g. AlreadyExistingEmail, ValidationError)
|
||||
* @param message Human readable error message
|
||||
* @throws JSONException
|
||||
*/
|
||||
public ClientException(String type, String message) throws JSONException {
|
||||
super(Response.status(Status.BAD_REQUEST).entity(new JSONObject()
|
||||
.put("type", type)
|
||||
.put("message", message)).build());
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.sismics.rest.exception;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Unauthorized access to the resource exception.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ForbiddenClientException extends WebApplicationException {
|
||||
/**
|
||||
* Serial UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor of ForbiddenClientException.
|
||||
*
|
||||
* @throws JSONException
|
||||
*/
|
||||
public ForbiddenClientException() throws JSONException {
|
||||
super(Response.status(Status.FORBIDDEN).entity(new JSONObject()
|
||||
.put("type", "ForbiddenError")
|
||||
.put("message", "You don't have access to this resource")).build());
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.sismics.rest.exception;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Jersey exception encapsulating an error from the client (INTERNAL_SERVER_ERROR).
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ServerException extends WebApplicationException {
|
||||
/**
|
||||
* Serial UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(ServerException.class);
|
||||
|
||||
/**
|
||||
* Constructor of ClientException.
|
||||
*
|
||||
* @param type Error type (e.g. DatabaseError)
|
||||
* @param message Human readable error message
|
||||
* @param e Inner exception
|
||||
* @throws JSONException
|
||||
*/
|
||||
public ServerException(String type, String message, Exception e) throws JSONException {
|
||||
this(type, message);
|
||||
log.error(type + ": " + message, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of ClientException.
|
||||
*
|
||||
* @param type Error type (e.g. DatabaseError)
|
||||
* @param message Human readable error message
|
||||
* @throws JSONException
|
||||
*/
|
||||
public ServerException(String type, String message) throws JSONException {
|
||||
super(Response.status(Status.INTERNAL_SERVER_ERROR).entity(new JSONObject()
|
||||
.put("type", type)
|
||||
.put("message", message)).build());
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.sismics.rest.resource;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Generic exception mapper that transforms all unknown exception into ServerError.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Provider
|
||||
public class GenericExceptionMapper implements ExceptionMapper<Exception> {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(GenericExceptionMapper.class);
|
||||
|
||||
@Override
|
||||
public Response toResponse(Exception e) {
|
||||
if (e instanceof WebApplicationException) {
|
||||
return ((WebApplicationException) e).getResponse();
|
||||
}
|
||||
|
||||
log.error("Unknown error", e);
|
||||
|
||||
JSONObject entity = new JSONObject();
|
||||
try {
|
||||
entity.put("type", "UnknownError");
|
||||
entity.put("message", "Unknown server error");
|
||||
} catch (JSONException e2) {
|
||||
log.error("Error building response", e2);
|
||||
}
|
||||
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity(entity)
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.sismics.rest.util;
|
||||
|
||||
import org.codehaus.jettison.json.JSONArray;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
/**
|
||||
* JSON utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class JsonUtil {
|
||||
|
||||
/**
|
||||
* Fix of {@see JsonObject.append()}, which seems to create nested arrays.
|
||||
*
|
||||
* @param o JSON Object
|
||||
* @param key Key containing the array of null
|
||||
* @param value Value to append
|
||||
* @return Updated object
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static JSONObject append(JSONObject o, String key, JSONObject value) throws JSONException {
|
||||
Object prevValue = o.opt(key);
|
||||
if (prevValue == null) {
|
||||
o.put(key, new JSONArray().put(value));
|
||||
} else if (!(prevValue instanceof JSONArray)){
|
||||
throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
|
||||
} else {
|
||||
JSONArray newArray = new JSONArray();
|
||||
JSONArray oldArray = ((JSONArray) prevValue);
|
||||
for (int i = 0; i < oldArray.length(); i++) {
|
||||
newArray.put(oldArray.get(i));
|
||||
}
|
||||
newArray.put(value);
|
||||
o.put(key, newArray);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
package com.sismics.rest.util;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.sismics.docs.core.dao.file.theme.ThemeDao;
|
||||
import com.sismics.docs.core.dao.jpa.LocaleDao;
|
||||
import com.sismics.docs.core.model.jpa.Locale;
|
||||
import com.sismics.rest.exception.ClientException;
|
||||
|
||||
/**
|
||||
* Utility class to validate parameters.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ValidationUtil {
|
||||
private static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+\\..+");
|
||||
|
||||
private static Pattern HTTP_URL_PATTERN = Pattern.compile("https?://.+");
|
||||
|
||||
private static Pattern ALPHANUMERIC_PATTERN = Pattern.compile("[a-zA-Z0-9_]+");
|
||||
|
||||
/**
|
||||
* Checks that the argument is not null.
|
||||
*
|
||||
* @param s Object tu validate
|
||||
* @param name Name of the parameter
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateRequired(Object s, String name) throws JSONException {
|
||||
if (s == null) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a string length.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @param lengthMin Minimum length (or null)
|
||||
* @param lengthMax Maximum length (or null)
|
||||
* @param nullable True if the string can be empty or null
|
||||
* @return String without white spaces
|
||||
* @throws ClientException
|
||||
*/
|
||||
public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax, boolean nullable) throws JSONException {
|
||||
s = StringUtils.strip(s);
|
||||
if (nullable && StringUtils.isEmpty(s)) {
|
||||
return s;
|
||||
}
|
||||
if (s == null) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be set", name));
|
||||
}
|
||||
if (lengthMin != null && s.length() < lengthMin) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be more than {1} characters", name, lengthMin));
|
||||
}
|
||||
if (lengthMax != null && s.length() > lengthMax) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be more than {1} characters", name, lengthMax));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a string length. The string mustn't be empty.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @param lengthMin Minimum length (or null)
|
||||
* @param lengthMax Maximum length (or null)
|
||||
* @return String without white spaces
|
||||
* @throws ClientException
|
||||
*/
|
||||
public static String validateLength(String s, String name, Integer lengthMin, Integer lengthMax) throws JSONException {
|
||||
return validateLength(s, name, lengthMin, lengthMax, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the string is not null and is not only whitespaces.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @return String without white spaces
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String validateStringNotBlank(String s, String name) throws JSONException {
|
||||
return validateLength(s, name, 1, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the string is an email.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateEmail(String s, String name) throws JSONException {
|
||||
if (!EMAIL_PATTERN.matcher(s).matches()) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be an email", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the provided string matches an URL with HTTP or HTTPS scheme.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @return Stripped URL
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static String validateHttpUrl(String s, String name) throws JSONException {
|
||||
s = StringUtils.strip(s);
|
||||
if (!HTTP_URL_PATTERN.matcher(s).matches()) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be an HTTP(s) URL", name));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the string uses only alphanumerical or underscore characters.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static void validateAlphanumeric(String s, String name) throws JSONException {
|
||||
if (!ALPHANUMERIC_PATTERN.matcher(s).matches()) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must have only alphanumeric or underscore characters", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and parses a date.
|
||||
*
|
||||
* @param s String to validate
|
||||
* @param name Name of the parameter
|
||||
* @param nullable True if the string can be empty or null
|
||||
* @return Parsed date
|
||||
* @throws JSONException
|
||||
*/
|
||||
public static Date validateDate(String s, String name, boolean nullable) throws JSONException {
|
||||
if (Strings.isNullOrEmpty(s)) {
|
||||
if (!nullable) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be set", name));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new DateTime(Long.parseLong(s)).toDate();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} must be a date", name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a locale.
|
||||
*
|
||||
* @param localeId String to validate
|
||||
* @param name Name of the parameter
|
||||
* @return String without white spaces
|
||||
* @param nullable True if the string can be empty or null
|
||||
* @throws ClientException
|
||||
*/
|
||||
public static String validateLocale(String localeId, String name, boolean nullable) throws JSONException {
|
||||
localeId = StringUtils.strip(localeId);
|
||||
if (StringUtils.isEmpty(localeId)) {
|
||||
if (!nullable) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} is required", name));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
LocaleDao localeDao = new LocaleDao();
|
||||
Locale locale = localeDao.getById(localeId);
|
||||
if (locale == null) {
|
||||
throw new ClientException("ValidationError", "Locale not found: " + localeId);
|
||||
}
|
||||
return localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a theme.
|
||||
*
|
||||
* @param themeId ID of the theme to validate
|
||||
* @param name Name of the parameter
|
||||
* @return String without white spaces
|
||||
* @param nullable True if the string can be empty or null
|
||||
* @throws ClientException
|
||||
*/
|
||||
public static String validateTheme(String themeId, String name, boolean nullable) throws JSONException {
|
||||
themeId = StringUtils.strip(themeId);
|
||||
if (StringUtils.isEmpty(themeId)) {
|
||||
if (!nullable) {
|
||||
throw new ClientException("ValidationError", MessageFormat.format("{0} is required", name));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
ThemeDao themeDao = new ThemeDao();
|
||||
List<String> themeList = themeDao.findAll();
|
||||
if (!themeList.contains(themeId)) {
|
||||
throw new ClientException("ValidationError", "Theme not found: " + themeId);
|
||||
}
|
||||
return themeId;
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.sismics.security;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
/**
|
||||
* Anonymous principal.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class AnonymousPrincipal implements IPrincipal {
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
|
||||
/**
|
||||
* User locale.
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
/**
|
||||
* User timezone.
|
||||
*/
|
||||
private DateTimeZone dateTimeZone;
|
||||
|
||||
/**
|
||||
* Constructor of AnonymousPrincipal.
|
||||
*/
|
||||
public AnonymousPrincipal() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANONYMOUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnonymous() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of locale.
|
||||
*
|
||||
* @param locale locale
|
||||
*/
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getDateTimeZone() {
|
||||
return dateTimeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of dateTimeZone.
|
||||
*
|
||||
* @param dateTimeZone dateTimeZone
|
||||
*/
|
||||
public void setDateTimeZone(DateTimeZone dateTimeZone) {
|
||||
this.dateTimeZone = dateTimeZone;
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.sismics.security;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
/**
|
||||
* Interface of principals.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public interface IPrincipal extends Principal {
|
||||
/**
|
||||
* Checks if the principal is anonymous.
|
||||
*
|
||||
* @return True if the principal is anonymous.
|
||||
*/
|
||||
boolean isAnonymous();
|
||||
|
||||
/**
|
||||
* Returns the ID of the connected user, or null if the user is anonymous
|
||||
*
|
||||
* @return ID of the connected user
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Returns the locale of the principal.
|
||||
*
|
||||
* @return Locale of the principal
|
||||
*/
|
||||
public Locale getLocale();
|
||||
|
||||
/**
|
||||
* Returns the timezone of the principal.
|
||||
*
|
||||
* @return Timezone of the principal
|
||||
*/
|
||||
public DateTimeZone getDateTimeZone();
|
||||
|
||||
/**
|
||||
* Returns the email of the principal.
|
||||
*
|
||||
* @return Email of the principal
|
||||
*/
|
||||
public String getEmail();
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
package com.sismics.security;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
/**
|
||||
* Authenticated users principal.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class UserPrincipal implements IPrincipal {
|
||||
/**
|
||||
* ID of the user.
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Username of the user.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Locale of the principal.
|
||||
*/
|
||||
private Locale locale;
|
||||
|
||||
/**
|
||||
* Timezone of the principal.
|
||||
*/
|
||||
private DateTimeZone dateTimeZone;
|
||||
|
||||
/**
|
||||
* Email of the principal.
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* User base functions.
|
||||
*/
|
||||
private Set<String> baseFunctionSet;
|
||||
|
||||
/**
|
||||
* Constructor of UserPrincipal.
|
||||
*
|
||||
* @param id ID of the user
|
||||
* @param name Usrename of the user
|
||||
*/
|
||||
public UserPrincipal(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnonymous() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of id.
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of name.
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of locale.
|
||||
*
|
||||
* @param locale locale
|
||||
*/
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTimeZone getDateTimeZone() {
|
||||
return dateTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of dateTimeZone.
|
||||
*
|
||||
* @param dateTimeZone dateTimeZone
|
||||
*/
|
||||
public void setDateTimeZone(DateTimeZone dateTimeZone) {
|
||||
this.dateTimeZone = dateTimeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of email.
|
||||
*
|
||||
* @param email email
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter of baseFunctionSet.
|
||||
*
|
||||
* @return baseFunctionSet
|
||||
*/
|
||||
public Set<String> getBaseFunctionSet() {
|
||||
return baseFunctionSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter of baseFunctionSet.
|
||||
*
|
||||
* @param baseFunctionSet baseFunctionSet
|
||||
*/
|
||||
public void setBaseFunctionSet(Set<String> baseFunctionSet) {
|
||||
this.baseFunctionSet = baseFunctionSet;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package com.sismics.util.filter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.PatternLayout;
|
||||
import org.apache.log4j.RollingFileAppender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.model.context.AppContext;
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
import com.sismics.docs.core.util.TransactionUtil;
|
||||
import com.sismics.util.EnvironmentUtil;
|
||||
import com.sismics.util.context.ThreadLocalContext;
|
||||
import com.sismics.util.jpa.EMF;
|
||||
|
||||
/**
|
||||
* Filter used to process a couple things in the request context.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class RequestContextFilter implements Filter {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(RequestContextFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// Force the locale in order to not depend on the execution environment
|
||||
Locale.setDefault(new Locale(Constants.DEFAULT_LOCALE_ID));
|
||||
|
||||
// Injects the webapp root
|
||||
String webappRoot = filterConfig.getServletContext().getRealPath("/");
|
||||
EnvironmentUtil.setWebappRoot(webappRoot);
|
||||
|
||||
// Initialize the app directory
|
||||
File baseDataDirectory = null;
|
||||
try {
|
||||
baseDataDirectory = DirectoryUtil.getBaseDataDirectory();
|
||||
} catch (Exception e) {
|
||||
log.error("Error initializing base data directory", e);
|
||||
}
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(MessageFormat.format("Using base data directory: {0}", baseDataDirectory.toString()));
|
||||
}
|
||||
|
||||
// Initialize file logger
|
||||
RollingFileAppender fileAppender = new RollingFileAppender();
|
||||
fileAppender.setName("FILE");
|
||||
fileAppender.setFile(DirectoryUtil.getLogDirectory() + File.separator + "docs.log");
|
||||
fileAppender.setLayout(new PatternLayout("%d{DATE} %p %l %m %n"));
|
||||
fileAppender.setThreshold(Level.INFO);
|
||||
fileAppender.setAppend(true);
|
||||
fileAppender.setMaxFileSize("5MB");
|
||||
fileAppender.setMaxBackupIndex(5);
|
||||
fileAppender.activateOptions();
|
||||
org.apache.log4j.Logger.getRootLogger().addAppender(fileAppender);
|
||||
|
||||
// Initialize the application context
|
||||
TransactionUtil.handle(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
AppContext.getInstance();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
EntityManager em = null;
|
||||
|
||||
try {
|
||||
em = EMF.get().createEntityManager();
|
||||
} catch (Exception e) {
|
||||
throw new ServletException("Cannot create entity manager", e);
|
||||
}
|
||||
ThreadLocalContext context = ThreadLocalContext.get();
|
||||
context.setEntityManager(em);
|
||||
EntityTransaction tx = em.getTransaction();
|
||||
tx.begin();
|
||||
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (Exception e) {
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
log.error("An exception occured, rolling back current transaction", e);
|
||||
|
||||
// If an unprocessed error comes up from the application layers (Jersey...), rollback the transaction (should not happen)
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception ce) {
|
||||
log.error("Error closing entity manager", ce);
|
||||
}
|
||||
}
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
||||
ThreadLocalContext.cleanup();
|
||||
|
||||
// No error processing the request : commit / rollback the current transaction depending on the HTTP code
|
||||
if (em.isOpen()) {
|
||||
if (em.getTransaction() != null && em.getTransaction().isActive()) {
|
||||
HttpServletResponse r = (HttpServletResponse) response;
|
||||
int statusClass = r.getStatus() / 100;
|
||||
if (statusClass == 2 || statusClass == 3) {
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
} catch (Exception e) {
|
||||
log.error("Error during commit", e);
|
||||
r.sendError(500);
|
||||
}
|
||||
} else {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
try {
|
||||
em.close();
|
||||
} catch (Exception e) {
|
||||
log.error("Error closing entity manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
package com.sismics.util.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.sismics.docs.core.constant.Constants;
|
||||
import com.sismics.docs.core.dao.jpa.AuthenticationTokenDao;
|
||||
import com.sismics.docs.core.dao.jpa.RoleBaseFunctionDao;
|
||||
import com.sismics.docs.core.dao.jpa.UserDao;
|
||||
import com.sismics.docs.core.model.jpa.AuthenticationToken;
|
||||
import com.sismics.docs.core.model.jpa.User;
|
||||
import com.sismics.security.AnonymousPrincipal;
|
||||
import com.sismics.security.UserPrincipal;
|
||||
import com.sismics.util.LocaleUtil;
|
||||
|
||||
/**
|
||||
* This filter is used to authenticate the user having an active session via an authentication token stored in database.
|
||||
* The filter extracts the authentication token stored in a cookie.
|
||||
* If the ocokie exists and the token is valid, the filter injects a UserPrincipal into a request attribute.
|
||||
* If not, the user is anonymous, and the filter injects a AnonymousPrincipal into the request attribute.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TokenBasedSecurityFilter implements Filter {
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(TokenBasedSecurityFilter.class);
|
||||
|
||||
/**
|
||||
* Name of the cookie used to store the authentication token.
|
||||
*/
|
||||
public static final String COOKIE_NAME = "auth_token";
|
||||
|
||||
/**
|
||||
* Name of the attribute containing the principal.
|
||||
*/
|
||||
public static final String PRINCIPAL_ATTRIBUTE = "principal";
|
||||
|
||||
/**
|
||||
* Lifetime of the authentication token in seconds, since login.
|
||||
*/
|
||||
public static final int TOKEN_LONG_LIFETIME = 3600 * 24 * 365 * 20;
|
||||
|
||||
/**
|
||||
* Lifetime of the authentication token in seconds, since last connection.
|
||||
*/
|
||||
public static final int TOKEN_SESSION_LIFETIME = 3600 * 24;
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// NOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
|
||||
// Get the value of the client authentication token
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
String authToken = null;
|
||||
if (request.getCookies() != null) {
|
||||
for (Cookie cookie : request.getCookies()) {
|
||||
if (COOKIE_NAME.equals(cookie.getName())) {
|
||||
authToken = cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the corresponding server token
|
||||
AuthenticationTokenDao authenticationTokenDao = new AuthenticationTokenDao();
|
||||
AuthenticationToken authenticationToken = null;
|
||||
if (authToken != null) {
|
||||
authenticationToken = authenticationTokenDao.get(authToken);
|
||||
}
|
||||
|
||||
if (authenticationToken == null) {
|
||||
injectAnonymousUser(request);
|
||||
} else {
|
||||
// Check if the token is still valid
|
||||
if (isTokenExpired(authenticationToken)) {
|
||||
try {
|
||||
injectAnonymousUser(request);
|
||||
|
||||
// Destroy the expired token
|
||||
authenticationTokenDao.delete(authToken);
|
||||
} catch (Exception e) {
|
||||
if (log.isErrorEnabled()) {
|
||||
log.error(MessageFormat.format("Error deleting authentication token {0} ", authToken), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if the user is still valid
|
||||
UserDao userDao = new UserDao();
|
||||
User user = userDao.getById(authenticationToken.getUserId());
|
||||
if (user != null && user.getDeleteDate() == null) {
|
||||
injectAuthenticatedUser(request, user);
|
||||
|
||||
// Update the last connection date
|
||||
authenticationTokenDao.updateLastConnectionDate(authenticationToken.getId());
|
||||
} else {
|
||||
injectAnonymousUser(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the token is expired.
|
||||
*
|
||||
* @param authenticationToken Authentication token
|
||||
* @return Token expired
|
||||
*/
|
||||
private boolean isTokenExpired(AuthenticationToken authenticationToken) {
|
||||
final long now = new Date().getTime();
|
||||
final long creationDate = authenticationToken.getCreationDate().getTime();
|
||||
if (authenticationToken.isLongLasted()) {
|
||||
return now >= creationDate + ((long) TOKEN_LONG_LIFETIME) * 1000L;
|
||||
} else {
|
||||
long date = authenticationToken.getLastConnectionDate() != null ?
|
||||
authenticationToken.getLastConnectionDate().getTime() : creationDate;
|
||||
return now >= date + ((long) TOKEN_SESSION_LIFETIME) * 1000L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject an authenticated user into the request attributes.
|
||||
*
|
||||
* @param request HTTP request
|
||||
* @param user User to inject
|
||||
*/
|
||||
private void injectAuthenticatedUser(HttpServletRequest request, User user) {
|
||||
UserPrincipal userPrincipal = new UserPrincipal(user.getId(), user.getUsername());
|
||||
|
||||
// Add locale
|
||||
Locale locale = LocaleUtil.getLocale(user.getLocaleId());
|
||||
userPrincipal.setLocale(locale);
|
||||
|
||||
// Add base functions
|
||||
RoleBaseFunctionDao userBaseFuction = new RoleBaseFunctionDao();
|
||||
Set<String> baseFunctionSet = userBaseFuction.findByRoleId(user.getRoleId());
|
||||
userPrincipal.setBaseFunctionSet(baseFunctionSet);
|
||||
|
||||
request.setAttribute(PRINCIPAL_ATTRIBUTE, userPrincipal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject an anonymous user into the request attributes.
|
||||
*
|
||||
* @param request HTTP request
|
||||
*/
|
||||
private void injectAnonymousUser(HttpServletRequest request) {
|
||||
AnonymousPrincipal anonymousPrincipal = new AnonymousPrincipal();
|
||||
anonymousPrincipal.setLocale(request.getLocale());
|
||||
anonymousPrincipal.setDateTimeZone(DateTimeZone.forID(Constants.DEFAULT_TIMEZONE_ID));
|
||||
|
||||
request.setAttribute(PRINCIPAL_ATTRIBUTE, anonymousPrincipal);
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package com.sismics.docs.rest;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.List;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
import org.glassfish.grizzly.http.server.HttpServer;
|
||||
import org.glassfish.grizzly.http.server.StaticHttpHandler;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.subethamail.wiser.Wiser;
|
||||
import org.subethamail.wiser.WiserMessage;
|
||||
|
||||
import com.sismics.docs.rest.descriptor.JerseyTestWebAppDescriptorFactory;
|
||||
import com.sismics.docs.rest.util.ClientUtil;
|
||||
import com.sun.jersey.test.framework.JerseyTest;
|
||||
|
||||
/**
|
||||
* Base class of integration tests with Jersey.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public abstract class BaseJerseyTest extends JerseyTest {
|
||||
/**
|
||||
* Test email server.
|
||||
*/
|
||||
protected Wiser wiser;
|
||||
|
||||
/**
|
||||
* Test HTTP server.
|
||||
*/
|
||||
HttpServer httpServer;
|
||||
|
||||
/**
|
||||
* Utility class for the REST client.
|
||||
*/
|
||||
protected ClientUtil clientUtil;
|
||||
|
||||
/**
|
||||
* Constructor of BaseJerseyTest.
|
||||
*/
|
||||
public BaseJerseyTest() {
|
||||
super(JerseyTestWebAppDescriptorFactory.build());
|
||||
this.clientUtil = new ClientUtil(resource());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
wiser = new Wiser();
|
||||
wiser.setPort(2500);
|
||||
wiser.start();
|
||||
|
||||
String httpRoot = URLDecoder.decode(new File(getClass().getResource("/").getFile()).getAbsolutePath(), "utf-8");
|
||||
httpServer = HttpServer.createSimpleServer(httpRoot, "localhost", 9997);
|
||||
// Disable file cache to fix https://java.net/jira/browse/GRIZZLY-1350
|
||||
((StaticHttpHandler) httpServer.getServerConfiguration().getHttpHandlers().keySet().iterator().next()).setFileCacheEnabled(false);
|
||||
httpServer.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
wiser.stop();
|
||||
httpServer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts an email from the queue and consumes the email.
|
||||
*
|
||||
* @return Text of the email
|
||||
* @throws MessagingException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected String popEmail() throws MessagingException, IOException {
|
||||
List<WiserMessage> wiserMessageList = wiser.getMessages();
|
||||
if (wiserMessageList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
WiserMessage wiserMessage = wiserMessageList.get(wiserMessageList.size() - 1);
|
||||
wiserMessageList.remove(wiserMessageList.size() - 1);
|
||||
MimeMessage message = wiserMessage.getMimeMessage();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
message.writeTo(os);
|
||||
String body = os.toString();
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a string to "quoted-printable" characters to compare with the contents of an email.
|
||||
*
|
||||
* @param input String to encode
|
||||
* @return Encoded string
|
||||
* @throws MessagingException
|
||||
* @throws IOException
|
||||
*/
|
||||
protected String encodeQuotedPrintable(String input) throws MessagingException, IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
OutputStream os = MimeUtility.encode(baos, "quoted-printable");
|
||||
os.write(input.getBytes());
|
||||
os.close();
|
||||
return baos.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.sismics.docs.rest.descriptor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.sismics.util.filter.RequestContextFilter;
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
import com.sun.jersey.test.framework.WebAppDescriptor;
|
||||
|
||||
/**
|
||||
* Jersey tests Webapp descriptor.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class JerseyTestWebAppDescriptorFactory {
|
||||
private static String basePath = new File("src/main/webapp").getAbsolutePath();
|
||||
|
||||
/**
|
||||
* Constructs a new descriptor.
|
||||
*
|
||||
* @return Descriptor
|
||||
*/
|
||||
public static WebAppDescriptor build() {
|
||||
// Target the base path to the Webapp resources
|
||||
System.setProperty("user.dir", basePath);
|
||||
System.setProperty("test", "true");
|
||||
|
||||
return new WebAppDescriptor.Builder("com.sismics.docs.rest.resource")
|
||||
.contextPath("docs")
|
||||
.addFilter(RequestContextFilter.class, "requestContextFilter")
|
||||
.addFilter(TokenBasedSecurityFilter.class, "tokenBasedSecurityFilter")
|
||||
.initParam("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.LoggingFilter")
|
||||
.initParam("com.sun.jersey.spi.container.ContainerResponseFilters", "com.sun.jersey.api.container.filter.LoggingFilter")
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.sismics.docs.rest.filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.core.Cookie;
|
||||
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
import com.sun.jersey.api.client.ClientHandlerException;
|
||||
import com.sun.jersey.api.client.ClientRequest;
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.api.client.filter.ClientFilter;
|
||||
|
||||
/**
|
||||
* Filter to add the authentication token into a cookie.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class CookieAuthenticationFilter extends ClientFilter {
|
||||
private String authToken;
|
||||
|
||||
public CookieAuthenticationFilter(String authToken) {
|
||||
this.authToken = authToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientResponse handle(ClientRequest request) throws ClientHandlerException {
|
||||
Cookie cookie = new Cookie(TokenBasedSecurityFilter.COOKIE_NAME, authToken);
|
||||
List<Object> cookieList = new ArrayList<Object>();
|
||||
cookieList.add(cookie);
|
||||
if (authToken != null) {
|
||||
request.getHeaders().put("Cookie", cookieList);
|
||||
}
|
||||
ClientResponse response = getNext().handle(request);
|
||||
if (response.getCookies() != null) {
|
||||
cookieList.addAll(response.getCookies());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package com.sismics.docs.rest.util;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.NewCookie;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import com.sismics.docs.rest.filter.CookieAuthenticationFilter;
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
import com.sun.jersey.api.client.ClientResponse;
|
||||
import com.sun.jersey.api.client.ClientResponse.Status;
|
||||
import com.sun.jersey.api.client.WebResource;
|
||||
import com.sun.jersey.core.util.MultivaluedMapImpl;
|
||||
|
||||
/**
|
||||
* REST client utilities.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class ClientUtil {
|
||||
private WebResource resource;
|
||||
|
||||
/**
|
||||
* Constructor of ClientUtil.
|
||||
*
|
||||
* @param webResource Resource corresponding to the base URI of REST resources.
|
||||
*/
|
||||
public ClientUtil(WebResource resource) {
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user.
|
||||
*
|
||||
* @param username Username
|
||||
*/
|
||||
public void createUser(String username) {
|
||||
// Login admin to create the user
|
||||
String adminAuthenticationToken = login("admin", "admin", false);
|
||||
|
||||
// Create the user
|
||||
WebResource userResource = resource.path("/user");
|
||||
userResource.addFilter(new CookieAuthenticationFilter(adminAuthenticationToken));
|
||||
MultivaluedMap<String, String> postParams = new MultivaluedMapImpl();
|
||||
postParams.putSingle("username", username);
|
||||
postParams.putSingle("email", username + "@docs.com");
|
||||
postParams.putSingle("password", "12345678");
|
||||
postParams.putSingle("time_zone", "Asia/Tokyo");
|
||||
ClientResponse response = userResource.put(ClientResponse.class, postParams);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
|
||||
// Logout admin
|
||||
logout(adminAuthenticationToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a user to the application.
|
||||
*
|
||||
* @param username Username
|
||||
* @param password Password
|
||||
* @param remember Remember user
|
||||
* @return Authentication token
|
||||
*/
|
||||
public String login(String username, String password, Boolean remember) {
|
||||
WebResource userResource = resource.path("/user/login");
|
||||
MultivaluedMap<String, String> postParams = new MultivaluedMapImpl();
|
||||
postParams.putSingle("username", username);
|
||||
postParams.putSingle("password", password);
|
||||
postParams.putSingle("remember", remember.toString());
|
||||
ClientResponse response = userResource.post(ClientResponse.class, postParams);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
|
||||
return getAuthenticationCookie(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a user to the application.
|
||||
*
|
||||
* @param username Username
|
||||
* @return Authentication token
|
||||
*/
|
||||
public String login(String username) {
|
||||
return login(username, "12345678", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects a user from the application.
|
||||
*
|
||||
* @param authenticationToken Authentication token
|
||||
*/
|
||||
public void logout(String authenticationToken) {
|
||||
WebResource userResource = resource.path("/user/logout");
|
||||
userResource.addFilter(new CookieAuthenticationFilter(authenticationToken));
|
||||
ClientResponse response = userResource.post(ClientResponse.class);
|
||||
Assert.assertEquals(Status.OK, Status.fromStatusCode(response.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the authentication token of the response.
|
||||
*
|
||||
* @param response Response
|
||||
* @return Authentication token
|
||||
*/
|
||||
public String getAuthenticationCookie(ClientResponse response) {
|
||||
String authToken = null;
|
||||
for (NewCookie cookie : response.getCookies()) {
|
||||
if (TokenBasedSecurityFilter.COOKIE_NAME.equals(cookie.getName())) {
|
||||
authToken = cookie.getValue();
|
||||
}
|
||||
}
|
||||
return authToken;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.sismics.docs.rest.util;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.sismics.rest.exception.ClientException;
|
||||
import com.sismics.rest.util.ValidationUtil;
|
||||
|
||||
/**
|
||||
* Test the validations.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public class TestValidationUtil {
|
||||
@Test
|
||||
public void testValidateHttpUrlFail() throws Exception {
|
||||
ValidationUtil.validateHttpUrl("http://www.google.com", "url");
|
||||
ValidationUtil.validateHttpUrl("https://www.google.com", "url");
|
||||
ValidationUtil.validateHttpUrl(" https://www.google.com ", "url");
|
||||
try {
|
||||
ValidationUtil.validateHttpUrl("ftp://www.google.com", "url");
|
||||
Assert.fail();
|
||||
} catch (ClientException e) {
|
||||
// NOP
|
||||
}
|
||||
try {
|
||||
ValidationUtil.validateHttpUrl("http://", "url");
|
||||
Assert.fail();
|
||||
} catch (ClientException e) {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
325
docs-web/pom.xml
Normal file
325
docs-web/pom.xml
Normal file
@ -0,0 +1,325 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<parent>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<relativePath>../docs-parent</relativePath>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>docs-web</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Docs Web</name>
|
||||
|
||||
<dependencies>
|
||||
<!-- Dependencies to Docs -->
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies to Jersey -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-bundle</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Other external dependencies -->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web-common</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.grizzly</groupId>
|
||||
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.jersey-test-framework</groupId>
|
||||
<artifactId>jersey-test-framework-grizzly2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.subethamail</groupId>
|
||||
<artifactId>subethasmtp-wiser</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<systemProperty>
|
||||
<name>webapp.root</name>
|
||||
<value>${basedir}/src/main/webapp</value>
|
||||
</systemProperty>
|
||||
</systemProperties>
|
||||
<scanIntervalSeconds>0</scanIntervalSeconds>
|
||||
<webAppConfig>
|
||||
<contextPath>/docs-web</contextPath>
|
||||
<extraClasspath>target/classes;../docs-core/target/classes</extraClasspath>
|
||||
<overrideDescriptor>src/dev/main/webapp/web-override.xml</overrideDescriptor>
|
||||
</webAppConfig>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Cargo Plugin -->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.cargo</groupId>
|
||||
<artifactId>cargo-maven2-plugin</artifactId>
|
||||
<configuration>
|
||||
<container>
|
||||
<containerId>jetty8x</containerId>
|
||||
<type>remote</type>
|
||||
</container>
|
||||
|
||||
<deployer>
|
||||
<type>remote</type>
|
||||
</deployer>
|
||||
|
||||
<deployables>
|
||||
<deployable>
|
||||
<groupId>com.sismics.docs</groupId>
|
||||
<artifactId>docs-web</artifactId>
|
||||
<type>war</type>
|
||||
<properties>
|
||||
<context>/docs</context>
|
||||
</properties>
|
||||
<pingURL>http://localhost:8080/docs/index.html</pingURL>
|
||||
</deployable>
|
||||
</deployables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>com.samaxes.maven</groupId>
|
||||
<artifactId>
|
||||
minify-maven-plugin
|
||||
</artifactId>
|
||||
<versionRange>[1.5,)</versionRange>
|
||||
<goals>
|
||||
<goal>minify</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- Development profile (active by default) -->
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
<property>
|
||||
<name>env</name>
|
||||
<value>dev</value>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/dev/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/config.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/dev/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/config.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<scanIntervalSeconds>0</scanIntervalSeconds>
|
||||
<webAppConfig>
|
||||
<contextPath>/docs-web</contextPath>
|
||||
<extraClasspath>target/classes;../docs-core/target/classes</extraClasspath>
|
||||
<overrideDescriptor>src/dev/main/webapp/web-override.xml</overrideDescriptor>
|
||||
</webAppConfig>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Production profile -->
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env</name>
|
||||
<value>prod</value>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/prod/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/config.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/prod/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/config.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
<!-- Generation of the war -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<warSourceExcludes>
|
||||
sismicsdocs/**,
|
||||
</warSourceExcludes>
|
||||
<webXml>src\main\webapp\WEB-INF\web.xml</webXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Hosted version profile -->
|
||||
<profile>
|
||||
<id>hosted</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>env</name>
|
||||
<value>hosted</value>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/hosted/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
16
docs-web/src/dev/main/webapp/web-override.xml
Normal file
16
docs-web/src/dev/main/webapp/web-override.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app id="docs"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
|
||||
<!-- Override init parameter to avoid nasty file locking issue on windows. -->
|
||||
<servlet>
|
||||
<servlet-name>default</servlet-name>
|
||||
<init-param>
|
||||
<param-name>useFileMappedBuffer</param-name>
|
||||
<param-value>false</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
</web-app>
|
3
docs-web/src/dev/resources/config.properties
Normal file
3
docs-web/src/dev/resources/config.properties
Normal file
@ -0,0 +1,3 @@
|
||||
api.current_version=${project.version}
|
||||
api.min_version=1.0
|
||||
db.version=1
|
10
docs-web/src/dev/resources/hibernate.properties
Normal file
10
docs-web/src/dev/resources/hibernate.properties
Normal file
@ -0,0 +1,10 @@
|
||||
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
|
||||
hibernate.connection.url=jdbc:hsqldb:mem:docs
|
||||
hibernate.connection.username=sa
|
||||
hibernate.connection.password=
|
||||
hibernate.hbm2ddl.auto=none
|
||||
hibernate.dialect=org.hibernate.dialect.HSQLDialect
|
||||
hibernate.show_sql=false
|
||||
hibernate.format_sql=false
|
||||
hibernate.max_fetch_depth=5
|
||||
hibernate.cache.use_second_level_cache=false
|
8
docs-web/src/dev/resources/log4j.properties
Normal file
8
docs-web/src/dev/resources/log4j.properties
Normal file
@ -0,0 +1,8 @@
|
||||
log4j.rootCategory=WARN, CONSOLE, MEMORY
|
||||
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.CONSOLE.layout.ConversionPattern=%d{DATE} %p %l %m %n
|
||||
log4j.appender.MEMORY=com.sismics.util.log4j.MemoryAppender
|
||||
log4j.appender.MEMORY.size=1000
|
||||
|
||||
log4j.logger.com.sismics=DEBUG
|
@ -0,0 +1,14 @@
|
||||
package com.sismics.docs.rest.constant;
|
||||
|
||||
/**
|
||||
* Base functions.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public enum BaseFunction {
|
||||
|
||||
/**
|
||||
* Allows the user to use the admin fonctions.
|
||||
*/
|
||||
ADMIN,
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package com.sismics.docs.rest.resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
import com.sismics.docs.core.util.ConfigUtil;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedLists;
|
||||
import com.sismics.docs.rest.constant.BaseFunction;
|
||||
import com.sismics.rest.exception.ForbiddenClientException;
|
||||
import com.sismics.rest.exception.ServerException;
|
||||
import com.sismics.util.log4j.LogCriteria;
|
||||
import com.sismics.util.log4j.LogEntry;
|
||||
import com.sismics.util.log4j.MemoryAppender;
|
||||
|
||||
/**
|
||||
* General app REST resource.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Path("/app")
|
||||
public class AppResource extends BaseResource {
|
||||
/**
|
||||
* Return the information about the application.
|
||||
*
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response version() throws JSONException {
|
||||
ResourceBundle configBundle = ConfigUtil.getConfigBundle();
|
||||
String currentVersion = configBundle.getString("api.current_version");
|
||||
String minVersion = configBundle.getString("api.min_version");
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("current_version", currentVersion.replace("-SNAPSHOT", ""));
|
||||
response.put("min_version", minVersion);
|
||||
response.put("total_memory", Runtime.getRuntime().totalMemory());
|
||||
response.put("free_memory", Runtime.getRuntime().freeMemory());
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the application logs.
|
||||
*
|
||||
* @param level Filter on logging level
|
||||
* @param tag Filter on logger name / tag
|
||||
* @param message Filter on message
|
||||
* @param limit Page limit
|
||||
* @param offset Page offset
|
||||
* @return
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Path("log")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response log(
|
||||
@QueryParam("level") String level,
|
||||
@QueryParam("tag") String tag,
|
||||
@QueryParam("message") String message,
|
||||
@QueryParam("limit") Integer limit,
|
||||
@QueryParam("offset") Integer offset) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
checkBaseFunction(BaseFunction.ADMIN);
|
||||
|
||||
// Get the memory appender
|
||||
Logger logger = Logger.getRootLogger();
|
||||
Appender appender = logger.getAppender("MEMORY");
|
||||
if (appender == null || !(appender instanceof MemoryAppender)) {
|
||||
throw new ServerException("ServerError", "MEMORY appender not configured");
|
||||
}
|
||||
MemoryAppender memoryAppender = (MemoryAppender) appender;
|
||||
|
||||
// Find the logs
|
||||
LogCriteria logCriteria = new LogCriteria();
|
||||
logCriteria.setLevel(StringUtils.stripToNull(level));
|
||||
logCriteria.setTag(StringUtils.stripToNull(tag));
|
||||
logCriteria.setMessage(StringUtils.stripToNull(message));
|
||||
|
||||
PaginatedList<LogEntry> paginatedList = PaginatedLists.create(limit, offset);
|
||||
memoryAppender.find(logCriteria, paginatedList);
|
||||
JSONObject response = new JSONObject();
|
||||
List<JSONObject> logs = new ArrayList<JSONObject>();
|
||||
for (LogEntry logEntry : paginatedList.getResultList()) {
|
||||
JSONObject log = new JSONObject();
|
||||
log.put("date", logEntry.getTimestamp());
|
||||
log.put("level", logEntry.getLevel());
|
||||
log.put("tag", logEntry.getTag());
|
||||
log.put("message", logEntry.getMessage());
|
||||
logs.add(log);
|
||||
}
|
||||
response.put("total", paginatedList.getResultCount());
|
||||
response.put("logs", logs);
|
||||
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package com.sismics.docs.rest.resource;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
|
||||
import com.sismics.docs.rest.constant.BaseFunction;
|
||||
import com.sismics.rest.exception.ForbiddenClientException;
|
||||
import com.sismics.security.IPrincipal;
|
||||
import com.sismics.security.UserPrincipal;
|
||||
import com.sismics.util.filter.TokenBasedSecurityFilter;
|
||||
|
||||
/**
|
||||
* Base class of REST resources.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
public abstract class BaseResource {
|
||||
/**
|
||||
* Injects the HTTP request.
|
||||
*/
|
||||
@Context
|
||||
protected HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* Application key.
|
||||
*/
|
||||
@QueryParam("app_key")
|
||||
protected String appKey;
|
||||
|
||||
/**
|
||||
* Principal of the authenticated user.
|
||||
*/
|
||||
protected IPrincipal principal;
|
||||
|
||||
/**
|
||||
* This method is used to check if the user is authenticated.
|
||||
*
|
||||
* @return True if the user is authenticated and not anonymous
|
||||
*/
|
||||
protected boolean authenticate() {
|
||||
Principal principal = (Principal) request.getAttribute(TokenBasedSecurityFilter.PRINCIPAL_ATTRIBUTE);
|
||||
if (principal != null && principal instanceof IPrincipal) {
|
||||
this.principal = (IPrincipal) principal;
|
||||
return !this.principal.isAnonymous();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has a base function. Throw an exception if the check fails.
|
||||
*
|
||||
* @param baseFunction Base function to check
|
||||
* @throws JSONException
|
||||
*/
|
||||
protected void checkBaseFunction(BaseFunction baseFunction) throws JSONException {
|
||||
if (!hasBaseFunction(baseFunction)) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has a base function.
|
||||
*
|
||||
* @param baseFunction Base function to check
|
||||
* @return True if the user has the base function
|
||||
* @throws JSONException
|
||||
*/
|
||||
protected boolean hasBaseFunction(BaseFunction baseFunction) throws JSONException {
|
||||
if (principal == null || !(principal instanceof UserPrincipal)) {
|
||||
return false;
|
||||
}
|
||||
Set<String> baseFunctionSet = ((UserPrincipal) principal).getBaseFunctionSet();
|
||||
return baseFunctionSet != null && baseFunctionSet.contains(baseFunction.name());
|
||||
}
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package com.sismics.docs.rest.resource;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.FormParam;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
||||
import com.sismics.docs.core.dao.jpa.criteria.DocumentCriteria;
|
||||
import com.sismics.docs.core.dao.jpa.dto.DocumentDto;
|
||||
import com.sismics.docs.core.model.jpa.Document;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedList;
|
||||
import com.sismics.docs.core.util.jpa.PaginatedLists;
|
||||
import com.sismics.docs.core.util.jpa.SortCriteria;
|
||||
import com.sismics.rest.exception.ClientException;
|
||||
import com.sismics.rest.exception.ForbiddenClientException;
|
||||
import com.sismics.rest.util.ValidationUtil;
|
||||
|
||||
/**
|
||||
* Document REST resources.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
@Path("/document")
|
||||
public class DocumentResource extends BaseResource {
|
||||
/**
|
||||
* Returns a document.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response get(
|
||||
@QueryParam("id") String id) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document documentDb = null;
|
||||
try {
|
||||
documentDb = documentDao.getDocument(id, principal.getId());
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("DocumentNotFound", MessageFormat.format("Document not found: {0}", id));
|
||||
}
|
||||
|
||||
JSONObject document = new JSONObject();
|
||||
document.put("id", documentDb.getId());
|
||||
document.put("title", documentDb.getTitle());
|
||||
document.put("description", documentDb.getDescription());
|
||||
document.put("create_date", documentDb.getCreateDate().getTime());
|
||||
|
||||
return Response.ok().entity(document).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all documents.
|
||||
*
|
||||
* @param limit Page limit
|
||||
* @param offset Page offset
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Path("list")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response list(
|
||||
@QueryParam("limit") Integer limit,
|
||||
@QueryParam("offset") Integer offset,
|
||||
@QueryParam("sort_column") Integer sortColumn,
|
||||
@QueryParam("asc") Boolean asc) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
List<JSONObject> documents = new ArrayList<JSONObject>();
|
||||
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
PaginatedList<DocumentDto> paginatedList = PaginatedLists.create(limit, offset);
|
||||
SortCriteria sortCriteria = new SortCriteria(sortColumn, asc);
|
||||
DocumentCriteria documentCriteria = new DocumentCriteria();
|
||||
documentCriteria.setUserId(principal.getId());
|
||||
documentDao.findByCriteria(paginatedList, documentCriteria, sortCriteria);
|
||||
|
||||
for (DocumentDto documentDto : paginatedList.getResultList()) {
|
||||
JSONObject document = new JSONObject();
|
||||
document.put("id", documentDto.getId());
|
||||
document.put("title", documentDto.getTitle());
|
||||
document.put("description", documentDto.getDescription());
|
||||
document.put("create_date", documentDto.getCreateTimestamp());
|
||||
documents.add(document);
|
||||
}
|
||||
response.put("total", paginatedList.getResultCount());
|
||||
response.put("documents", documents);
|
||||
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new document.
|
||||
*
|
||||
* @param title Title
|
||||
* @param description Description
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@PUT
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response add(
|
||||
@FormParam("title") String title,
|
||||
@FormParam("description") String description) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
// Validate input data
|
||||
title = ValidationUtil.validateLength(title, "title", 1, 100, false);
|
||||
description = ValidationUtil.validateLength(description, "description", 0, 4000, true);
|
||||
|
||||
// Create the document
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = new Document();
|
||||
document.setUserId(principal.getId());
|
||||
document.setTitle(title);
|
||||
document.setDescription(description);
|
||||
String documentId = documentDao.create(document);
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("id", documentId);
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the document.
|
||||
*
|
||||
* @param title Title
|
||||
* @param description Description
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@POST
|
||||
@Path("{id: [a-z0-9\\-]+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response update(
|
||||
@PathParam("id") String id,
|
||||
@FormParam("title") String title,
|
||||
@FormParam("description") String description) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
// Validate input data
|
||||
title = ValidationUtil.validateLength(title, "title", 1, 100, false);
|
||||
description = ValidationUtil.validateLength(description, "description", 0, 4000, true);
|
||||
|
||||
// Get the document
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = null;
|
||||
try {
|
||||
document = documentDao.getDocument(id, principal.getId());
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("DocumentNotFound", MessageFormat.format("Document not found: {0}", id));
|
||||
}
|
||||
|
||||
// Update the document
|
||||
if (title != null) {
|
||||
document.setTitle(title);
|
||||
}
|
||||
if (description != null) {
|
||||
document.setDescription(description);
|
||||
}
|
||||
|
||||
// Always return ok
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("status", "ok");
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a document.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id: [a-z0-9\\-]+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response delete(
|
||||
@PathParam("id") String id) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
// Get the document
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = null;
|
||||
try {
|
||||
document = documentDao.getDocument(id, principal.getId());
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("DocumentNotFound", MessageFormat.format("Document not found: {0}", id));
|
||||
}
|
||||
|
||||
// Delete the document
|
||||
documentDao.delete(document.getId());
|
||||
|
||||
// Always return ok
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("status", "ok");
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
package com.sismics.docs.rest.resource;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
import com.sismics.docs.core.dao.jpa.DocumentDao;
|
||||
import com.sismics.docs.core.dao.jpa.FileDao;
|
||||
import com.sismics.docs.core.model.jpa.Document;
|
||||
import com.sismics.docs.core.model.jpa.File;
|
||||
import com.sismics.docs.core.util.DirectoryUtil;
|
||||
import com.sismics.rest.exception.ClientException;
|
||||
import com.sismics.rest.exception.ForbiddenClientException;
|
||||
import com.sismics.rest.exception.ServerException;
|
||||
import com.sismics.rest.util.ValidationUtil;
|
||||
import com.sismics.util.mime.MimeTypeUtil;
|
||||
import com.sun.jersey.multipart.FormDataBodyPart;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
|
||||
/**
|
||||
* File REST resources.
|
||||
*
|
||||
* @author bgamard
|
||||
*/
|
||||
@Path("/file")
|
||||
public class FileResource extends BaseResource {
|
||||
/**
|
||||
* Add a file to a document.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @param fileBodyPart File to add
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@PUT
|
||||
@Consumes("multipart/form-data")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response add(
|
||||
@FormDataParam("id") String documentId,
|
||||
@FormDataParam("file") FormDataBodyPart fileBodyPart) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
// Validate input data
|
||||
ValidationUtil.validateRequired(documentId, "id");
|
||||
ValidationUtil.validateRequired(fileBodyPart, "file");
|
||||
|
||||
// Get the document
|
||||
DocumentDao documentDao = new DocumentDao();
|
||||
Document document = null;
|
||||
try {
|
||||
document = documentDao.getDocument(documentId, principal.getId());
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("DocumentNotFound", MessageFormat.format("Document not found: {0}", documentId));
|
||||
}
|
||||
|
||||
|
||||
FileDao fileDao = new FileDao();
|
||||
|
||||
InputStream is = fileBodyPart.getValueAs(InputStream.class);
|
||||
try {
|
||||
// Create the file
|
||||
File file = new File();
|
||||
file.setDocumentId(document.getId());
|
||||
file.setMimeType(MimeTypeUtil.guessMimeType(is));
|
||||
String fileId = fileDao.create(file);
|
||||
|
||||
// Copy the incoming stream content into the storage directory
|
||||
Files.copy(is, Paths.get(DirectoryUtil.getStorageDirectory().getPath(), fileId));
|
||||
|
||||
// Always return ok
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("status", "ok");
|
||||
response.put("id", fileId);
|
||||
return Response.ok().entity(response).build();
|
||||
} catch (Exception e) {
|
||||
throw new ServerException("FileError", "Error adding a file", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response get(
|
||||
@QueryParam("id") String id) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
FileDao fileDao = new FileDao();
|
||||
File fileDb = null;
|
||||
try {
|
||||
fileDb = fileDao.getFile(id);
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("FileNotFound", MessageFormat.format("File not found: {0}", id));
|
||||
}
|
||||
|
||||
JSONObject file = new JSONObject();
|
||||
file.put("id", fileDb.getId());
|
||||
file.put("mimetype", fileDb.getMimeType());
|
||||
file.put("document_id", fileDb.getDocumentId());
|
||||
file.put("create_date", fileDb.getCreateDate().getTime());
|
||||
|
||||
return Response.ok().entity(file).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns files linked to a document.
|
||||
*
|
||||
* @param id Document ID
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Path("list")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response list(
|
||||
@QueryParam("id") String documentId) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
FileDao fileDao = new FileDao();
|
||||
List<File> fileList = fileDao.getByDocumentId(documentId);
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
List<JSONObject> files = new ArrayList<JSONObject>();
|
||||
|
||||
for (File fileDb : fileList) {
|
||||
JSONObject file = new JSONObject();
|
||||
file.put("id", fileDb.getId());
|
||||
file.put("mimetype", fileDb.getMimeType());
|
||||
file.put("document_id", fileDb.getDocumentId());
|
||||
file.put("create_date", fileDb.getCreateDate().getTime());
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
response.put("files", files);
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file.
|
||||
*
|
||||
* @param id File ID
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id: [a-z0-9\\-]+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response delete(
|
||||
@PathParam("id") String id) throws JSONException {
|
||||
if (!authenticate()) {
|
||||
throw new ForbiddenClientException();
|
||||
}
|
||||
|
||||
// Get the file
|
||||
FileDao fileDao = new FileDao();
|
||||
File file = null;
|
||||
try {
|
||||
file = fileDao.getFile(id);
|
||||
} catch (NoResultException e) {
|
||||
throw new ClientException("FileNotFound", MessageFormat.format("File not found: {0}", id));
|
||||
}
|
||||
|
||||
// Delete the document
|
||||
fileDao.delete(file.getId());
|
||||
|
||||
// Always return ok
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("status", "ok");
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.sismics.docs.rest.resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
|
||||
import com.sismics.docs.core.dao.jpa.LocaleDao;
|
||||
import com.sismics.docs.core.model.jpa.Locale;
|
||||
|
||||
/**
|
||||
* Locale REST resources.
|
||||
*
|
||||
* @author jtremeaux
|
||||
*/
|
||||
@Path("/locale")
|
||||
public class LocaleResource extends BaseResource {
|
||||
/**
|
||||
* Returns the list of all locales.
|
||||
*
|
||||
* @return Response
|
||||
* @throws JSONException
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response list() throws JSONException {
|
||||
LocaleDao localeDao = new LocaleDao();
|
||||
List<Locale> localeList = localeDao.findAll();
|
||||
JSONObject response = new JSONObject();
|
||||
List<JSONObject> items = new ArrayList<JSONObject>();
|
||||
for (Locale locale : localeList) {
|
||||
JSONObject item = new JSONObject();
|
||||
item.put("id", locale.getId());
|
||||
items.add(item);
|
||||
}
|
||||
response.put("locales", items);
|
||||
return Response.ok().entity(response).build();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user