You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2018/09/06 18:25:50 UTC

[sling-org-apache-sling-file-optimization] branch master updated: Adding Provider / Consumer Type annotations and moving the reference optimizers into an internal package

This is an automated email from the ASF dual-hosted git repository.

dklco pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-file-optimization.git


The following commit(s) were added to refs/heads/master by this push:
     new b8abe02  Adding Provider / Consumer Type annotations and moving the reference optimizers into an internal package
b8abe02 is described below

commit b8abe02a3e4290743cb89a5f8a4a077ec884be69
Author: Dan Klco <da...@perficient.com>
AuthorDate: Thu Sep 6 14:25:06 2018 -0400

    Adding Provider / Consumer Type annotations and moving the reference
    optimizers into an internal package
---
 pom.xml                                            | 398 ++++++++++----------
 .../org/apache/sling/fileoptim/FileOptimizer.java  |  34 +-
 .../sling/fileoptim/FileOptimizerService.java      |  76 ++--
 .../apache/sling/fileoptim/OptimizationResult.java | 255 +++++++------
 .../fileoptim/impl/FileOptimizerEventHandler.java  |  86 ++---
 .../fileoptim/impl/FileOptimizerServiceImpl.java   | 418 ++++++++++-----------
 .../fileoptim/impl/FileOptimizerWebConsole.java    |  80 ++--
 .../fileoptim/impl/OptimizeFileOperation.java      |  92 ++---
 .../fileoptim/impl/RestoreOriginalOperation.java   |  98 ++---
 .../impl/filters/FileOptimizerFilter.java          |  96 ++---
 .../fileoptim/impl/servlets/FileOptimizerData.java |  58 +--
 .../impl/servlets/FileOptimizerPreview.java        |  42 +--
 .../optimizers/JpegFileOptimizer.java              |  74 ++--
 .../optimizers/PngFileOptimizer.java               |  40 +-
 .../sling/fileoptim/models/OptimizeResource.java   |  90 ++---
 .../sling/fileoptim/models/OptimizedFile.java      |  50 +--
 .../sling/fileoptim/models/package-info.java       |   2 +-
 .../sling/fileoptim/optimizers/package-info.java   |  18 -
 .../org/apache/sling/fileoptim/package-info.java   |   2 +-
 .../sling/fileoptim/BaseFileOptimizerTest.java     | 232 ++++++------
 .../sling/fileoptim/impl/TestFileOptimizer.java    |  69 ++--
 .../impl/servlets/TestFileOptimizerData.java       |  72 ++--
 .../fileoptim/optimizers/TestJPGFileOptimizer.java |  66 ++--
 .../fileoptim/optimizers/TestPngFileOptimizer.java |  30 +-
 24 files changed, 1233 insertions(+), 1245 deletions(-)

diff --git a/pom.xml b/pom.xml
index 568ab9d..3d1376c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,217 +1,219 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <!-- 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. -->
-<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">
+    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. -->
+<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>
-	<parent>
-		<groupId>org.apache.sling</groupId>
-		<artifactId>sling</artifactId>
-		<version>33</version>
-		<relativePath />
-	</parent>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>33</version>
+        <relativePath />
+    </parent>
 
-	<artifactId>org.apache.sling.fileoptim</artifactId>
-	<version>0.9.3-SNAPSHOT</version>
-	<packaging>bundle</packaging>
+    <artifactId>org.apache.sling.fileoptim</artifactId>
+    <version>0.9.3-SNAPSHOT</version>
+    <packaging>bundle</packaging>
 
-	<name>Apache Sling File Optimization</name>
-	<description>
+    <name>Apache Sling File Optimization</name>
+    <description>
         Bundle for optimizing files stored in the Apache Sling repository. Includes a plugin architecture for providing file optimizers and hooks to automatically and manually optimize files.
     </description>
 
-	<scm>
-		<connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-file-optimization.git</connection>
-		<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-file-optimization.git</developerConnection>
-		<url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-file-optimization.git</url>
-		<tag>HEAD</tag>
-	</scm>
+    <scm>
+        <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-file-optimization.git</connection>
+        <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-file-optimization.git</developerConnection>
+        <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-file-optimization.git</url>
+        <tag>HEAD</tag>
+    </scm>
 
-	<build>
-		<plugins>
-			<plugin>
-				<groupId>org.apache.felix</groupId>
-				<artifactId>maven-bundle-plugin</artifactId>
-				<extensions>true</extensions>
-				<configuration>
-					<instructions>
-						<Sling-Nodetypes>SLING-INF/nodetypes/nodetypes.cnd</Sling-Nodetypes>
-						<Sling-Model-Packages>org.apache.sling.fileoptim.models</Sling-Model-Packages>
-						<Import-Package>!org.apache.tools.ant,!org.apache.tools.ant.types,*</Import-Package>
-						<Embed-Dependency>
-							*;scope=compile;inline=true
-						</Embed-Dependency>
-					</instructions>
-				</configuration>
-			</plugin>
-			<plugin>
-				<groupId>org.jacoco</groupId>
-				<artifactId>jacoco-maven-plugin</artifactId>
-				<executions>
-					<execution>
-						<goals>
-							<goal>prepare-agent</goal>
-						</goals>
-					</execution>
-					<execution>
-						<id>report</id>
-						<phase>prepare-package</phase>
-						<goals>
-							<goal>report</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
-		</plugins>
-	</build>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Sling-Nodetypes>SLING-INF/nodetypes/nodetypes.cnd</Sling-Nodetypes>
+                        <Sling-Model-Packages>org.apache.sling.fileoptim.models</Sling-Model-Packages>
+                        <Import-Package>!org.apache.tools.ant,!org.apache.tools.ant.types,*</Import-Package>
+                        <Embed-Dependency>
+                            *;scope=compile;inline=true
+                        </Embed-Dependency>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.jacoco</groupId>
+                <artifactId>jacoco-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>prepare-agent</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>report</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>report</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 
-	<dependencies>
+    <dependencies>
 
-		<!-- OSGi -->
-		<dependency>
-			<groupId>org.osgi</groupId>
-			<artifactId>org.osgi.service.component.annotations</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.osgi</groupId>
-			<artifactId>org.osgi.service.metatype.annotations</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.osgi</groupId>
-			<artifactId>org.osgi.annotation.versioning</artifactId>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.osgi</groupId>
-			<artifactId>osgi.core</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.osgi</groupId>
-			<artifactId>osgi.cmpn</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.felix</groupId>
-			<artifactId>org.apache.felix.webconsole</artifactId>
-			<version>4.2.0</version>
-			<scope>provided</scope>
-		</dependency>
+        <!-- OSGi -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.component.annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.metatype.annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.annotation.versioning</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.cmpn</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.webconsole</artifactId>
+            <version>4.2.0</version>
+            <scope>provided</scope>
+        </dependency>
 
-		<!-- JCR / Sling Commons -->
-		<dependency>
-			<groupId>javax.jcr</groupId>
-			<artifactId>jcr</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.jackrabbit</groupId>
-			<artifactId>jackrabbit-jcr-commons</artifactId>
-			<version>2.7.5</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.sling</groupId>
-			<artifactId>org.apache.sling.api</artifactId>
-			<version>2.8.0</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.sling</groupId>
-			<artifactId>org.apache.sling.servlets.post</artifactId>
-			<version>2.3.22</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.sling</groupId>
-			<artifactId>org.apache.sling.engine</artifactId>
-			<version>2.6.12</version>
-			<scope>provided</scope>
-		</dependency>
+        <!-- JCR / Sling Commons -->
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>2.7.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.8.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.servlets.post</artifactId>
+            <version>2.3.22</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.engine</artifactId>
+            <version>2.6.12</version>
+            <scope>provided</scope>
+        </dependency>
 
-		<!-- Image Optimization Dependencies -->
-		<dependency>
-			<groupId>com.github.depsypher</groupId>
-			<artifactId>pngtastic</artifactId>
-			<version>1.5</version>
-			<scope>compile</scope>
-		</dependency>
+        <!-- Image Optimization Dependencies -->
+        <dependency>
+            <groupId>com.github.depsypher</groupId>
+            <artifactId>pngtastic</artifactId>
+            <version>1.5</version>
+            <scope>compile</scope>
+        </dependency>
 
 
-		<!-- Base Dependencies -->
-		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>javax.servlet-api</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.slf4j</groupId>
-			<artifactId>slf4j-api</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>commons-lang</groupId>
-			<artifactId>commons-lang</artifactId>
-			<version>2.4</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>commons-io</groupId>
-			<artifactId>commons-io</artifactId>
-			<version>2.4</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<artifactId>commons-codec</artifactId>
-			<version>1.11</version>
-			<groupId>commons-codec</groupId>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<artifactId>org.apache.sling.commons.johnzon</artifactId>
-			<version>1.1.0</version>
-			<groupId>org.apache.sling</groupId>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.jetbrains</groupId>
-			<artifactId>annotations</artifactId>
-			<version>16.0.2</version>
-			<scope>provided</scope>
-		</dependency>
+        <!-- Base Dependencies -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <artifactId>commons-codec</artifactId>
+            <version>1.11</version>
+            <groupId>commons-codec</groupId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <artifactId>org.apache.sling.commons.johnzon</artifactId>
+            <version>1.1.0</version>
+            <groupId>org.apache.sling</groupId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>16.0.2</version>
+            <scope>provided</scope>
+        </dependency>
 
 
-		<!-- Sling Models -->
-		<dependency>
-			<groupId>org.apache.sling</groupId>
-			<artifactId>org.apache.sling.models.api</artifactId>
-			<version>1.3.6</version>
-			<scope>provided</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.geronimo.specs</groupId>
-			<artifactId>geronimo-atinject_1.0_spec</artifactId>
-			<version>1.0</version>
-			<scope>provided</scope>
-		</dependency>
+        <!-- Sling Models -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.models.api</artifactId>
+            <version>1.3.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-atinject_1.0_spec</artifactId>
+            <version>1.0</version>
+            <scope>provided</scope>
+        </dependency>
 
-		<!-- Test Dependencies -->
-		<dependency>
-			<groupId>junit</groupId>
-			<artifactId>junit</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.mockito</groupId>
-			<artifactId>mockito-core</artifactId>
-			<version>2.7.16</version>
-			<scope>test</scope>
-		</dependency>
-		<dependency>
-			<groupId>org.slf4j</groupId>
-			<artifactId>slf4j-simple</artifactId>
-		</dependency>
-	</dependencies>
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>2.7.16</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/src/main/java/org/apache/sling/fileoptim/FileOptimizer.java b/src/main/java/org/apache/sling/fileoptim/FileOptimizer.java
index e304c42..eadf155 100644
--- a/src/main/java/org/apache/sling/fileoptim/FileOptimizer.java
+++ b/src/main/java/org/apache/sling/fileoptim/FileOptimizer.java
@@ -18,28 +18,30 @@ package org.apache.sling.fileoptim;
 
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ConsumerType;
 
 /**
  * Interface for File Optimizers to extend to implement
  */
