Commit 38a6a1cd authored by Arent-Jan Banck's avatar Arent-Jan Banck

CMS7-8719: Rename services-webresources to services-webfiles

parents
* text=auto !eol
/pom.xml -text
src/main/java/org/onehippo/cms7/services/webfiles/WebFilesServiceImpl.java -text
src/main/java/org/onehippo/cms7/services/webfiles/WebFilesServiceModule.java -text
src/main/java/org/onehippo/cms7/services/webfiles/jcr/JcrBinaryImpl.java -text
src/main/java/org/onehippo/cms7/services/webfiles/jcr/WebFileBundleImpl.java -text
src/main/java/org/onehippo/cms7/services/webfiles/jcr/WebFileImpl.java -text
src/main/java/org/onehippo/cms7/services/webfiles/vault/AbstractWebFilesArchive.java -text
src/main/java/org/onehippo/cms7/services/webfiles/vault/FileNameComparatorUtils.java -text
src/main/java/org/onehippo/cms7/services/webfiles/watch/WebFilesWatcherJcrConfig.java -text
src/main/resources/hippoecm-extension.xml -text
src/main/resources/webfiles-service-module.xml -text
src/main/resources/webfiles.cnd -text
src/test/java/org/onehippo/cms7/services/webfiles/jcr/WebFileImplTest.java -text
src/test/java/org/onehippo/cms7/services/webfiles/vault/FileNameComparatorUtilsTest.java -text
src/test/java/org/onehippo/cms7/services/webfiles/watch/AbstractSubDirectoriesWatcherWithFileSystemObserverIT.java -text
src/test/java/org/onehippo/cms7/services/webfiles/watch/AbstractWatcherIT.java -text
src/test/java/org/onehippo/cms7/services/webfiles/watch/WebFilesWatcherIT.java -text
src/test/resources/empty.zip -text
src/test/resources/log4j.xml -text
src/test/resources/testbundle-empty.zip -text
src/test/resources/testbundle-with-custom-dot-content-xml.zip -text
src/test/resources/testbundle-with-empty-dir.zip -text
src/test/resources/testbundle.zip -text
src/test/resources/testbundle/ftl/main/list.ftl -text
src/test/resources/testbundle/ftl/main/list.properties -text
src/test/resources/testbundle/ftl/main/list/list_title.ftl -text
src/test/resources/testbundle/ftl/main/list/list_title_date.ftl -text
/*.iml
/.idea
/log4j.log
/target
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2014 Hippo B.V. (http://www.onehippo.com)
Licensed 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.
-->
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-cms7-project</artifactId>
<version>27-SNAPSHOT</version>
</parent>
<name>Hippo CMS7 Services - webfiles</name>
<artifactId>hippo-services-webfiles</artifactId>
<version>1.05.00-SNAPSHOT</version>
<inceptionYear>2014</inceptionYear>
<properties>
<!-- use root project name for all project modules NOTICE files, should be the same as in the root NOTICE file -->
<notice.project.name>Hippo CMS7 Services - webfiles</notice.project.name>
<commons-io.version>2.4</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<hippo.repository.version>2.27.00-SNAPSHOT</hippo.repository.version>
<hippo.services.version>1.05.00-SNAPSHOT</hippo.services.version>
<tika.version>1.3</tika.version>
<junit.version>4.11</junit.version>
</properties>
<scm>
<connection>scm:svn:http://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-webresources/trunk</connection>
<developerConnection>scm:svn:https://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-webresources/trunk</developerConnection>
<url>http://svn.onehippo.org/repos/hippo/hippo-cms7/services/services-webresources/trunk</url>
</scm>
<repositories>
<repository>
<id>hippo</id>
<name>Hippo Maven 2</name>
<url>https://maven.onehippo.com/maven2/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-services</artifactId>
<version>${hippo.services.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jackrabbit.vault</groupId>
<artifactId>org.apache.jackrabbit.vault</artifactId>
<version>3.1.6</version>
</dependency>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-repository-api</artifactId>
<version>${hippo.repository.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>${tika.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-repository-testutils</artifactId>
<version>${hippo.repository.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.onehippo.cms7</groupId>
<artifactId>hippo-repository-engine</artifactId>
<version>${hippo.repository.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>tests</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>pedantic</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<inherited>false</inherited>
<configuration>
<excludes combine.children="append">
<!-- test resources with specific content that is verified in unit tests -->
<exclude>src/test/resources/testbundle/**/*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
/*
* Copyright 2014-2015 Hippo B.V. (http://www.onehippo.com)
*
* Licensed 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.
*/
package org.onehippo.cms7.services.webfiles;
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipFile;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.vault.fs.config.ConfigurationException;
import org.apache.jackrabbit.vault.fs.io.Archive;
import org.apache.jackrabbit.vault.fs.io.ImportOptions;
import org.apache.jackrabbit.vault.fs.io.Importer;
import org.hippoecm.repository.util.JcrUtils;
import org.onehippo.cms7.event.HippoEvent;
import org.onehippo.cms7.services.HippoServiceRegistry;
import org.onehippo.cms7.services.eventbus.HippoEventBus;
import org.onehippo.cms7.services.webfiles.jcr.WebFileBundleImpl;
import org.onehippo.cms7.services.webfiles.vault.AbstractWebFilesArchive;
import org.onehippo.cms7.services.webfiles.vault.WebFileBundleArchive;
import org.onehippo.cms7.services.webfiles.vault.WebFilesFileArchive;
import org.onehippo.cms7.services.webfiles.vault.WebFilesZipArchive;
import org.onehippo.cms7.services.webfiles.watch.GlobFileNameMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.onehippo.cms7.services.webfiles.jcr.WebFileBundleImpl.PROPERTY_WEB_FILE_BUNDLE_ANTICACHE;
public class WebFilesServiceImpl implements WebFilesService {
private static final Logger log = LoggerFactory.getLogger(WebFilesServiceImpl.class);
public static final String NT_WEB_RESOURCE_BUNDLE = "webfiles:bundle";
private final GlobFileNameMatcher importedFiles;
public WebFilesServiceImpl(final GlobFileNameMatcher importedFiles) {
this.importedFiles = importedFiles;
}
@Override
public WebFileBundle getJcrWebFileBundle(final Session session, final String bundleName) {
try {
final Node bundleRoot = getBundleRoot(session, bundleName);
return new WebFileBundleImpl(session, bundleRoot);
} catch (RepositoryException e) {
throw new WebFileException(warn("Cannot instantiate web file bundle for '%s'", bundleName));
}
}
private Node getBundleRoot(final Session session, final String bundleName) throws RepositoryException {
final Node webFilesRoot = getWebFilessRoot(session);
final Node bundleRoot = JcrUtils.getNodeIfExists(webFilesRoot, bundleName);
if (bundleRoot == null) {
warnAndThrow("Cannot find web files bundle '%s' below '%s'", bundleName, JCR_ROOT_PATH);
}
if (!bundleRoot.isNodeType(NT_WEB_RESOURCE_BUNDLE)) {
warnAndThrow("Cannot instantiate web file bundle for '%s' because" +
" it does not point to a node of type '%s'", bundleName, NT_WEB_RESOURCE_BUNDLE);
}
return bundleRoot;
}
private Node getWebFilessRoot(final Session session) throws RepositoryException, WebFileException {
final Node webFilesRoot = JcrUtils.getNodeIfExists(JCR_ROOT_PATH, session);
if (webFilesRoot == null) {
warnAndThrow("Cannot find web files root at '%s'", JCR_ROOT_PATH);
}
return webFilesRoot;
}
@Override
public void importJcrWebFileBundle(final Session session, final File directory) throws IOException, WebFileException {
final WebFilesFileArchive archive = new WebFilesFileArchive(directory, importedFiles);
importJcrWebFileBundle(session, archive);
}
@Override
public void importJcrWebFileBundle(final Session session, final ZipFile zip) throws IOException, WebFileException {
final WebFilesZipArchive archive = new WebFilesZipArchive(zip, importedFiles);
importJcrWebFileBundle(session, archive);
}
private void importJcrWebFileBundle(final Session session, final AbstractWebFilesArchive archive) {
WebFileBundleArchive bundleArchive = new WebFileBundleArchive(archive);
String bundleName = null;
try {
bundleArchive.open(true);
bundleName = bundleArchive.getBundleName();
final Node webFilesRoot = getWebFilessRoot(session);
final String bundleRootPath = webFilesRoot.getPath() + '/' + bundleName;
replaceWebFiles(session, bundleArchive, bundleRootPath, bundleRootPath);
} catch (IOException|RepositoryException|ConfigurationException e) {
throw new WebFileException(warn("Cannot import web file bundle '%s'", bundleName), e);
} finally {
bundleArchive.close();
}
}
@Override
public void importJcrWebFiles(final Session session, final String bundleName, final String bundleSubPath, final File fileOrDirectory) throws WebFileException {
final WebFilesFileArchive archive = new WebFilesFileArchive(fileOrDirectory, importedFiles);
try {
archive.open(true);
final Node webFilesRoot = getWebFilessRoot(session);
final String bundleRootPath = webFilesRoot.getPath() + '/' + bundleName;
String archiveRootPath = bundleRootPath;
if (StringUtils.isNotEmpty(bundleSubPath)) {
archiveRootPath += '/' + bundleSubPath;
}
replaceWebFiles(session, archive, bundleRootPath, archiveRootPath);
} catch (IOException|RepositoryException|ConfigurationException e) {
throw new WebFileException(warn("Cannot import web files from '%s'", fileOrDirectory), e);
} finally {
archive.close();
}
}
private void replaceWebFiles(final Session session,
final Archive archive,
final String bundleRootPath,
final String archiveRootPath) throws RepositoryException, IOException, ConfigurationException {
long startTime = System.currentTimeMillis();
final Node archiveRootNode = JcrUtils.getNodeIfExists(archiveRootPath, session);
if (archiveRootNode != null) {
log.debug("Removing existing children of '{}'", archiveRootPath);
removeChildren(archiveRootNode);
}
final String importPath = StringUtils.substringBeforeLast(archiveRootPath, "/");
final Node importRootNode = JcrUtils.getNodeIfExists(importPath, session);
if (importRootNode == null) {
throw new WebFileException(warn("Cannot import web files at '%s': no such node", importPath));
}
log.debug("Importing archive at '{}'", importPath);
final ImportOptions options = new ImportOptions();
options.setAutoSaveThreshold(Integer.MAX_VALUE); // never save after the import is done
final Importer importer = new Importer(options);
importer.run(archive, importRootNode);
final Node bundleRootNode = session.getNode(bundleRootPath);
final Property antiCache = JcrUtils.getPropertyIfExists(bundleRootNode, PROPERTY_WEB_FILE_BUNDLE_ANTICACHE);
if (antiCache == null) {
bundleRootNode.setProperty(PROPERTY_WEB_FILE_BUNDLE_ANTICACHE, String.valueOf(System.currentTimeMillis()));
} else {
antiCache.setValue(String.valueOf(System.currentTimeMillis()));
}
long endTime = System.currentTimeMillis();
log.info("Replacing web files at '{}' took {} ms", StringUtils.removeStart(archiveRootPath, JCR_ROOT_PATH), endTime - startTime);
}
private static void removeChildren(final Node node) throws RepositoryException {
final NodeIterator children = node.getNodes();
while (children.hasNext()) {
final Node child = children.nextNode();
child.remove();
}
}
public static void logEvent(String action, String user, String message) {
final HippoEventBus eventBus = HippoServiceRegistry.getService(HippoEventBus.class);
if (eventBus != null) {
final HippoEvent event = new HippoEvent("webfiles-service");
event.category("webfiles-service").user(user).action(action);
event.message(message);
eventBus.post(event);
}
}
private static void warnAndThrow(final String message, final Object... args) {
throw new WebFileException(warn(message, args));
}
private static String warn(final String message, final Object... args) {
String warning = String.format(message, args);
log.warn(warning);
return warning;
}
}
/*
* Copyright 2014-2015 Hippo B.V. (http://www.onehippo.com)
*
* Licensed 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.
*/
package org.onehippo.cms7.services.webfiles;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.onehippo.cms7.services.HippoServiceRegistry;
import org.onehippo.cms7.services.autoreload.AutoReloadService;
import org.onehippo.cms7.services.eventbus.HippoEventBus;
import org.onehippo.cms7.services.webfiles.watch.GlobFileNameMatcher;
import org.onehippo.cms7.services.webfiles.watch.WebFilesWatcher;
import org.onehippo.cms7.services.webfiles.watch.WebFilesWatcherConfig;
import org.onehippo.cms7.services.webfiles.watch.WebFilesWatcherJcrConfig;
import org.onehippo.repository.modules.AbstractReconfigurableDaemonModule;
public class WebFilesServiceModule extends AbstractReconfigurableDaemonModule {
private WebFilesServiceImpl service;
private WebFilesWatcherConfig config;
private WebFilesWatcher watcher;
@Override
protected void doConfigure(final Node moduleConfig) throws RepositoryException {
if (config == null) {
config = new WebFilesWatcherJcrConfig(moduleConfig);
}
}
@Override
protected void doInitialize(final Session session) throws RepositoryException {
final GlobFileNameMatcher watchedFiles = new GlobFileNameMatcher();
watchedFiles.includeFiles(config.getIncludedFiles());
watchedFiles.excludeDirectories(config.getExcludedDirectories());
service = new WebFilesServiceImpl(watchedFiles);
HippoServiceRegistry.registerService(service, WebFilesService.class);
final HippoEventBus eventBus = HippoServiceRegistry.getService(HippoEventBus.class);
final AutoReloadService autoReload = HippoServiceRegistry.getService(AutoReloadService.class);
watcher = new WebFilesWatcher(config, service, session, eventBus, autoReload);
}
@Override
protected void doShutdown() {
if (service != null) {
HippoServiceRegistry.unregisterService(service, WebFilesService.class);
}
if (watcher != null) {
try {
watcher.shutdown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
/*
* Copyright 2014-2015 Hippo B.V. (http://www.onehippo.com)
*
* Licensed 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.
*/
package org.onehippo.cms7.services.webfiles.jcr;
import java.io.InputStream;
import javax.jcr.RepositoryException;
import org.onehippo.cms7.services.webfiles.Binary;
import org.onehippo.cms7.services.webfiles.WebFileException;
public class JcrBinaryImpl implements Binary {
final javax.jcr.Binary delegatee;
public JcrBinaryImpl(final javax.jcr.Binary binary) {
delegatee = binary;
}
@Override
public InputStream getStream(){
try {
return delegatee.getStream();
} catch (RepositoryException e) {
throw new WebFileException(e);
}
}
@Override
public long getSize() {
try {
return delegatee.getSize();
} catch (RepositoryException e) {
throw new WebFileException(e);
}
}
@Override
public void dispose() {
delegatee.dispose();
}
}
/*
* Copyright 2014-2015 Hippo B.V. (http://www.onehippo.com)
*
* Licensed 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.
*/
package org.onehippo.cms7.services.webfiles.jcr;
import java.util.Calendar;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.hippoecm.repository.util.JcrUtils;
import org.onehippo.cms7.services.webfiles.Binary;
import org.onehippo.cms7.services.webfiles.WebFile;
import org.onehippo.cms7.services.webfiles.WebFileException;
import org.onehippo.cms7.services.webfiles.WebFileNotFoundException;
import static org.onehippo.repository.util.JcrConstants.JCR_CONTENT;
import static org.onehippo.repository.util.JcrConstants.JCR_DATA;
import static org.onehippo.repository.util.JcrConstants.JCR_FROZEN_PRIMARY_TYPE;
import static org.onehippo.repository.util.JcrConstants.JCR_LAST_MODIFIED;
import static org.onehippo.repository.util.JcrConstants.JCR_MIME_TYPE;
import static org.onehippo.repository.util.JcrConstants.NT_FILE;
import static org.onehippo.repository.util.JcrConstants.NT_FROZEN_NODE;
public class WebFileImpl implements WebFile {
private final Node resource;
private final Node content;
private final String path;
public WebFileImpl(final Node file) {
try {
assertExpectedNodeType(file);
this.resource = file;
this.path = file.getPath();
content = resource.getNode(JCR_CONTENT);
} catch (RepositoryException e) {
throw new WebFileException("Cannot initialize web file.", e);
}
}
@Override
public String getPath() {
return path;
}
@Override
public String getName() {
try {
return resource.getName();
} catch (RepositoryException e) {
throw new WebFileException(e.toString() , e);
}
}
@Override
public String getEncoding() {
return null;
}
@Override
public Calendar getLastModified() {
try {
return JcrUtils.getDateProperty(content, JCR_LAST_MODIFIED, null);
} catch (RepositoryException e) {
throw new WebFileException(e.toString(), e);
}
}
@Override
public String getMimeType() {
try {
return JcrUtils.getStringProperty(content, JCR_MIME_TYPE, null);
} catch (RepositoryException e) {
throw new WebFileException(e.toString(), e);
}
}
@Override
public Binary getBinary() {
try {
return new JcrBinaryImpl(content.getProperty(JCR_DATA).getBinary());
} catch (RepositoryException e) {
throw new WebFileException(e.toString(), e);
}
}
private void assertExpectedNodeType(final Node file) throws RepositoryException {
if (! (file.isNodeType(NT_FILE) || file.isNodeType(NT_FROZEN_NODE))) {
throwUnexpectedNode(file);
}
if (file.isNodeT