+@ConsumerType
 public interface FileOptimizer {
 
-	/**
-	 * Optimize a single file.
-	 * 
-	 * @param original the original file to optimize
-	 * @param metaType the type of the file to optimize
-	 * @return the optimized file
-	 */
-	@Nullable
-	byte[] optimizeFile(byte[] original, String metaType);
+    /**
+     * Optimize a single file.
+     * 
+     * @param original the original file to optimize
+     * @param metaType the type of the file to optimize
+     * @return the optimized file
+     */
+    @Nullable
+    byte[] optimizeFile(byte[] original, String metaType);
 
-	/**
-	 * Gets the name of the optimizer
-	 * 
-	 * @return the name of the optimizer
-	 */
-	@NotNull
-	String getName();
+    /**
+     * Gets the name of the optimizer
+     * 
+     * @return the name of the optimizer
+     */
+    @NotNull
+    String getName();
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/FileOptimizerService.java b/src/main/java/org/apache/sling/fileoptim/FileOptimizerService.java
index e05192d..5ae9500 100644
--- a/src/main/java/org/apache/sling/fileoptim/FileOptimizerService.java
+++ b/src/main/java/org/apache/sling/fileoptim/FileOptimizerService.java
@@ -19,51 +19,53 @@ package org.apache.sling.fileoptim;
 import java.io.IOException;
 
 import org.apache.sling.api.resource.Resource;
+import org.osgi.annotation.versioning.ProviderType;
 
 /**
  * A service for optimizing files stored in Sling Resources.
  */
+@ProviderType
 public interface FileOptimizerService {
 
-	/**
-	 * Returns true if the resource is a registered type, the CA Config for the
-	 * resource is enabled and if an optimizer is registered for the file's meta
-	 * type
-	 * 
-	 * @param fileResource the resource to check if the optimizer is available
-	 * @return true if the file optimizer can optimize the file, false otherwise
-	 */
-	boolean canOptimize(Resource fileResource);
+    /**
+     * Returns true if the resource is a registered type, the CA Config for the
+     * resource is enabled and if an optimizer is registered for the file's meta
+     * type
+     * 
+     * @param fileResource the resource to check if the optimizer is available
+     * @return true if the file optimizer can optimize the file, false otherwise
+     */
+    boolean canOptimize(Resource fileResource);
 
-	/**
-	 * Gets the optimized contents of a file resource. This will not update the
-	 * underlying resource, but instead just returns the results of optimizing the
-	 * resource.
-	 * 
-	 * @param fileResource the resource to optimize
-	 * @return the results of the optimization
-	 * @throws IOException an exception occurs reading the original resource
-	 */
-	OptimizationResult getOptimizedContents(Resource fileResource) throws IOException;
+    /**
+     * Gets the optimized contents of a file resource. This will not update the
+     * underlying resource, but instead just returns the results of optimizing the
+     * resource.
+     * 
+     * @param fileResource the resource to optimize
+     * @return the results of the optimization
+     * @throws IOException an exception occurs reading the original resource
+     */
+    OptimizationResult getOptimizedContents(Resource fileResource) throws IOException;
 
-	/**
-	 * Returns true if the specified resource has already been optimized by the
-	 * FileOptimizer.
-	 * 
-	 * @param fileResource the resource to check
-	 * @return true if optimized by the file optimizer, false otherwise
-	 */
-	boolean isOptimized(Resource fileResource);
+    /**
+     * Returns true if the specified resource has already been optimized by the
+     * FileOptimizer.
+     * 
+     * @param fileResource the resource to check
+     * @return true if optimized by the file optimizer, false otherwise
+     */
+    boolean isOptimized(Resource fileResource);
 
-	/**
-	 * Optimizes a file resource. This method will modify the underlying resource.
-	 * 
-	 * @param fileResource the resource to optimize
-	 * @param autoCommit   if true, the results will automatically be committed to
-	 *                     the Sling Repo
-	 * @return the results of the optimization
-	 * @throws IOException an exception occurs reading the original resource
-	 */
-	OptimizationResult optimizeFile(Resource fileResource, boolean autoCommit) throws IOException;
+    /**
+     * Optimizes a file resource. This method will modify the underlying resource.
+     * 
+     * @param fileResource the resource to optimize
+     * @param autoCommit   if true, the results will automatically be committed to
+     *                     the Sling Repo
+     * @return the results of the optimization
+     * @throws IOException an exception occurs reading the original resource
+     */
+    OptimizationResult optimizeFile(Resource fileResource, boolean autoCommit) throws IOException;
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/OptimizationResult.java b/src/main/java/org/apache/sling/fileoptim/OptimizationResult.java
index 21de34b..79b8c2f 100644
--- a/src/main/java/org/apache/sling/fileoptim/OptimizationResult.java
+++ b/src/main/java/org/apache/sling/fileoptim/OptimizationResult.java
@@ -20,139 +20,136 @@ import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 
 import org.apache.sling.api.resource.Resource;
+import org.osgi.annotation.versioning.ProviderType;
 
 /**
  * Result of file optimization
  */
+@ProviderType
 public class OptimizationResult {
 
-	private String algorithm;
-	private boolean optimized = false;
-	private byte[] optimizedContents;
-	private long optimizedSize;
-	private long originalSize;
-	private final Resource resource;
-	private double savings = 0;
-
-	public OptimizationResult(Resource resource) {
-		this.resource = resource;
-	}
-
-	/**
-	 * Returns the algorithm by which the file was optimized
-	 * 
-	 * @return the algorithm
-	 */
-	public String getAlgorithm() {
-		return algorithm;
-	}
-
-	/**
-	 * Returns the raw optimized contents as a byte array
-	 * 
-	 * @return the optimized contents
-	 */
-	public byte[] getOptimizedContents() {
-		return optimizedContents;
-	}
-
-	/**
-	 * Returns the optimized contents as an InputStream
-	 * 
-	 * @return the optimized content stream
-	 */
-	public InputStream getOptimizedContentStream() {
-		return new ByteArrayInputStream(optimizedContents);
-	}
-
-	/**
-	 * Returns the optimized size in bytes
-	 * 
-	 * @return the optimizedSize
-	 */
-	public long getOptimizedSize() {
-		return optimizedSize;
-	}
-
-	/**
-	 * Return the original size in bytes
-	 * 
-	 * @return the originalSize
-	 */
-	public long getOriginalSize() {
-		return originalSize;
-	}
-
-	/**
-	 * Returns the resource that was optimized
-	 * 
-	 * @return the resource
-	 */
-	public Resource getResource() {
-		return resource;
-	}
-
-	/**
-	 * Return the percent savings as a 1-based double value
-	 * 
-	 * @return the savings
-	 */
-	public double getSavings() {
-		return savings;
-	}
-
-	/**
-	 * Returns true if the result is actually optimized, if the optimization did not
-	 * provide a smaller result or the file was not optimized for any other reason,
-	 * this will be false.
-	 * 
-	 * @return the optimized flag
-	 */
-	public boolean isOptimized() {
-		return optimized;
-	}
-
-	/**
-	 * @param algorithm
-	 *            the algorithm to set
-	 */
-	public void setAlgorithm(String algorithm) {
-		this.algorithm = algorithm;
-	}
-
-	/**
-	 * @param optimized
-	 *            the optimized to set
-	 */
-	public void setOptimized(boolean optimized) {
-		this.optimized = optimized;
-	}
-
-	public void setOptimizedContents(byte[] optimizedContents) {
-		this.optimizedContents = optimizedContents;
-	}
-
-	/**
-	 * @param optimizedSize
-	 *            the optimizedSize to set
-	 */
-	public void setOptimizedSize(long optimizedSize) {
-		this.optimizedSize = optimizedSize;
-	}
-
-	/**
-	 * @param originalSize
-	 *            the originalSize to set
-	 */
-	public void setOriginalSize(long originalSize) {
-		this.originalSize = originalSize;
-	}
-
-	/**
-	 * @param savings
-	 *            the savings to set
-	 */
-	public void setSavings(double savings) {
-		this.savings = savings;
-	}
+    private String algorithm;
+    private boolean optimized = false;
+    private byte[] optimizedContents;
+    private long optimizedSize;
+    private long originalSize;
+    private final Resource resource;
+    private double savings = 0;
+
+    public OptimizationResult(Resource resource) {
+        this.resource = resource;
+    }
+
+    /**
+     * Returns the algorithm by which the file was optimized
+     * 
+     * @return the algorithm
+     */
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Returns the raw optimized contents as a byte array
+     * 
+     * @return the optimized contents
+     */
+    public byte[] getOptimizedContents() {
+        return optimizedContents;
+    }
+
+    /**
+     * Returns the optimized contents as an InputStream
+     * 
+     * @return the optimized content stream
+     */
+    public InputStream getOptimizedContentStream() {
+        return new ByteArrayInputStream(optimizedContents);
+    }
+
+    /**
+     * Returns the optimized size in bytes
+     * 
+     * @return the optimizedSize
+     */
+    public long getOptimizedSize() {
+        return optimizedSize;
+    }
+
+    /**
+     * Return the original size in bytes
+     * 
+     * @return the originalSize
+     */
+    public long getOriginalSize() {
+        return originalSize;
+    }
+
+    /**
+     * Returns the resource that was optimized
+     * 
+     * @return the resource
+     */
+    public Resource getResource() {
+        return resource;
+    }
+
+    /**
+     * Return the percent savings as a 1-based double value
+     * 
+     * @return the savings
+     */
+    public double getSavings() {
+        return savings;
+    }
+
+    /**
+     * Returns true if the result is actually optimized, if the optimization did not
+     * provide a smaller result or the file was not optimized for any other reason,
+     * this will be false.
+     * 
+     * @return the optimized flag
+     */
+    public boolean isOptimized() {
+        return optimized;
+    }
+
+    /**
+     * @param algorithm the algorithm to set
+     */
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * @param optimized the optimized to set
+     */
+    public void setOptimized(boolean optimized) {
+        this.optimized = optimized;
+    }
+
+    public void setOptimizedContents(byte[] optimizedContents) {
+        this.optimizedContents = optimizedContents;
+    }
+
+    /**
+     * @param optimizedSize the optimizedSize to set
+     */
+    public void setOptimizedSize(long optimizedSize) {
+        this.optimizedSize = optimizedSize;
+    }
+
+    /**
+     * @param originalSize the originalSize to set
+     */
+    public void setOriginalSize(long originalSize) {
+        this.originalSize = originalSize;
+    }
+
+    /**
+     * @param savings the savings to set
+     */
+    public void setSavings(double savings) {
+        this.savings = savings;
+    }
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerEventHandler.java b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerEventHandler.java
index 5d0364e..2ad4e11 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerEventHandler.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerEventHandler.java
@@ -47,56 +47,56 @@ import org.slf4j.LoggerFactory;
 @Designate(ocd = Config.class)
 public class FileOptimizerEventHandler implements EventHandler {
 
-	@ObjectClassDefinition(name = "%event.handler.name", description = "%event.handler.description", localization = "OSGI-INF/l10n/bundle")
-	public @interface Config {
-		@AttributeDefinition(name = "%event.handler.filter.name", description = "%event.handler.filter.description")
-		String event_filter() default "(&(resourceType=sling:File)(|(path=*.png)(path=*.jpg)))";
+    @ObjectClassDefinition(name = "%event.handler.name", description = "%event.handler.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+        @AttributeDefinition(name = "%event.handler.filter.name", description = "%event.handler.filter.description")
+        String event_filter() default "(&(resourceType=sling:File)(|(path=*.png)(path=*.jpg)))";
 
-		@AttributeDefinition(name = "%event.handler.topics.name", description = "%event.handler.topics.description")
-		String[] event_topics() default { SlingConstants.TOPIC_RESOURCE_ADDED, SlingConstants.TOPIC_RESOURCE_CHANGED };
-	}
+        @AttributeDefinition(name = "%event.handler.topics.name", description = "%event.handler.topics.description")
+        String[] event_topics() default { SlingConstants.TOPIC_RESOURCE_ADDED, SlingConstants.TOPIC_RESOURCE_CHANGED };
+    }
 
-	private static final Logger log = LoggerFactory.getLogger(FileOptimizerEventHandler.class);
+    private static final Logger log = LoggerFactory.getLogger(FileOptimizerEventHandler.class);
 
-	@Reference
-	private FileOptimizerService fileOptimizer;
+    @Reference
+    private FileOptimizerService fileOptimizer;
 
-	private ResourceResolver resourceResolver;
+    private ResourceResolver resourceResolver;
 
-	@Reference
-	private ResourceResolverFactory rrf;
+    @Reference
+    private ResourceResolverFactory rrf;
 
-	@Activate
-	@Modified
-	public void activate(Config config) throws LoginException {
-		deactivate();
-		resourceResolver = rrf.getServiceResourceResolver(null);
-	}
+    @Activate
+    @Modified
+    public void activate(Config config) throws LoginException {
+        deactivate();
+        resourceResolver = rrf.getServiceResourceResolver(null);
+    }
 
-	@Deactivate
-	public void deactivate() {
-		if (resourceResolver != null) {
-			resourceResolver.close();
-		}
-	}
+    @Deactivate
+    public void deactivate() {
+        if (resourceResolver != null) {
+            resourceResolver.close();
+        }
+    }
 
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
-	 */
-	@Override
-	public void handleEvent(Event event) {
-		String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
-		Resource fileResource = resourceResolver.getResource(path);
-		if (fileResource != null && fileOptimizer.canOptimize(fileResource)) {
-			try {
-				fileOptimizer.optimizeFile(fileResource, true);
-			} catch (IOException e) {
-				log.error("Exception saving optimized file", e);
-			}
-		}
-	}
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
+     */
+    @Override
+    public void handleEvent(Event event) {
+        String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
+        Resource fileResource = resourceResolver.getResource(path);
+        if (fileResource != null && fileOptimizer.canOptimize(fileResource)) {
+            try {
+                fileOptimizer.optimizeFile(fileResource, true);
+            } catch (IOException e) {
+                log.error("Exception saving optimized file", e);
+            }
+        }
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerServiceImpl.java b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerServiceImpl.java
index 4d5a2d6..3ffacee 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerServiceImpl.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerServiceImpl.java
@@ -68,214 +68,214 @@ import org.slf4j.LoggerFactory;
 @Designate(ocd = Config.class)
 public class FileOptimizerServiceImpl implements FileOptimizerService, ServiceListener {
 
-	@ObjectClassDefinition(name = "%file.optimizer.name", description = "%file.optimizer.description", localization = "OSGI-INF/l10n/bundle")
-	public @interface Config {
-
-		@AttributeDefinition(name = "%file.optimizer.hash.algorithm.name", description = "%file.optimizer.hash.algorithm.description")
-		String hashAlgorithm() default "MD5";
-	}
-
-	private static final Logger log = LoggerFactory.getLogger(FileOptimizerServiceImpl.class);
-
-	private BundleContext bundleContext;
-
-	private Config config;
-
-	private Map<String, List<ServiceReference<FileOptimizer>>> fileOptimizers = new HashMap<>();
-
-	@Activate
-	@Modified
-	public void activate(ComponentContext context, Config config) throws InvalidSyntaxException {
-		bundleContext = context.getBundleContext();
-		this.config = config;
-		this.rebuildOptimizerCache();
-		bundleContext.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + FileOptimizer.class.getName() + ")");
-	}
-
-	private void addOptimizer(Map<String, List<ServiceReference<FileOptimizer>>> tempCache, String metaType,
-			ServiceReference<FileOptimizer> ref) {
-		if (!tempCache.containsKey(metaType)) {
-			tempCache.put(metaType, new ArrayList<ServiceReference<FileOptimizer>>());
-		}
-		tempCache.get(metaType).add(ref);
-	}
-
-	private String calculateHash(byte[] bytes) {
-		MessageDigest messageDigest;
-		try {
-			messageDigest = MessageDigest.getInstance(config.hashAlgorithm());
-			messageDigest.reset();
-			messageDigest.update(bytes);
-			return Base64.encodeBase64String(messageDigest.digest());
-		} catch (NoSuchAlgorithmException e) {
-			log.error("Exception generating hash", e);
-		}
-		return null;
-	}
-
-	@Override
-	public boolean canOptimize(Resource fileResource) {
-		if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
-				&& fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
-			fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
-		}
-		OptimizedFile of = fileResource.adaptTo(OptimizedFile.class);
-		return of != null && !of.getDisabled() && fileOptimizers.containsKey(of.getMimeType())
-				&& !fileOptimizers.get(of.getMimeType()).isEmpty();
-	}
-
-	@Deactivate
-	public void deactivate(ComponentContext context) {
-		context.getBundleContext().removeServiceListener(this);
-	}
-
-	/**
-	 * @return the fileOptimizers
-	 */
-	public Map<String, List<ServiceReference<FileOptimizer>>> getFileOptimizers() {
-		return fileOptimizers;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * org.apache.sling.fileoptim.FileOptimizerService#getOptimizedContents(org.
-	 * apache.sling.api.resource.Resource)
-	 */
-	@Override
-	public OptimizationResult getOptimizedContents(Resource fileResource) throws IOException {
-		if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
-				&& fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
-			fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
-		}
-		OptimizationResult result = new OptimizationResult(fileResource);
-
-		OptimizedFile optim = fileResource.adaptTo(OptimizedFile.class);
-
-		boolean optimize = true;
-		byte[] original = IOUtils.toByteArray(optim.getContent());
-		if (StringUtils.isNotBlank(optim.getHash()) && optim.getHash().equals(calculateHash(original))) {
-			optimize = false;
-		}
-
-		if (optimize) {
-			doOptimize(fileResource, result, optim, original);
-		} else {
-			log.trace("Resource {} is already optimized", fileResource);
-		}
-		return result;
-	}
-
-	private void doOptimize(Resource fileResource, OptimizationResult result, OptimizedFile optim, byte[] original) {
-		log.debug("Optimizing file resource {}", fileResource);
-		List<ServiceReference<FileOptimizer>> optimizers = fileOptimizers.get(optim.getMimeType());
-		for (ServiceReference<FileOptimizer> ref : optimizers) {
-			FileOptimizer optimizer = bundleContext.getService(ref);
-			if (optimizer == null) {
-				log.warn("No service retrieved for service reference {}", ref);
-				continue;
-			}
-
-			byte[] optimized = optimizer.optimizeFile(original, optim.getMimeType());
-			if (optimized != null && optimized.length < original.length) {
-
-				double savings = 1.0 - ((double) optimized.length / (double) original.length);
-
-				log.debug("Optimized file with {} saving {}%", optimizer.getName(), Math.round(savings * 100));
-				result.setAlgorithm(optimizer.getName());
-				result.setSavings(savings);
-				result.setOptimized(true);
-				result.setOptimizedSize(optimized.length);
-				result.setOriginalSize(original.length);
-				result.setOptimizedContents(optimized);
-			} else {
-				log.debug("Optimizer {} was not able to optimize the file", optimizer.getName());
-			}
-		}
-	}
-
-	@Override
-	public boolean isOptimized(Resource fileResource) {
-
-		if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
-				&& fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
-			fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
-		}
-
-		OptimizedFile of = fileResource.adaptTo(OptimizedFile.class);
-		try {
-			String calculatedHash = calculateHash(IOUtils.toByteArray(of.getContent()));
-			log.debug("Comparing stored {} and calculated {} hashes", of.getHash(), calculatedHash);
-			return ObjectUtils.equals(of.getHash(), calculatedHash);
-		} catch (IOException e) {
-			log.error("Exception checking if file optimized, assuming false", e);
-			return false;
-		}
-	}
-
-	@Override
-	public OptimizationResult optimizeFile(Resource fileResource, boolean autoCommit) throws IOException {
-
-		OptimizationResult result = getOptimizedContents(fileResource);
-
-		ModifiableValueMap mvm = fileResource.adaptTo(ModifiableValueMap.class);
-
-		Set<String> mixins = new HashSet<>(Arrays.asList(mvm.get(JcrConstants.JCR_MIXINTYPES, new String[0])));
-		mixins.add(FileOptimizerConstants.MT_OPTIMIZED);
-		mvm.put(JcrConstants.JCR_MIXINTYPES, mixins.toArray(new String[] {}));
-
-		mvm.put(FileOptimizerConstants.PN_ALGORITHM, result.getAlgorithm());
-		mvm.put(FileOptimizerConstants.PN_HASH, calculateHash(result.getOptimizedContents()));
-		mvm.put(FileOptimizerConstants.PN_ORIGINAL, mvm.get(JcrConstants.JCR_DATA, InputStream.class));
-		mvm.put(FileOptimizerConstants.PN_SAVINGS, result.getSavings());
-
-		mvm.put(JcrConstants.JCR_DATA, new ByteArrayInputStream(result.getOptimizedContents()));
-
-		if (autoCommit) {
-			log.debug("Persisting changes...");
-			fileResource.getResourceResolver().commit();
-		}
-
-		return result;
-
-	}
-
-	private void rebuildOptimizerCache() {
-		log.debug("rebuildOptimizerCache");
-		Map<String, List<ServiceReference<FileOptimizer>>> tempCache = new HashMap<>();
-		Collection<ServiceReference<FileOptimizer>> references = null;
-		try {
-			references = bundleContext.getServiceReferences(FileOptimizer.class, null);
-		} catch (Exception e) {
-			log.error("Exception retrieving service references", e);
-		}
-		for (ServiceReference<FileOptimizer> ref : references) {
-			Object mimeType = ref.getProperty(FileOptimizerConstants.MIME_TYPE);
-			if (mimeType instanceof String[]) {
-				for (String mt : (String[]) mimeType) {
-					addOptimizer(tempCache, mt, ref);
-				}
-			} else if (mimeType != null) {
-				addOptimizer(tempCache, (String) mimeType, ref);
-			}
-		}
-		for (List<ServiceReference<FileOptimizer>> optList : tempCache.values()) {
-			Collections.sort(optList);
-		}
-		this.fileOptimizers = tempCache;
-	}
-
-	@Override
-	public void serviceChanged(ServiceEvent event) {
-		rebuildOptimizerCache();
-	}
-
-	/**
-	 * @param fileOptimizers the fileOptimizers to set
-	 */
-	public void setFileOptimizers(Map<String, List<ServiceReference<FileOptimizer>>> fileOptimizers) {
-		this.fileOptimizers = fileOptimizers;
-	}
+    @ObjectClassDefinition(name = "%file.optimizer.name", description = "%file.optimizer.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+
+        @AttributeDefinition(name = "%file.optimizer.hash.algorithm.name", description = "%file.optimizer.hash.algorithm.description")
+        String hashAlgorithm() default "MD5";
+    }
+
+    private static final Logger log = LoggerFactory.getLogger(FileOptimizerServiceImpl.class);
+
+    private BundleContext bundleContext;
+
+    private Config config;
+
+    private Map<String, List<ServiceReference<FileOptimizer>>> fileOptimizers = new HashMap<>();
+
+    @Activate
+    @Modified
+    public void activate(ComponentContext context, Config config) throws InvalidSyntaxException {
+        bundleContext = context.getBundleContext();
+        this.config = config;
+        this.rebuildOptimizerCache();
+        bundleContext.addServiceListener(this, "(" + Constants.OBJECTCLASS + "=" + FileOptimizer.class.getName() + ")");
+    }
+
+    private void addOptimizer(Map<String, List<ServiceReference<FileOptimizer>>> tempCache, String metaType,
+            ServiceReference<FileOptimizer> ref) {
+        if (!tempCache.containsKey(metaType)) {
+            tempCache.put(metaType, new ArrayList<ServiceReference<FileOptimizer>>());
+        }
+        tempCache.get(metaType).add(ref);
+    }
+
+    private String calculateHash(byte[] bytes) {
+        MessageDigest messageDigest;
+        try {
+            messageDigest = MessageDigest.getInstance(config.hashAlgorithm());
+            messageDigest.reset();
+            messageDigest.update(bytes);
+            return Base64.encodeBase64String(messageDigest.digest());
+        } catch (NoSuchAlgorithmException e) {
+            log.error("Exception generating hash", e);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean canOptimize(Resource fileResource) {
+        if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
+                && fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
+            fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
+        }
+        OptimizedFile of = fileResource.adaptTo(OptimizedFile.class);
+        return of != null && !of.getDisabled() && fileOptimizers.containsKey(of.getMimeType())
+                && !fileOptimizers.get(of.getMimeType()).isEmpty();
+    }
+
+    @Deactivate
+    public void deactivate(ComponentContext context) {
+        context.getBundleContext().removeServiceListener(this);
+    }
+
+    /**
+     * @return the fileOptimizers
+     */
+    public Map<String, List<ServiceReference<FileOptimizer>>> getFileOptimizers() {
+        return fileOptimizers;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * org.apache.sling.fileoptim.FileOptimizerService#getOptimizedContents(org.
+     * apache.sling.api.resource.Resource)
+     */
+    @Override
+    public OptimizationResult getOptimizedContents(Resource fileResource) throws IOException {
+        if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
+                && fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
+            fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
+        }
+        OptimizationResult result = new OptimizationResult(fileResource);
+
+        OptimizedFile optim = fileResource.adaptTo(OptimizedFile.class);
+
+        boolean optimize = true;
+        byte[] original = IOUtils.toByteArray(optim.getContent());
+        if (StringUtils.isNotBlank(optim.getHash()) && optim.getHash().equals(calculateHash(original))) {
+            optimize = false;
+        }
+
+        if (optimize) {
+            doOptimize(fileResource, result, optim, original);
+        } else {
+            log.trace("Resource {} is already optimized", fileResource);
+        }
+        return result;
+    }
+
+    private void doOptimize(Resource fileResource, OptimizationResult result, OptimizedFile optim, byte[] original) {
+        log.debug("Optimizing file resource {}", fileResource);
+        List<ServiceReference<FileOptimizer>> optimizers = fileOptimizers.get(optim.getMimeType());
+        for (ServiceReference<FileOptimizer> ref : optimizers) {
+            FileOptimizer optimizer = bundleContext.getService(ref);
+            if (optimizer == null) {
+                log.warn("No service retrieved for service reference {}", ref);
+                continue;
+            }
+
+            byte[] optimized = optimizer.optimizeFile(original, optim.getMimeType());
+            if (optimized != null && optimized.length < original.length) {
+
+                double savings = 1.0 - ((double) optimized.length / (double) original.length);
+
+                log.debug("Optimized file with {} saving {}%", optimizer.getName(), Math.round(savings * 100));
+                result.setAlgorithm(optimizer.getName());
+                result.setSavings(savings);
+                result.setOptimized(true);
+                result.setOptimizedSize(optimized.length);
+                result.setOriginalSize(original.length);
+                result.setOptimizedContents(optimized);
+            } else {
+                log.debug("Optimizer {} was not able to optimize the file", optimizer.getName());
+            }
+        }
+    }
+
+    @Override
+    public boolean isOptimized(Resource fileResource) {
+
+        if (!fileResource.getName().equals(JcrConstants.JCR_CONTENT)
+                && fileResource.getChild(JcrConstants.JCR_CONTENT) != null) {
+            fileResource = fileResource.getChild(JcrConstants.JCR_CONTENT);
+        }
+
+        OptimizedFile of = fileResource.adaptTo(OptimizedFile.class);
+        try {
+            String calculatedHash = calculateHash(IOUtils.toByteArray(of.getContent()));
+            log.debug("Comparing stored {} and calculated {} hashes", of.getHash(), calculatedHash);
+            return ObjectUtils.equals(of.getHash(), calculatedHash);
+        } catch (IOException e) {
+            log.error("Exception checking if file optimized, assuming false", e);
+            return false;
+        }
+    }
+
+    @Override
+    public OptimizationResult optimizeFile(Resource fileResource, boolean autoCommit) throws IOException {
+
+        OptimizationResult result = getOptimizedContents(fileResource);
+
+        ModifiableValueMap mvm = fileResource.adaptTo(ModifiableValueMap.class);
+
+        Set<String> mixins = new HashSet<>(Arrays.asList(mvm.get(JcrConstants.JCR_MIXINTYPES, new String[0])));
+        mixins.add(FileOptimizerConstants.MT_OPTIMIZED);
+        mvm.put(JcrConstants.JCR_MIXINTYPES, mixins.toArray(new String[] {}));
+
+        mvm.put(FileOptimizerConstants.PN_ALGORITHM, result.getAlgorithm());
+        mvm.put(FileOptimizerConstants.PN_HASH, calculateHash(result.getOptimizedContents()));
+        mvm.put(FileOptimizerConstants.PN_ORIGINAL, mvm.get(JcrConstants.JCR_DATA, InputStream.class));
+        mvm.put(FileOptimizerConstants.PN_SAVINGS, result.getSavings());
+
+        mvm.put(JcrConstants.JCR_DATA, new ByteArrayInputStream(result.getOptimizedContents()));
+
+        if (autoCommit) {
+            log.debug("Persisting changes...");
+            fileResource.getResourceResolver().commit();
+        }
+
+        return result;
+
+    }
+
+    private void rebuildOptimizerCache() {
+        log.debug("rebuildOptimizerCache");
+        Map<String, List<ServiceReference<FileOptimizer>>> tempCache = new HashMap<>();
+        Collection<ServiceReference<FileOptimizer>> references = null;
+        try {
+            references = bundleContext.getServiceReferences(FileOptimizer.class, null);
+        } catch (Exception e) {
+            log.error("Exception retrieving service references", e);
+        }
+        for (ServiceReference<FileOptimizer> ref : references) {
+            Object mimeType = ref.getProperty(FileOptimizerConstants.MIME_TYPE);
+            if (mimeType instanceof String[]) {
+                for (String mt : (String[]) mimeType) {
+                    addOptimizer(tempCache, mt, ref);
+                }
+            } else if (mimeType != null) {
+                addOptimizer(tempCache, (String) mimeType, ref);
+            }
+        }
+        for (List<ServiceReference<FileOptimizer>> optList : tempCache.values()) {
+            Collections.sort(optList);
+        }
+        this.fileOptimizers = tempCache;
+    }
+
+    @Override
+    public void serviceChanged(ServiceEvent event) {
+        rebuildOptimizerCache();
+    }
+
+    /**
+     * @param fileOptimizers the fileOptimizers to set
+     */
+    public void setFileOptimizers(Map<String, List<ServiceReference<FileOptimizer>>> fileOptimizers) {
+        this.fileOptimizers = fileOptimizers;
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerWebConsole.java b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerWebConsole.java
index ad62359..81be914 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerWebConsole.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/FileOptimizerWebConsole.java
@@ -41,56 +41,56 @@ import org.osgi.service.component.annotations.Reference;
  * Simple web console plugin for listing out the available optimizers
  */
 @Component(property = { Constants.SERVICE_DESCRIPTION + "=Web Console Plugin for Apache Sling File Optimizer",
-		Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
-		WebConsoleConstants.PLUGIN_LABEL + "=" + FileOptimizerWebConsole.CONSOLE_LABEL,
-		WebConsoleConstants.PLUGIN_TITLE + "=" + FileOptimizerWebConsole.CONSOLE_TITLE,
-		WebConsoleConstants.CONFIG_PRINTER_MODES + "=always",
-		WebConsoleConstants.PLUGIN_CATEGORY + "=Status" }, service = { Servlet.class })
+        Constants.SERVICE_VENDOR + "=The Apache Software Foundation",
+        WebConsoleConstants.PLUGIN_LABEL + "=" + FileOptimizerWebConsole.CONSOLE_LABEL,
+        WebConsoleConstants.PLUGIN_TITLE + "=" + FileOptimizerWebConsole.CONSOLE_TITLE,
+        WebConsoleConstants.CONFIG_PRINTER_MODES + "=always",
+        WebConsoleConstants.PLUGIN_CATEGORY + "=Status" }, service = { Servlet.class })
 public class FileOptimizerWebConsole extends AbstractWebConsolePlugin {
 
-	private static final long serialVersionUID = 7086113364871387281L;
-	public static final String CONSOLE_LABEL = "fileoptim";
-	public static final String CONSOLE_TITLE = "File Optimizer";
+    private static final long serialVersionUID = 7086113364871387281L;
+    public static final String CONSOLE_LABEL = "fileoptim";
+    public static final String CONSOLE_TITLE = "File Optimizer";
 
-	@Reference
-	private FileOptimizerService fileOptimizer;
+    @Reference
+    private FileOptimizerService fileOptimizer;
 
-	@Override
-	public String getTitle() {
-		return CONSOLE_TITLE;
-	}
+    @Override
+    public String getTitle() {
+        return CONSOLE_TITLE;
+    }
 
-	@Override
-	public String getLabel() {
-		return CONSOLE_LABEL;
-	}
+    @Override
+    public String getLabel() {
+        return CONSOLE_LABEL;
+    }
 
-	@Override
-	protected void renderContent(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
-			throws IOException {
-		PrintWriter pw = httpServletResponse.getWriter();
-		pw.println("<div id='content' class='ui-widget'><br>");
-		pw.println("<pre>");
-		pw.println("Available Optimizers");
-		pw.println("========================");
+    @Override
+    protected void renderContent(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
+            throws IOException {
+        PrintWriter pw = httpServletResponse.getWriter();
+        pw.println("<div id='content' class='ui-widget'><br>");
+        pw.println("<pre>");
+        pw.println("Available Optimizers");
+        pw.println("========================");
 
-		Map<String, List<ServiceReference<FileOptimizer>>> optimizerCache = ((FileOptimizerServiceImpl) fileOptimizer)
-				.getFileOptimizers();
+        Map<String, List<ServiceReference<FileOptimizer>>> optimizerCache = ((FileOptimizerServiceImpl) fileOptimizer)
+                .getFileOptimizers();
 
-		for (Entry<String, List<ServiceReference<FileOptimizer>>> to : optimizerCache.entrySet()) {
+        for (Entry<String, List<ServiceReference<FileOptimizer>>> to : optimizerCache.entrySet()) {
 
-			pw.println();
-			pw.println(to.getKey());
-			pw.println("-------------------------------------");
-			for (ServiceReference<FileOptimizer> fo : to.getValue()) {
+            pw.println();
+            pw.println(to.getKey());
+            pw.println("-------------------------------------");
+            for (ServiceReference<FileOptimizer> fo : to.getValue()) {
 
-				FileOptimizer o = this.getBundleContext().getService(fo);
+                FileOptimizer o = this.getBundleContext().getService(fo);
 
-				pw.println("- " + o.getName() + " (" + o.getClass().getName() + ")");
-			}
-		}
-		pw.println("</pre>");
-		pw.println("</div>");
-	}
+                pw.println("- " + o.getName() + " (" + o.getClass().getName() + ")");
+            }
+        }
+        pw.println("</pre>");
+        pw.println("</div>");
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/OptimizeFileOperation.java b/src/main/java/org/apache/sling/fileoptim/impl/OptimizeFileOperation.java
index 486bbad..334d642 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/OptimizeFileOperation.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/OptimizeFileOperation.java
@@ -41,62 +41,62 @@ import org.slf4j.LoggerFactory;
  * The File Optimization operation will optimize a file
  */
 @Component(immediate = true, service = { PostOperation.class }, property = PostOperation.PROP_OPERATION_NAME
-		+ "=fileoptim:optimize")
+        + "=fileoptim:optimize")
 public class OptimizeFileOperation implements PostOperation {
 
-	private static final Logger log = LoggerFactory.getLogger(OptimizeFileOperation.class);
+    private static final Logger log = LoggerFactory.getLogger(OptimizeFileOperation.class);
 
-	@Reference
-	private FileOptimizerService fileOptimizer;
+    @Reference
+    private FileOptimizerService fileOptimizer;
 
-	protected void doRun(SlingHttpServletRequest request, List<Modification> changes) throws IOException {
-		Resource resource = request.getResource();
+    protected void doRun(SlingHttpServletRequest request, List<Modification> changes) throws IOException {
+        Resource resource = request.getResource();
 
-		if (fileOptimizer.canOptimize(resource)) {
-			if (resource.getChild(JcrConstants.JCR_CONTENT) != null) {
-				resource = resource.getChild(JcrConstants.JCR_CONTENT);
-			}
-			fileOptimizer.optimizeFile(resource, true);
-			changes.add(Modification.onModified(resource.getPath()));
-		}
-	}
+        if (fileOptimizer.canOptimize(resource)) {
+            if (resource.getChild(JcrConstants.JCR_CONTENT) != null) {
+                resource = resource.getChild(JcrConstants.JCR_CONTENT);
+            }
+            fileOptimizer.optimizeFile(resource, true);
+            changes.add(Modification.onModified(resource.getPath()));
+        }
+    }
 
-	public void run(final SlingHttpServletRequest request, final PostResponse response,
-			final SlingPostProcessor[] processors) {
+    public void run(final SlingHttpServletRequest request, final PostResponse response,
+            final SlingPostProcessor[] processors) {
 
-		try {
-			// calculate the paths
-			String path = request.getResource().getPath();
-			response.setPath(path);
+        try {
+            // calculate the paths
+            String path = request.getResource().getPath();
+            response.setPath(path);
 
-			final List<Modification> changes = new ArrayList<>();
+            final List<Modification> changes = new ArrayList<>();
 
-			doRun(request, changes);
+            doRun(request, changes);
 
-			// invoke processors
-			if (processors != null) {
-				for (SlingPostProcessor processor : processors) {
-					processor.process(request, changes);
-				}
-			}
+            // invoke processors
+            if (processors != null) {
+                for (SlingPostProcessor processor : processors) {
+                    processor.process(request, changes);
+                }
+            }
 
-			// check modifications for remaining postfix and store the base path
-			final Map<String, String> modificationSourcesContainingPostfix = new HashMap<>();
-			final Set<String> allModificationSources = new HashSet<>(changes.size());
-			for (final Modification modification : changes) {
-				final String source = modification.getSource();
-				if (source != null) {
-					allModificationSources.add(source);
-					final int atIndex = source.indexOf('@');
-					if (atIndex > 0) {
-						modificationSourcesContainingPostfix.put(source.substring(0, atIndex), source);
-					}
-				}
-			}
-		} catch (Exception e) {
-			log.error("Exception during response processing.", e);
-			response.setError(e);
-		}
-	}
+            // check modifications for remaining postfix and store the base path
+            final Map<String, String> modificationSourcesContainingPostfix = new HashMap<>();
+            final Set<String> allModificationSources = new HashSet<>(changes.size());
+            for (final Modification modification : changes) {
+                final String source = modification.getSource();
+                if (source != null) {
+                    allModificationSources.add(source);
+                    final int atIndex = source.indexOf('@');
+                    if (atIndex > 0) {
+                        modificationSourcesContainingPostfix.put(source.substring(0, atIndex), source);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("Exception during response processing.", e);
+            response.setError(e);
+        }
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/RestoreOriginalOperation.java b/src/main/java/org/apache/sling/fileoptim/impl/RestoreOriginalOperation.java
index 99c0407..db63a75 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/RestoreOriginalOperation.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/RestoreOriginalOperation.java
@@ -44,66 +44,66 @@ import org.slf4j.LoggerFactory;
  * The File Optimization operation restore the original file
  */
 @Component(immediate = true, service = { PostOperation.class }, property = PostOperation.PROP_OPERATION_NAME
-		+ "=fileoptim:restore")
+        + "=fileoptim:restore")
 public class RestoreOriginalOperation implements PostOperation {
 
-	private static final Logger log = LoggerFactory.getLogger(RestoreOriginalOperation.class);
+    private static final Logger log = LoggerFactory.getLogger(RestoreOriginalOperation.class);
 
-	@Reference
-	private FileOptimizerService fileOptimizer;
+    @Reference
+    private FileOptimizerService fileOptimizer;
 
-	protected void doRun(SlingHttpServletRequest request, List<Modification> changes) throws IOException {
-		Resource resource = request.getResource();
-		if (fileOptimizer.isOptimized(resource)) {
-			ModifiableValueMap mvm = resource.getChild(JcrConstants.JCR_CONTENT).adaptTo(ModifiableValueMap.class);
-			mvm.put(JcrConstants.JCR_DATA, mvm.get(FileOptimizerConstants.PN_ORIGINAL, InputStream.class));
-			mvm.remove(FileOptimizerConstants.PN_ORIGINAL);
-			mvm.remove(FileOptimizerConstants.PN_ALGORITHM);
-			mvm.remove(FileOptimizerConstants.PN_HASH);
-			mvm.remove(FileOptimizerConstants.PN_SAVINGS);
+    protected void doRun(SlingHttpServletRequest request, List<Modification> changes) throws IOException {
+        Resource resource = request.getResource();
+        if (fileOptimizer.isOptimized(resource)) {
+            ModifiableValueMap mvm = resource.getChild(JcrConstants.JCR_CONTENT).adaptTo(ModifiableValueMap.class);
+            mvm.put(JcrConstants.JCR_DATA, mvm.get(FileOptimizerConstants.PN_ORIGINAL, InputStream.class));
+            mvm.remove(FileOptimizerConstants.PN_ORIGINAL);
+            mvm.remove(FileOptimizerConstants.PN_ALGORITHM);
+            mvm.remove(FileOptimizerConstants.PN_HASH);
+            mvm.remove(FileOptimizerConstants.PN_SAVINGS);
 
-			resource.getResourceResolver().commit();
+            resource.getResourceResolver().commit();
 
-			changes.add(Modification.onModified(resource.getPath()));
-		}
-	}
+            changes.add(Modification.onModified(resource.getPath()));
+        }
+    }
 
-	public void run(final SlingHttpServletRequest request, final PostResponse response,
-			final SlingPostProcessor[] processors) {
+    public void run(final SlingHttpServletRequest request, final PostResponse response,
+            final SlingPostProcessor[] processors) {
 
-		try {
-			// calculate the paths
-			String path = request.getResource().getPath();
-			response.setPath(path);
+        try {
+            // calculate the paths
+            String path = request.getResource().getPath();
+            response.setPath(path);
 
-			final List<Modification> changes = new ArrayList<>();
+            final List<Modification> changes = new ArrayList<>();
 
-			doRun(request, changes);
+            doRun(request, changes);
 
-			// invoke processors
-			if (processors != null) {
-				for (SlingPostProcessor processor : processors) {
-					processor.process(request, changes);
-				}
-			}
+            // invoke processors
+            if (processors != null) {
+                for (SlingPostProcessor processor : processors) {
+                    processor.process(request, changes);
+                }
+            }
 
-			// check modifications for remaining postfix and store the base path
-			final Map<String, String> modificationSourcesContainingPostfix = new HashMap<>();
-			final Set<String> allModificationSources = new HashSet<>(changes.size());
-			for (final Modification modification : changes) {
-				final String source = modification.getSource();
-				if (source != null) {
-					allModificationSources.add(source);
-					final int atIndex = source.indexOf('@');
-					if (atIndex > 0) {
-						modificationSourcesContainingPostfix.put(source.substring(0, atIndex), source);
-					}
-				}
-			}
-		} catch (Exception e) {
-			log.error("Exception during response processing.", e);
-			response.setError(e);
-		}
-	}
+            // check modifications for remaining postfix and store the base path
+            final Map<String, String> modificationSourcesContainingPostfix = new HashMap<>();
+            final Set<String> allModificationSources = new HashSet<>(changes.size());
+            for (final Modification modification : changes) {
+                final String source = modification.getSource();
+                if (source != null) {
+                    allModificationSources.add(source);
+                    final int atIndex = source.indexOf('@');
+                    if (atIndex > 0) {
+                        modificationSourcesContainingPostfix.put(source.substring(0, atIndex), source);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("Exception during response processing.", e);
+            response.setError(e);
+        }
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/filters/FileOptimizerFilter.java b/src/main/java/org/apache/sling/fileoptim/impl/filters/FileOptimizerFilter.java
index 35609a9..85eeb36 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/filters/FileOptimizerFilter.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/filters/FileOptimizerFilter.java
@@ -48,64 +48,64 @@ import org.slf4j.LoggerFactory;
  * Sling Servlet Filter for optimizing a file response.
  */
 @Component(service = { Filter.class }, property = { "sling.filter.scope="
-		+ EngineConstants.FILTER_SCOPE_REQUEST }, configurationPolicy = ConfigurationPolicy.REQUIRE)
+        + EngineConstants.FILTER_SCOPE_REQUEST }, configurationPolicy = ConfigurationPolicy.REQUIRE)
 @Designate(ocd = Config.class)
 public class FileOptimizerFilter implements Filter {
 
-	@ObjectClassDefinition(name = "%filter.name", description = "%filter.description", localization = "OSGI-INF/l10n/bundle")
-	public @interface Config {
+    @ObjectClassDefinition(name = "%filter.name", description = "%filter.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
 
-		@AttributeDefinition(name = "%filter.pattern.name", description = "%filter.pattern.description")
-		String sling_filter_pattern() default "-";
+        @AttributeDefinition(name = "%filter.pattern.name", description = "%filter.pattern.description")
+        String sling_filter_pattern() default "-";
 
-		@AttributeDefinition(name = "%filter.service.ranking.name", description = "%filter.service.ranking.name")
-		int service_ranking() default 0;
+        @AttributeDefinition(name = "%filter.service.ranking.name", description = "%filter.service.ranking.name")
+        int service_ranking() default 0;
 
-	}
+    }
 
-	private static final Logger log = LoggerFactory.getLogger(FileOptimizerFilter.class);
+    private static final Logger log = LoggerFactory.getLogger(FileOptimizerFilter.class);
 
-	@Reference
-	private FileOptimizerService fileOptimizer;
+    @Reference
+    private FileOptimizerService fileOptimizer;
 
-	@Override
-	public void init(FilterConfig filterConfig) throws ServletException {
-		// Nothing required
-	}
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // Nothing required
+    }
 
-	@Override
-	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-			throws IOException, ServletException {
-		if (request instanceof SlingHttpServletRequest) {
-			Resource resource = ((SlingHttpServletRequest) request).getResource();
-			try {
-				if (fileOptimizer.canOptimize(resource)) {
-					log.debug("Returning optimized file");
-					OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
-					if (res.isOptimized()) {
-						OptimizedFile of = null;
-						if (!resource.getName().equals(JcrConstants.JCR_CONTENT)) {
-							of = resource.getChild(JcrConstants.JCR_CONTENT).adaptTo(OptimizedFile.class);
-						} else {
-							of = resource.adaptTo(OptimizedFile.class);
-						}
-						response.setContentType(of.getMimeType());
-						response.setContentLengthLong(res.getOptimizedSize());
-						((HttpServletResponse) response).setHeader("Optimized-With", res.getAlgorithm());
-						IOUtils.copy(res.getOptimizedContentStream(), response.getOutputStream());
-						return;
-					}
-				}
-			} catch (Exception e) {
-				log.warn("Unexpected exception attempting to optimize file response", e);
-			}
-		}
-		chain.doFilter(request, response);
-	}
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException {
+        if (request instanceof SlingHttpServletRequest) {
+            Resource resource = ((SlingHttpServletRequest) request).getResource();
+            try {
+                if (fileOptimizer.canOptimize(resource)) {
+                    log.debug("Returning optimized file");
+                    OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
+                    if (res.isOptimized()) {
+                        OptimizedFile of = null;
+                        if (!resource.getName().equals(JcrConstants.JCR_CONTENT)) {
+                            of = resource.getChild(JcrConstants.JCR_CONTENT).adaptTo(OptimizedFile.class);
+                        } else {
+                            of = resource.adaptTo(OptimizedFile.class);
+                        }
+                        response.setContentType(of.getMimeType());
+                        response.setContentLengthLong(res.getOptimizedSize());
+                        ((HttpServletResponse) response).setHeader("Optimized-With", res.getAlgorithm());
+                        IOUtils.copy(res.getOptimizedContentStream(), response.getOutputStream());
+                        return;
+                    }
+                }
+            } catch (Exception e) {
+                log.warn("Unexpected exception attempting to optimize file response", e);
+            }
+        }
+        chain.doFilter(request, response);
+    }
 
-	@Override
-	public void destroy() {
-		// Nothing requireds
-	}
+    @Override
+    public void destroy() {
+        // Nothing requireds
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerData.java b/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerData.java
index 4a2bba2..23fc572 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerData.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerData.java
@@ -36,41 +36,41 @@ import org.osgi.service.component.annotations.Reference;
  * Servlet for displaying a preview of an optimized image.
  */
 @Component(service = { Servlet.class }, property = { "sling.servlet.paths=/system/fileoptim.json",
-		"sling.servlet.methods=GET" })
+        "sling.servlet.methods=GET" })
 public class FileOptimizerData extends SlingSafeMethodsServlet {
 
-	@Reference
-	private transient FileOptimizerService fileOptimizer;
+    @Reference
+    private transient FileOptimizerService fileOptimizer;
 
-	private static final long serialVersionUID = 8635343288414416865L;
+    private static final long serialVersionUID = 8635343288414416865L;
 
-	@Override
-	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
-			throws ServletException, IOException {
-		String path = request.getParameter("path");
+    @Override
+    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
+            throws ServletException, IOException {
+        String path = request.getParameter("path");
 
-		Resource resource = request.getResourceResolver().getResource(path);
+        Resource resource = request.getResourceResolver().getResource(path);
 
-		if (resource == null) {
-			response.sendError(404, "No Resource found at path " + path);
-		} else if (fileOptimizer.canOptimize(resource)) {
+        if (resource == null) {
+            response.sendError(404, "No Resource found at path " + path);
+        } else if (fileOptimizer.canOptimize(resource)) {
 
-			OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
-			response.setContentType("application/json");
+            OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
+            response.setContentType("application/json");
 
-			JsonGenerator json = Json.createGenerator(response.getWriter());
-			json.writeStartObject();
-			json.write("algorithm", res.getAlgorithm());
-			json.write("originalSize", res.getOriginalSize());
-			json.write("optimizedSize", res.getOptimizedSize());
-			json.write("optimized", res.isOptimized());
-			json.write("preview", "/system/fileoptim/preview?path=" + path);
-			json.write("savings", res.getSavings());
-			json.writeEnd();
-			json.close();
-			response.flushBuffer();
-		} else {
-			response.sendError(400, "Resource at path " + path + " is not a file or cannot be optimized");
-		}
-	}
+            JsonGenerator json = Json.createGenerator(response.getWriter());
+            json.writeStartObject();
+            json.write("algorithm", res.getAlgorithm());
+            json.write("originalSize", res.getOriginalSize());
+            json.write("optimizedSize", res.getOptimizedSize());
+            json.write("optimized", res.isOptimized());
+            json.write("preview", "/system/fileoptim/preview?path=" + path);
+            json.write("savings", res.getSavings());
+            json.writeEnd();
+            json.close();
+            response.flushBuffer();
+        } else {
+            response.sendError(400, "Resource at path " + path + " is not a file or cannot be optimized");
+        }
+    }
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerPreview.java b/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerPreview.java
index 9b2dc08..7055dc0 100644
--- a/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerPreview.java
+++ b/src/main/java/org/apache/sling/fileoptim/impl/servlets/FileOptimizerPreview.java
@@ -37,31 +37,31 @@ import org.osgi.service.component.annotations.Reference;
  * Servlet for displaying a preview of an optimized image.
  */
 @Component(service = Servlet.class, property = { "sling.servlet.paths=/system/fileoptim/preview",
-		"sling.servlet.methods=GET" }, immediate = true)
+        "sling.servlet.methods=GET" }, immediate = true)
 public class FileOptimizerPreview extends SlingSafeMethodsServlet {
 
-	@Reference
-	private transient FileOptimizerService fileOptimizer;
+    @Reference
+    private transient FileOptimizerService fileOptimizer;
 
-	private static final long serialVersionUID = 8635343288414416865L;
+    private static final long serialVersionUID = 8635343288414416865L;
 
-	@Override
-	protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
-			throws ServletException, IOException {
-		String path = request.getParameter("path");
+    @Override
+    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
+            throws ServletException, IOException {
+        String path = request.getParameter("path");
 
-		Resource resource = request.getResourceResolver().getResource(path);
+        Resource resource = request.getResourceResolver().getResource(path);
 
-		if (resource == null) {
-			response.sendError(404, "No Resource found at path " + path);
-		} else if (fileOptimizer.canOptimize(resource)) {
-			OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
-			ValueMap vm = res.getResource().getValueMap();
-			response.setContentType(vm.get(JcrConstants.JCR_MIMETYPE, String.class));
-			response.setHeader("Content-disposition", "inline; filename=" + resource.getName());
-			IOUtils.copy(res.getOptimizedContentStream(), response.getOutputStream());
-		} else {
-			response.sendError(400, "Resource at path " + path + " is not a file or cannot be optimized");
-		}
-	}
+        if (resource == null) {
+            response.sendError(404, "No Resource found at path " + path);
+        } else if (fileOptimizer.canOptimize(resource)) {
+            OptimizationResult res = fileOptimizer.getOptimizedContents(resource);
+            ValueMap vm = res.getResource().getValueMap();
+            response.setContentType(vm.get(JcrConstants.JCR_MIMETYPE, String.class));
+            response.setHeader("Content-disposition", "inline; filename=" + resource.getName());
+            IOUtils.copy(res.getOptimizedContentStream(), response.getOutputStream());
+        } else {
+            response.sendError(400, "Resource at path " + path + " is not a file or cannot be optimized");
+        }
+    }
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/optimizers/JpegFileOptimizer.java b/src/main/java/org/apache/sling/fileoptim/internal/optimizers/JpegFileOptimizer.java
similarity index 52%
rename from src/main/java/org/apache/sling/fileoptim/optimizers/JpegFileOptimizer.java
rename to src/main/java/org/apache/sling/fileoptim/internal/optimizers/JpegFileOptimizer.java
index c7702e2..aef1b23 100644
--- a/src/main/java/org/apache/sling/fileoptim/optimizers/JpegFileOptimizer.java
+++ b/src/main/java/org/apache/sling/fileoptim/internal/optimizers/JpegFileOptimizer.java
@@ -14,7 +14,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.sling.fileoptim.optimizers;
+package org.apache.sling.fileoptim.internal.optimizers;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -29,7 +29,7 @@ import javax.imageio.stream.MemoryCacheImageOutputStream;
 
 import org.apache.sling.fileoptim.FileOptimizer;
 import org.apache.sling.fileoptim.FileOptimizerConstants;
-import org.apache.sling.fileoptim.optimizers.JpegFileOptimizer.Config;
+import org.apache.sling.fileoptim.internal.optimizers.JpegFileOptimizer.Config;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Modified;
@@ -46,46 +46,46 @@ import org.slf4j.LoggerFactory;
 @Designate(ocd = Config.class)
 public class JpegFileOptimizer implements FileOptimizer {
 
-	private static final Logger log = LoggerFactory.getLogger(JpegFileOptimizer.class);
+    private static final Logger log = LoggerFactory.getLogger(JpegFileOptimizer.class);
 
-	@ObjectClassDefinition(name = "%jpeg.optimizer.name", description = "%jpeg.optimizer.description", localization = "OSGI-INF/l10n/bundle")
-	public @interface Config {
-		@AttributeDefinition(name = "%jpeg.optimizer.compression.level.name", description = "%jpeg.optimizer.compression.level.description")
-		float compressionLevel() default 0.8f;
-	}
+    @ObjectClassDefinition(name = "%jpeg.optimizer.name", description = "%jpeg.optimizer.description", localization = "OSGI-INF/l10n/bundle")
+    public @interface Config {
+        @AttributeDefinition(name = "%jpeg.optimizer.compression.level.name", description = "%jpeg.optimizer.compression.level.description")
+        float compressionLevel() default 0.8f;
+    }
 
-	private Config config;
+    private Config config;
 
-	@Activate
-	@Modified
-	public void activate(Config config) {
-		this.config = config;
-	}
+    @Activate
+    @Modified
+    public void activate(Config config) {
+        this.config = config;
+    }
 
-	@Override
-	public byte[] optimizeFile(byte[] original, String metaType) {
-		ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
-		ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
-		jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
-		jpgWriteParam.setCompressionQuality(config.compressionLevel());
+    @Override
+    public byte[] optimizeFile(byte[] original, String metaType) {
+        ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
+        ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
+        jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
+        jpgWriteParam.setCompressionQuality(config.compressionLevel());
 
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		ImageOutputStream outputStream = new MemoryCacheImageOutputStream(baos);
-		jpgWriter.setOutput(outputStream);
-		try {
-			IIOImage outputImage = new IIOImage(ImageIO.read(new ByteArrayInputStream(original)), null, null);
-			jpgWriter.write(null, outputImage, jpgWriteParam);
-			jpgWriter.dispose();
-			return baos.toByteArray();
-		} catch (IOException e) {
-			log.warn("Exception optimizing image", e);
-		}
-		return null;
-	}
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ImageOutputStream outputStream = new MemoryCacheImageOutputStream(baos);
+        jpgWriter.setOutput(outputStream);
+        try {
+            IIOImage outputImage = new IIOImage(ImageIO.read(new ByteArrayInputStream(original)), null, null);
+            jpgWriter.write(null, outputImage, jpgWriteParam);
+            jpgWriter.dispose();
+            return baos.toByteArray();
+        } catch (IOException e) {
+            log.warn("Exception optimizing image", e);
+        }
+        return null;
+    }
 
-	@Override
-	public String getName() {
-		return "Apache Sling JPEG File Optimizer";
-	}
+    @Override
+    public String getName() {
+        return "Apache Sling JPEG File Optimizer";
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/optimizers/PngFileOptimizer.java b/src/main/java/org/apache/sling/fileoptim/internal/optimizers/PngFileOptimizer.java
similarity index 64%
rename from src/main/java/org/apache/sling/fileoptim/optimizers/PngFileOptimizer.java
rename to src/main/java/org/apache/sling/fileoptim/internal/optimizers/PngFileOptimizer.java
index c7f23bf..146ade7 100644
--- a/src/main/java/org/apache/sling/fileoptim/optimizers/PngFileOptimizer.java
+++ b/src/main/java/org/apache/sling/fileoptim/internal/optimizers/PngFileOptimizer.java
@@ -14,7 +14,7 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.sling.fileoptim.optimizers;
+package org.apache.sling.fileoptim.internal.optimizers;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -35,30 +35,30 @@ import com.googlecode.pngtastic.core.PngOptimizer;
 @Component(service = FileOptimizer.class, property = { FileOptimizerConstants.MIME_TYPE + "=image/png" })
 public class PngFileOptimizer implements FileOptimizer {
 
-	private static final Logger log = LoggerFactory.getLogger(PngFileOptimizer.class);
+    private static final Logger log = LoggerFactory.getLogger(PngFileOptimizer.class);
 
-	@Override
-	public byte[] optimizeFile(byte[] original, String metaType) {
+    @Override
+    public byte[] optimizeFile(byte[] original, String metaType) {
 
-		PngOptimizer optimizer = new PngOptimizer();
+        PngOptimizer optimizer = new PngOptimizer();
 
-		PngImage image = new PngImage(new ByteArrayInputStream(original));
-		try {
-			PngImage optimized = optimizer.optimize(image);
+        PngImage image = new PngImage(new ByteArrayInputStream(original));
+        try {
+            PngImage optimized = optimizer.optimize(image);
 
-			ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			optimized.writeDataOutputStream(baos);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            optimized.writeDataOutputStream(baos);
 
-			return baos.toByteArray();
-		} catch (IOException e) {
-			log.warn("Exception optimizing PNG image", e);
-		}
-		return null;
-	}
+            return baos.toByteArray();
+        } catch (IOException e) {
+            log.warn("Exception optimizing PNG image", e);
+        }
+        return null;
+    }
 
-	@Override
-	public String getName() {
-		return "PNGTastic PNG Optimizer";
-	}
+    @Override
+    public String getName() {
+        return "PNGTastic PNG Optimizer";
+    }
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/models/OptimizeResource.java b/src/main/java/org/apache/sling/fileoptim/models/OptimizeResource.java
index d817393..530e840 100644
--- a/src/main/java/org/apache/sling/fileoptim/models/OptimizeResource.java
+++ b/src/main/java/org/apache/sling/fileoptim/models/OptimizeResource.java
@@ -25,6 +25,7 @@ import org.apache.sling.fileoptim.FileOptimizerService;
 import org.apache.sling.fileoptim.OptimizationResult;
 import org.apache.sling.models.annotations.Model;
 import org.apache.sling.models.annotations.injectorspecific.OSGiService;
+import org.osgi.annotation.versioning.ProviderType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,60 +33,61 @@ import org.slf4j.LoggerFactory;
  * Sling model for executing the optimizer on a resource, will not commit the
  * result
  */
+@ProviderType
 @Model(adaptables = Resource.class)
 public class OptimizeResource {
 
-	private static final Logger log = LoggerFactory.getLogger(OptimizeResource.class);
+    private static final Logger log = LoggerFactory.getLogger(OptimizeResource.class);
 
-	private boolean canOptimize;
+    private boolean canOptimize;
 
-	@OSGiService
-	private FileOptimizerService fileOptimizer;
+    @OSGiService
+    private FileOptimizerService fileOptimizer;
 
-	private OptimizationResult result;
+    private OptimizationResult result;
 
-	private Resource resource;
+    private Resource resource;
 
-	public OptimizeResource(Resource resource) {
-		this.resource = resource;
-	}
+    public OptimizeResource(Resource resource) {
+        this.resource = resource;
+    }
 
-	@PostConstruct
-	public void init() throws IOException {
-		log.debug("initializing with resource {}", resource);
-		if (fileOptimizer.canOptimize(resource)) {
-			this.canOptimize = true;
-			this.result = fileOptimizer.getOptimizedContents(resource);
-		} else {
-			this.canOptimize = false;
-			this.result = null;
-		}
-	}
+    @PostConstruct
+    public void init() throws IOException {
+        log.debug("initializing with resource {}", resource);
+        if (fileOptimizer.canOptimize(resource)) {
+            this.canOptimize = true;
+            this.result = fileOptimizer.getOptimizedContents(resource);
+        } else {
+            this.canOptimize = false;
+            this.result = null;
+        }
+    }
 
-	/**
-	 * Returns true if the file is optimized, false otherwise
-	 * 
-	 * @return
-	 */
-	public boolean isOptimized() {
-		return fileOptimizer.isOptimized(resource);
-	}
+    /**
+     * Returns true if the file is optimized, false otherwise
+     * 
+     * @return
+     */
+    public boolean isOptimized() {
+        return fileOptimizer.isOptimized(resource);
+    }
 
-	/**
-	 * Gets the optimization result.
-	 * 
-	 * @return
-	 */
-	public OptimizationResult getResult() {
-		return result;
-	}
+    /**
+     * Gets the optimization result.
+     * 
+     * @return
+     */
+    public OptimizationResult getResult() {
+        return result;
+    }
 
-	/**
-	 * Return true if the file can be optimized
-	 * 
-	 * @return
-	 */
-	public boolean isCanOptimize() {
-		return canOptimize;
-	}
+    /**
+     * Return true if the file can be optimized
+     * 
+     * @return
+     */
+    public boolean isCanOptimize() {
+        return canOptimize;
+    }
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/models/OptimizedFile.java b/src/main/java/org/apache/sling/fileoptim/models/OptimizedFile.java
index d209ad7..6b0ac6c 100644
--- a/src/main/java/org/apache/sling/fileoptim/models/OptimizedFile.java
+++ b/src/main/java/org/apache/sling/fileoptim/models/OptimizedFile.java
@@ -28,42 +28,44 @@ import org.apache.sling.models.annotations.Default;
 import org.apache.sling.models.annotations.DefaultInjectionStrategy;
 import org.apache.sling.models.annotations.Model;
 import org.apache.sling.models.annotations.Required;
+import org.osgi.annotation.versioning.ProviderType;
 
 /**
  * Sling Model representing a file which can be or has been optimized.
  */
+@ProviderType
 @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
 public interface OptimizedFile {
 
-	@Named(FileOptimizerConstants.PN_ALGORITHM)
-	@Inject
-	String getAlgorithm();
+    @Named(FileOptimizerConstants.PN_ALGORITHM)
+    @Inject
+    String getAlgorithm();
 
-	@Named(FileOptimizerConstants.PN_DISABLED)
-	@Inject
-	@Default(booleanValues = false)
-	boolean getDisabled();
+    @Named(FileOptimizerConstants.PN_DISABLED)
+    @Inject
+    @Default(booleanValues = false)
+    boolean getDisabled();
 
-	@Named(JcrConstants.JCR_DATA)
-	@Inject
-	@Required
-	InputStream getContent();
+    @Named(JcrConstants.JCR_DATA)
+    @Inject
+    @Required
+    InputStream getContent();
 
-	@Named(FileOptimizerConstants.PN_HASH)
-	@Inject
-	String getHash();
+    @Named(FileOptimizerConstants.PN_HASH)
+    @Inject
+    String getHash();
 
-	@Named(JcrConstants.JCR_MIMETYPE)
-	@Inject
-	@Required
-	String getMimeType();
+    @Named(JcrConstants.JCR_MIMETYPE)
+    @Inject
+    @Required
+    String getMimeType();
 
-	@Named(FileOptimizerConstants.PN_ORIGINAL)
-	@Inject
-	InputStream getOriginal();
+    @Named(FileOptimizerConstants.PN_ORIGINAL)
+    @Inject
+    InputStream getOriginal();
 
-	@Named(FileOptimizerConstants.PN_SAVINGS)
-	@Inject
-	double getSavings();
+    @Named(FileOptimizerConstants.PN_SAVINGS)
+    @Inject
+    double getSavings();
 
 }
diff --git a/src/main/java/org/apache/sling/fileoptim/models/package-info.java b/src/main/java/org/apache/sling/fileoptim/models/package-info.java
index af40c1d..75c9679 100644
--- a/src/main/java/org/apache/sling/fileoptim/models/package-info.java
+++ b/src/main/java/org/apache/sling/fileoptim/models/package-info.java
@@ -14,5 +14,5 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@org.osgi.annotation.versioning.Version("1.0.0")
+@org.osgi.annotation.versioning.Version("1.0.1")
 package org.apache.sling.fileoptim.models;
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/fileoptim/optimizers/package-info.java b/src/main/java/org/apache/sling/fileoptim/optimizers/package-info.java
deleted file mode 100644
index 631b918..0000000
--- a/src/main/java/org/apache/sling/fileoptim/optimizers/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.
- */
-@org.osgi.annotation.versioning.Version("1.0.0")
-package org.apache.sling.fileoptim.optimizers;
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/fileoptim/package-info.java b/src/main/java/org/apache/sling/fileoptim/package-info.java
index 36a43f9..a542da3 100644
--- a/src/main/java/org/apache/sling/fileoptim/package-info.java
+++ b/src/main/java/org/apache/sling/fileoptim/package-info.java
@@ -14,5 +14,5 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@org.osgi.annotation.versioning.Version("2.0.0")
+@org.osgi.annotation.versioning.Version("2.0.1")
 package org.apache.sling.fileoptim;
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/fileoptim/BaseFileOptimizerTest.java b/src/test/java/org/apache/sling/fileoptim/BaseFileOptimizerTest.java
index bef28fc..8843629 100644
--- a/src/test/java/org/apache/sling/fileoptim/BaseFileOptimizerTest.java
+++ b/src/test/java/org/apache/sling/fileoptim/BaseFileOptimizerTest.java
@@ -26,8 +26,8 @@ import java.util.Map;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.fileoptim.impl.FileOptimizerServiceImpl;
+import org.apache.sling.fileoptim.internal.optimizers.JpegFileOptimizer;
 import org.apache.sling.fileoptim.models.OptimizedFile;
-import org.apache.sling.fileoptim.optimizers.JpegFileOptimizer;
 import org.mockito.Mockito;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
@@ -38,119 +38,119 @@ import org.slf4j.LoggerFactory;
 
 public abstract class BaseFileOptimizerTest {
 
-	private static final Logger log = LoggerFactory.getLogger(BaseFileOptimizerTest.class);
-	public FileOptimizerServiceImpl fileOptimizerService;
-
-	private final Map<String, InputStream> FILES = new HashMap<String, InputStream>() {
-		private static final long serialVersionUID = 1L;
-		{
-			put("jpeg", BaseFileOptimizerTest.class.getClassLoader()
-					.getResourceAsStream("valentino-funghi-41239-unsplash.jpg"));
-			put("png", BaseFileOptimizerTest.class.getClassLoader()
-					.getResourceAsStream("Screen Shot 2018-05-29 at 4.17.20 PM.png"));
-		}
-	};
-
-	public BaseFileOptimizerTest() throws InvalidSyntaxException {
-		log.trace("BaseFileOptimizerTest()");
-		fileOptimizerService = new FileOptimizerServiceImpl();
-
-		// mock up the basic OSGi stuff
-		ComponentContext context = Mockito.mock(ComponentContext.class);
-		BundleContext bundleContext = Mockito.mock(BundleContext.class);
-		Mockito.when(context.getBundleContext()).thenReturn(bundleContext);
-
-		// allow for populating the service cache
-		@SuppressWarnings("unchecked")
-		ServiceReference<FileOptimizer> ref = Mockito.mock(ServiceReference.class);
-		Mockito.when(ref.getProperty(FileOptimizerConstants.MIME_TYPE)).thenReturn("image/jpeg");
-		Collection<ServiceReference<FileOptimizer>> references = new ArrayList<ServiceReference<FileOptimizer>>();
-		references.add(ref);
-		Mockito.when(bundleContext.getServiceReferences(FileOptimizer.class, null)).thenReturn(references);
-
-		// allow for retrieving the service
-		JpegFileOptimizer jpegFileOptimizer = new JpegFileOptimizer();
-		jpegFileOptimizer.activate(new org.apache.sling.fileoptim.optimizers.JpegFileOptimizer.Config() {
-			{
-			}
-
-			@Override
-			public Class<? extends Annotation> annotationType() {
-				// TODO Auto-generated method stub
-				return null;
-			}
-
-			@Override
-			public float compressionLevel() {
-				return 0.7f;
-			}
-		});
-		Mockito.when(bundleContext.getService(ref)).thenReturn(jpegFileOptimizer);
-
-		fileOptimizerService.activate(context, new org.apache.sling.fileoptim.impl.FileOptimizerServiceImpl.Config() {
-			public Class<? extends Annotation> annotationType() {
-				return null;
-			}
-
-			public String hashAlgorithm() {
-				return "MD5";
-			}
-		});
-
-	}
-
-	private Resource getValidFile(String type) {
-		Resource fileResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getName()).thenReturn("file." + type);
-
-		Resource contentResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
-
-		OptimizedFile of = Mockito.mock(OptimizedFile.class);
-		Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
-		Mockito.when(of.getHash()).thenReturn(null);
-		Mockito.when(of.getContent()).thenReturn(FILES.get(type));
-		Mockito.when(of.getDisabled()).thenReturn(false);
-		Mockito.when(of.getMimeType()).thenReturn("image/" + type);
-		return fileResource;
-	}
-
-	public Resource getOptimizedFile() {
-		Resource fileResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getName()).thenReturn("file.png");
-
-		Resource contentResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
-
-		OptimizedFile of = Mockito.mock(OptimizedFile.class);
-		Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
-		Mockito.when(of.getHash()).thenReturn(null);
-		Mockito.when(of.getContent()).thenReturn(FILES.get("png"));
-		Mockito.when(of.getDisabled()).thenReturn(false);
-		Mockito.when(of.getMimeType()).thenReturn("image/png");
-		Mockito.when(of.getHash()).thenReturn("M8SdtVLx2VXMDtteUPLVkQ==");
-		return fileResource;
-	}
-
-	public Resource getDisabled() {
-		Resource fileResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getName()).thenReturn("file.jpg");
-
-		Resource contentResource = Mockito.mock(Resource.class);
-		Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
-
-		OptimizedFile of = Mockito.mock(OptimizedFile.class);
-		Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
-		Mockito.when(of.getDisabled()).thenReturn(true);
-		Mockito.when(of.getMimeType()).thenReturn("image/jpeg");
-		return fileResource;
-	}
-
-	public Resource getValidJpegFile() {
-		return getValidFile("jpeg");
-	}
-
-	public Resource getValidPngFile() {
-		return getValidFile("png");
-	}
+    private static final Logger log = LoggerFactory.getLogger(BaseFileOptimizerTest.class);
+    public FileOptimizerServiceImpl fileOptimizerService;
+
+    private final Map<String, InputStream> FILES = new HashMap<String, InputStream>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put("jpeg", BaseFileOptimizerTest.class.getClassLoader()
+                    .getResourceAsStream("valentino-funghi-41239-unsplash.jpg"));
+            put("png", BaseFileOptimizerTest.class.getClassLoader()
+                    .getResourceAsStream("Screen Shot 2018-05-29 at 4.17.20 PM.png"));
+        }
+    };
+
+    public BaseFileOptimizerTest() throws InvalidSyntaxException {
+        log.trace("BaseFileOptimizerTest()");
+        fileOptimizerService = new FileOptimizerServiceImpl();
+
+        // mock up the basic OSGi stuff
+        ComponentContext context = Mockito.mock(ComponentContext.class);
+        BundleContext bundleContext = Mockito.mock(BundleContext.class);
+        Mockito.when(context.getBundleContext()).thenReturn(bundleContext);
+
+        // allow for populating the service cache
+        @SuppressWarnings("unchecked")
+        ServiceReference<FileOptimizer> ref = Mockito.mock(ServiceReference.class);
+        Mockito.when(ref.getProperty(FileOptimizerConstants.MIME_TYPE)).thenReturn("image/jpeg");
+        Collection<ServiceReference<FileOptimizer>> references = new ArrayList<ServiceReference<FileOptimizer>>();
+        references.add(ref);
+        Mockito.when(bundleContext.getServiceReferences(FileOptimizer.class, null)).thenReturn(references);
+
+        // allow for retrieving the service
+        JpegFileOptimizer jpegFileOptimizer = new JpegFileOptimizer();
+        jpegFileOptimizer.activate(new org.apache.sling.fileoptim.internal.optimizers.JpegFileOptimizer.Config() {
+            {
+            }
+
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                // TODO Auto-generated method stub
+                return null;
+            }
+
+            @Override
+            public float compressionLevel() {
+                return 0.7f;
+            }
+        });
+        Mockito.when(bundleContext.getService(ref)).thenReturn(jpegFileOptimizer);
+
+        fileOptimizerService.activate(context, new org.apache.sling.fileoptim.impl.FileOptimizerServiceImpl.Config() {
+            public Class<? extends Annotation> annotationType() {
+                return null;
+            }
+
+            public String hashAlgorithm() {
+                return "MD5";
+            }
+        });
+
+    }
+
+    private Resource getValidFile(String type) {
+        Resource fileResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getName()).thenReturn("file." + type);
+
+        Resource contentResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
+
+        OptimizedFile of = Mockito.mock(OptimizedFile.class);
+        Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
+        Mockito.when(of.getHash()).thenReturn(null);
+        Mockito.when(of.getContent()).thenReturn(FILES.get(type));
+        Mockito.when(of.getDisabled()).thenReturn(false);
+        Mockito.when(of.getMimeType()).thenReturn("image/" + type);
+        return fileResource;
+    }
+
+    public Resource getOptimizedFile() {
+        Resource fileResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getName()).thenReturn("file.png");
+
+        Resource contentResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
+
+        OptimizedFile of = Mockito.mock(OptimizedFile.class);
+        Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
+        Mockito.when(of.getHash()).thenReturn(null);
+        Mockito.when(of.getContent()).thenReturn(FILES.get("png"));
+        Mockito.when(of.getDisabled()).thenReturn(false);
+        Mockito.when(of.getMimeType()).thenReturn("image/png");
+        Mockito.when(of.getHash()).thenReturn("M8SdtVLx2VXMDtteUPLVkQ==");
+        return fileResource;
+    }
+
+    public Resource getDisabled() {
+        Resource fileResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getName()).thenReturn("file.jpg");
+
+        Resource contentResource = Mockito.mock(Resource.class);
+        Mockito.when(fileResource.getChild(JcrConstants.JCR_CONTENT)).thenReturn(contentResource);
+
+        OptimizedFile of = Mockito.mock(OptimizedFile.class);
+        Mockito.when(contentResource.adaptTo(OptimizedFile.class)).thenReturn(of);
+        Mockito.when(of.getDisabled()).thenReturn(true);
+        Mockito.when(of.getMimeType()).thenReturn("image/jpeg");
+        return fileResource;
+    }
+
+    public Resource getValidJpegFile() {
+        return getValidFile("jpeg");
+    }
+
+    public Resource getValidPngFile() {
+        return getValidFile("png");
+    }
 }
diff --git a/src/test/java/org/apache/sling/fileoptim/impl/TestFileOptimizer.java b/src/test/java/org/apache/sling/fileoptim/impl/TestFileOptimizer.java
index 92098b2..1b42dfb 100644
--- a/src/test/java/org/apache/sling/fileoptim/impl/TestFileOptimizer.java
+++ b/src/test/java/org/apache/sling/fileoptim/impl/TestFileOptimizer.java
@@ -32,46 +32,45 @@ import org.slf4j.LoggerFactory;
 
 public class TestFileOptimizer extends BaseFileOptimizerTest {
 
-	public TestFileOptimizer() throws InvalidSyntaxException {
-		super();
-	}
+    public TestFileOptimizer() throws InvalidSyntaxException {
+        super();
+    }
 
-	private static Logger log = LoggerFactory.getLogger(TestFileOptimizer.class);
+    private static Logger log = LoggerFactory.getLogger(TestFileOptimizer.class);
 
-	@Test
-	public void testCanOptimize() {
-		log.info("testCanOptimize");
-		assertTrue(fileOptimizerService.canOptimize(getValidJpegFile()));
-	}
+    @Test
+    public void testCanOptimize() {
+        log.info("testCanOptimize");
+        assertTrue(fileOptimizerService.canOptimize(getValidJpegFile()));
+    }
 
-	@Test
-	public void testCantOptimize() {
-		log.info("testCantOptimize");
-		assertFalse(fileOptimizerService.canOptimize(getValidPngFile()));
-	}
+    @Test
+    public void testCantOptimize() {
+        log.info("testCantOptimize");
+        assertFalse(fileOptimizerService.canOptimize(getValidPngFile()));
+    }
 
-	@Test
-	public void testDisabled() {
-		log.info("testDisabled");
-		assertFalse(fileOptimizerService.canOptimize(getDisabled()));
-	}
-	
+    @Test
+    public void testDisabled() {
+        log.info("testDisabled");
+        assertFalse(fileOptimizerService.canOptimize(getDisabled()));
+    }
 
-	@Test
-	public void isOptimized() {
-		log.info("isOptimized");
-		assertTrue(fileOptimizerService.isOptimized(super.getOptimizedFile()));
-	}
+    @Test
+    public void isOptimized() {
+        log.info("isOptimized");
+        assertTrue(fileOptimizerService.isOptimized(super.getOptimizedFile()));
+    }
 
-	@Test
-	public void testGetOptimizedContents() throws IOException {
-		log.info("testGetOptimizedContents");
-		OptimizationResult res = fileOptimizerService.getOptimizedContents(getValidJpegFile());
-		assertNotNull(res);
-		assertTrue(res.isOptimized());
-		assertNotNull(res.getOptimizedContents());
-		assertEquals(res.getOptimizedContents().length, res.getOptimizedSize());
-		assertTrue(res.getSavings() > 0.0 && res.getSavings() < 1.0);
-	}
+    @Test
+    public void testGetOptimizedContents() throws IOException {
+        log.info("testGetOptimizedContents");
+        OptimizationResult res = fileOptimizerService.getOptimizedContents(getValidJpegFile());
+        assertNotNull(res);
+        assertTrue(res.isOptimized());
+        assertNotNull(res.getOptimizedContents());
+        assertEquals(res.getOptimizedContents().length, res.getOptimizedSize());
+        assertTrue(res.getSavings() > 0.0 && res.getSavings() < 1.0);
+    }
 
 }
diff --git a/src/test/java/org/apache/sling/fileoptim/impl/servlets/TestFileOptimizerData.java b/src/test/java/org/apache/sling/fileoptim/impl/servlets/TestFileOptimizerData.java
index c39a22a..68743cc 100644
--- a/src/test/java/org/apache/sling/fileoptim/impl/servlets/TestFileOptimizerData.java
+++ b/src/test/java/org/apache/sling/fileoptim/impl/servlets/TestFileOptimizerData.java
@@ -39,47 +39,47 @@ import org.slf4j.LoggerFactory;
 
 public class TestFileOptimizerData extends BaseFileOptimizerTest {
 
-	public TestFileOptimizerData() throws InvalidSyntaxException {
-		super();
-		log.trace("TestFileOptimizerData()");
-	}
+    public TestFileOptimizerData() throws InvalidSyntaxException {
+        super();
+        log.trace("TestFileOptimizerData()");
+    }
 
-	private static final Logger log = LoggerFactory.getLogger(TestFileOptimizerData.class);
-	private static final String PATH = "/content/file.jpg";
-	private StringWriter writer;
-	private SlingHttpServletRequest request;
-	private SlingHttpServletResponse response;
-	private FileOptimizerData servlet;
+    private static final Logger log = LoggerFactory.getLogger(TestFileOptimizerData.class);
+    private static final String PATH = "/content/file.jpg";
+    private StringWriter writer;
+    private SlingHttpServletRequest request;
+    private SlingHttpServletResponse response;
+    private FileOptimizerData servlet;
 
-	@Before
-	public void initTest() throws IOException, NoSuchFieldException, SecurityException, IllegalArgumentException,
-			IllegalAccessException {
-		log.trace("initTest");
-		request = Mockito.mock(SlingHttpServletRequest.class);
-		Mockito.when(request.getParameter("path")).thenReturn(PATH);
-		ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
-		Mockito.when(request.getResourceResolver()).thenReturn(resolver);
-		Resource jpegResource = getValidJpegFile();
-		Mockito.when(resolver.getResource(PATH)).thenReturn(jpegResource);
+    @Before
+    public void initTest() throws IOException, NoSuchFieldException, SecurityException, IllegalArgumentException,
+            IllegalAccessException {
+        log.trace("initTest");
+        request = Mockito.mock(SlingHttpServletRequest.class);
+        Mockito.when(request.getParameter("path")).thenReturn(PATH);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        Mockito.when(request.getResourceResolver()).thenReturn(resolver);
+        Resource jpegResource = getValidJpegFile();
+        Mockito.when(resolver.getResource(PATH)).thenReturn(jpegResource);
 
-		this.writer = new StringWriter();
-		response = Mockito.mock(SlingHttpServletResponse.class);
-		Mockito.when(response.getWriter()).thenReturn(new PrintWriter(writer));
+        this.writer = new StringWriter();
+        response = Mockito.mock(SlingHttpServletResponse.class);
+        Mockito.when(response.getWriter()).thenReturn(new PrintWriter(writer));
 
-		servlet = new FileOptimizerData();
-		Field fo = FileOptimizerData.class.getDeclaredField("fileOptimizer");
-		fo.setAccessible(true);
-		fo.set(servlet, this.fileOptimizerService);
-	}
+        servlet = new FileOptimizerData();
+        Field fo = FileOptimizerData.class.getDeclaredField("fileOptimizer");
+        fo.setAccessible(true);
+        fo.set(servlet, this.fileOptimizerService);
+    }
 
-	@Test
-	public void testServlet() throws ServletException, IOException {
+    @Test
+    public void testServlet() throws ServletException, IOException {
 
-		servlet.doGet(request, response);
+        servlet.doGet(request, response);
 
-		String response = writer.toString();
-		assertNotNull(response);
-		log.info(response);
-		
-	}
+        String response = writer.toString();
+        assertNotNull(response);
+        log.info(response);
+
+    }
 }
diff --git a/src/test/java/org/apache/sling/fileoptim/optimizers/TestJPGFileOptimizer.java b/src/test/java/org/apache/sling/fileoptim/optimizers/TestJPGFileOptimizer.java
index 0264093..76dab1f 100644
--- a/src/test/java/org/apache/sling/fileoptim/optimizers/TestJPGFileOptimizer.java
+++ b/src/test/java/org/apache/sling/fileoptim/optimizers/TestJPGFileOptimizer.java
@@ -24,8 +24,8 @@ import java.io.IOException;
 import java.lang.annotation.Annotation;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.sling.fileoptim.optimizers.JpegFileOptimizer;
-import org.apache.sling.fileoptim.optimizers.JpegFileOptimizer.Config;
+import org.apache.sling.fileoptim.internal.optimizers.JpegFileOptimizer;
+import org.apache.sling.fileoptim.internal.optimizers.JpegFileOptimizer.Config;
 import org.junit.Before;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -33,44 +33,44 @@ import org.slf4j.LoggerFactory;
 
 public class TestJPGFileOptimizer {
 
-	private JpegFileOptimizer optimizer = new JpegFileOptimizer();
+    private JpegFileOptimizer optimizer = new JpegFileOptimizer();
 
-	private static final Logger log = LoggerFactory.getLogger(TestJPGFileOptimizer.class);
+    private static final Logger log = LoggerFactory.getLogger(TestJPGFileOptimizer.class);
 
-	@Before
-	public void init() {
+    @Before
+    public void init() {
 
-		Config config = new Config() {
-			{
-			}
+        Config config = new Config() {
+            {
+            }
 
-			@Override
-			public Class<? extends Annotation> annotationType() {
-				return null;
-			}
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return null;
+            }
 
-			@Override
-			public float compressionLevel() {
-				return 0.75f;
-			}
-		};
-		optimizer.activate(config);
-	}
+            @Override
+            public float compressionLevel() {
+                return 0.75f;
+            }
+        };
+        optimizer.activate(config);
+    }
 
-	@Test
-	public void testOptimizer() throws IOException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		IOUtils.copy(getClass().getClassLoader().getResourceAsStream("valentino-funghi-41239-unsplash.jpg"), baos);
-		byte[] optimized = optimizer.optimizeFile(baos.toByteArray(), "image/jpeg");
+    @Test
+    public void testOptimizer() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IOUtils.copy(getClass().getClassLoader().getResourceAsStream("valentino-funghi-41239-unsplash.jpg"), baos);
+        byte[] optimized = optimizer.optimizeFile(baos.toByteArray(), "image/jpeg");
 
-		assertTrue(baos.toByteArray().length > optimized.length);
+        assertTrue(baos.toByteArray().length > optimized.length);
 
-		log.info("Original size: {}", baos.toByteArray().length);
-		log.info("Optimized size: {}", optimized.length);
+        log.info("Original size: {}", baos.toByteArray().length);
+        log.info("Optimized size: {}", optimized.length);
 
-		double savings = 1.0 - ((double) optimized.length / (double) baos.toByteArray().length);
-		log.info("Compressed by {}%", Math.round(savings * 100.0));
-		
-		IOUtils.write(optimized, new FileOutputStream("target/optimized.jpg"));
-	}
+        double savings = 1.0 - ((double) optimized.length / (double) baos.toByteArray().length);
+        log.info("Compressed by {}%", Math.round(savings * 100.0));
+
+        IOUtils.write(optimized, new FileOutputStream("target/optimized.jpg"));
+    }
 }
diff --git a/src/test/java/org/apache/sling/fileoptim/optimizers/TestPngFileOptimizer.java b/src/test/java/org/apache/sling/fileoptim/optimizers/TestPngFileOptimizer.java
index 44278c1..721d239 100644
--- a/src/test/java/org/apache/sling/fileoptim/optimizers/TestPngFileOptimizer.java
+++ b/src/test/java/org/apache/sling/fileoptim/optimizers/TestPngFileOptimizer.java
@@ -23,31 +23,31 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.sling.fileoptim.optimizers.PngFileOptimizer;
+import org.apache.sling.fileoptim.internal.optimizers.PngFileOptimizer;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class TestPngFileOptimizer {
 
-	private PngFileOptimizer optimizer = new PngFileOptimizer();
+    private PngFileOptimizer optimizer = new PngFileOptimizer();
 
-	private static final Logger log = LoggerFactory.getLogger(TestPngFileOptimizer.class);
+    private static final Logger log = LoggerFactory.getLogger(TestPngFileOptimizer.class);
 
-	@Test
-	public void testOptimizer() throws IOException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		IOUtils.copy(getClass().getClassLoader().getResourceAsStream("Screen Shot 2018-05-29 at 4.17.20 PM.png"), baos);
-		byte[] optimized = optimizer.optimizeFile(baos.toByteArray(), "image/png");
+    @Test
+    public void testOptimizer() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        IOUtils.copy(getClass().getClassLoader().getResourceAsStream("Screen Shot 2018-05-29 at 4.17.20 PM.png"), baos);
+        byte[] optimized = optimizer.optimizeFile(baos.toByteArray(), "image/png");
 
-		assertTrue(baos.toByteArray().length > optimized.length);
+        assertTrue(baos.toByteArray().length > optimized.length);
 
-		log.info("Original size: {}", baos.toByteArray().length);
-		log.info("Optimized size: {}", optimized.length);
+        log.info("Original size: {}", baos.toByteArray().length);
+        log.info("Optimized size: {}", optimized.length);
 
-		double savings = 1.0 - ((double) optimized.length / (double) baos.toByteArray().length);
-		log.info("Compressed by {}%", Math.round(savings * 100.0));
+        double savings = 1.0 - ((double) optimized.length / (double) baos.toByteArray().length);
+        log.info("Compressed by {}%", Math.round(savings * 100.0));
 
-		IOUtils.write(optimized, new FileOutputStream("target/optimized.png"));
-	}
+        IOUtils.write(optimized, new FileOutputStream("target/optimized.png"));
+    }
 }