Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First steps to add encoding capability to outbound traffic #73

Merged
merged 37 commits into from
Feb 28, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
72801bf
Force Charset specification for strings
nicolas-rempulski Jan 13, 2014
f401002
Add ContentEncoder interface
nicolas-rempulski Jan 13, 2014
d773dc2
Add content encoders for wisdom
nicolas-rempulski Jan 13, 2014
c1ab9d3
Add EncodingNames with constants for encoding methods
nicolas-rempulski Jan 13, 2014
08857c7
Add ContentEncoder methods to ContentEngine
nicolas-rempulski Jan 13, 2014
a6e0ed7
Add a configuration key to enable / disable encoding globally
nicolas-rempulski Jan 13, 2014
a696344
Adding EncodingHelper
nicolas-rempulski Jan 13, 2014
2532659
Add encoding handling to the result processing
nicolas-rempulski Jan 13, 2014
062cc9a
RenderableString.render was not passing UT
nicolas-rempulski Jan 14, 2014
31b5999
Add @AllowEncoding and @DenyEncoding
nicolas-rempulski Jan 14, 2014
13883e4
Refactor process to decide whether to encode response content or not
nicolas-rempulski Jan 14, 2014
517c9ea
add size fields on @AllowEncoding annotations
nicolas-rempulski Jan 14, 2014
f885c8f
Add configuration keys encoding upper and lower boundaries + default …
nicolas-rempulski Jan 14, 2014
331b2a5
Adding size computation to shouldEncode
nicolas-rempulski Jan 14, 2014
10db476
Refactoring encoders to codecs
nicolas-rempulski Jan 15, 2014
6520fdd
Adding unit tests for codecs
nicolas-rempulski Jan 15, 2014
5abf514
Finalizing encoders to codecs refactoring
nicolas-rempulski Jan 15, 2014
edfff79
Codecs refactoring
nicolas-rempulski Jan 15, 2014
845eccb
Refactoring shouldEncode
nicolas-rempulski Jan 15, 2014
6a77954
Refactoring shouldEncode and parseAcceptEncodingHeader
nicolas-rempulski Jan 15, 2014
9b0641e
Adding documentation for content encoding
nicolas-rempulski Jan 15, 2014
8e8cea6
Fix documentation
nicolas-rempulski Jan 15, 2014
d16c8a3
Add configuration values for encoding
nicolas-rempulski Jan 16, 2014
fa7a06a
Refactor shouldEncode do handle stream
nicolas-rempulski Jan 16, 2014
b5bd947
Add functions to handle Long properties
nicolas-rempulski Jan 21, 2014
6585624
Finalize the refactoring of ContentEncoder to ContentCodec
nicolas-rempulski Jan 21, 2014
287e1dd
Add already compressed MimeTypes
nicolas-rempulski Jan 21, 2014
6690ed3
ContentEncodingHelper refactoring
nicolas-rempulski Jan 22, 2014
8543a01
Add filtering of already encoded content
nicolas-rempulski Jan 22, 2014
e9c02d8
Refactor @AllowEncoding annotation to use long instead of int
nicolas-rempulski Jan 23, 2014
fb7193b
Add ContentEncodingHelperImpl UT
nicolas-rempulski Jan 23, 2014
a817c1c
Update documentation to match latest changes
nicolas-rempulski Jan 23, 2014
d047644
Refactor AkkaBootstrap to handle multiple Callable types
nicolas-rempulski Jan 23, 2014
4d916ae
return writeResponse results as it can holds Async informations
nicolas-rempulski Jan 23, 2014
96ab1d6
Refactor WisdomHandler to handle asynchronous content encoding
nicolas-rempulski Jan 23, 2014
caea421
Merge branch 'refs/heads/master' into encoding-implem
nicolas-rempulski Jan 30, 2014
45447e0
Merge branch 'refs/heads/master' into encoding-implem
nicolas-rempulski Feb 27, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions akka-system/src/main/java/org/wisdom/akka/AkkaSystemService.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package org.wisdom.akka;

import akka.actor.ActorSystem;
import java.io.InputStream;
import java.util.concurrent.Callable;

import org.wisdom.api.http.Context;
import org.wisdom.api.http.Result;

import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;

import java.util.concurrent.Callable;
import akka.actor.ActorSystem;

/**
* A service to access the wisdom actor system and ease the dispatching of task.
Expand All @@ -24,15 +26,17 @@ public interface AkkaSystemService {
* @param context the context
* @return the future
*/
Future<Result> dispatch(Callable<Result> callable, Context context);
Future<Result> dispatchResultWithContext(Callable<Result> callable, Context context);

/**
* Dispatches the given task using an execution context preserving the current HTTP Context and the thread context
* classloader.
* @param callable the classloader
* @return the future
*/
Future<Result> dispatch(Callable<Result> callable);
Future<Result> dispatchResult(Callable<Result> callable);

Future<InputStream> dispatchInputStream(Callable<InputStream> callable);

/**
* Dispatches the given task. The task is executed using the given execution context.
Expand Down
29 changes: 22 additions & 7 deletions akka-system/src/main/java/org/wisdom/akka/impl/AkkaBootstrap.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package org.wisdom.akka.impl;

import akka.actor.ActorSystem;
import akka.osgi.OsgiActorSystemFactory;
import com.typesafe.config.ConfigFactory;
import org.apache.felix.ipojo.annotations.*;
import java.io.InputStream;
import java.util.concurrent.Callable;

import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Validate;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.wisdom.akka.AkkaSystemService;
import org.wisdom.api.http.Context;
import org.wisdom.api.http.Result;

import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;
import akka.actor.ActorSystem;
import akka.osgi.OsgiActorSystemFactory;

import java.util.concurrent.Callable;
import com.typesafe.config.ConfigFactory;

@Component
@Provides
Expand Down Expand Up @@ -56,13 +63,21 @@ public ActorSystem system() {
}

@Override
public Future<Result> dispatch(Callable<Result> callable, Context context) {
public Future<Result> dispatchResultWithContext(Callable<Result> callable, Context context) {
return akka.dispatch.Futures.future(callable,
new HttpExecutionContext(system.dispatcher(), context, Thread.currentThread().getContextClassLoader()));
}

@Override
public Future<Result> dispatch(Callable<Result> callable) {
public Future<Result> dispatchResult(Callable<Result> callable) {
return akka.dispatch.Futures.future(callable,
new HttpExecutionContext(system.dispatcher(), Context.CONTEXT.get(),
Thread.currentThread().getContextClassLoader
()));
}

@Override
public Future<InputStream> dispatchInputStream(Callable<InputStream> callable) {
return akka.dispatch.Futures.future(callable,
new HttpExecutionContext(system.dispatcher(), Context.CONTEXT.get(),
Thread.currentThread().getContextClassLoader
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package org.wisdom.configuration;

import org.apache.commons.configuration.ConfigurationConverter;
import java.io.File;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.felix.ipojo.annotations.Component;
import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Provides;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wisdom.api.configuration.Configuration;

import java.io.File;
import java.util.*;

/**
* Implementation of the configuration service reading application/conf and an external (optional) property.
Expand All @@ -24,9 +20,6 @@ public class ApplicationConfigurationImpl extends ConfigurationImpl implements o
.ApplicationConfiguration {

public static final String APPLICATION_CONFIGURATION = "application.configuration";
static final String ERROR_KEYNOTFOUND = "Key %s does not exist. Please include it in your application.conf. " +
"Otherwise this application will not work";
static final String ERROR_NOSUCHKEY = "No such key \"";
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationConfigurationImpl.class);
private final Mode mode;
private final File baseDirectory;
Expand Down Expand Up @@ -145,6 +138,20 @@ public Boolean getBoolean(String key) {
}
return r;
}

/**
* @param key the key
* @return the property or null if not there or property no Long
*/
@Override
public Long getLong(String key) {
Long r = super.getLong(key);
if (r == null) {
LOGGER.error(ERROR_NOSUCHKEY + key + "\"");
return null;
}
return r;
}

/**
* Whether we are in dev mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
* Unlike the main application configuration, this implementation does not used a logger.
*/
public class ConfigurationImpl implements Configuration {

private static final String ERROR_KEYNOTFOUND = "Key %s does not exist. Please include it in your application.conf. " +
"Otherwise this application will not work";
protected static final String ERROR_NOSUCHKEY = "No such key \"";

private org.apache.commons.configuration.Configuration configuration;

Expand Down Expand Up @@ -137,6 +141,39 @@ public Boolean getBooleanWithDefault(String key, Boolean defaultValue) {
return configuration.getBoolean(key, defaultValue);
}
}

@Override
public Long getLong(String key) {
Long v = Long.getLong(key);
if (v == null) {
try {
return configuration.getLong(key);
} catch (NoSuchElementException e) { //NOSONAR
return null;
}
} else {
return v;
}
}

@Override
public Long getLongWithDefault(String key, Long defaultValue) {
Long value = Long.getLong(key);
if (value == null) {
return configuration.getLong(key, defaultValue);
}
return value;
}

@Override
public Long getLongOrDie(String key) {
Long value = Long.getLong(key);
if (value == null) {
throw new IllegalArgumentException(String.format(ERROR_KEYNOTFOUND, key));
} else {
return value;
}
}

/**
* The "die" method forces this key to be set. Otherwise a runtime exception
Expand All @@ -150,7 +187,7 @@ public Boolean getBooleanOrDie(String key) {
Boolean value = getBoolean(key);

if (value == null) {
throw new IllegalArgumentException(String.format(ApplicationConfigurationImpl.ERROR_KEYNOTFOUND, key));
throw new IllegalArgumentException(String.format(ERROR_KEYNOTFOUND, key));
} else {
return value;
}
Expand All @@ -168,7 +205,7 @@ public Integer getIntegerOrDie(String key) {
Integer value = getInteger(key);

if (value == null) {
throw new IllegalArgumentException(String.format(ApplicationConfigurationImpl.ERROR_KEYNOTFOUND, key));
throw new IllegalArgumentException(String.format(ERROR_KEYNOTFOUND, key));
} else {
return value;
}
Expand All @@ -186,7 +223,7 @@ public String getOrDie(String key) {
String value = get(key);

if (value == null) {
throw new IllegalArgumentException(String.format(ApplicationConfigurationImpl.ERROR_KEYNOTFOUND, key));
throw new IllegalArgumentException(String.format(ERROR_KEYNOTFOUND, key));
} else {
return value;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.wisdom.configuration;

import org.junit.After;
import org.junit.Test;
import org.wisdom.api.configuration.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import org.junit.After;
import org.junit.Test;
import org.wisdom.api.configuration.ApplicationConfiguration;
import org.wisdom.api.configuration.Configuration;

/**
* Check the configuration management behavior.
Expand Down Expand Up @@ -84,6 +85,16 @@ public void testGetInteger() {
assertThat(configuration.getIntegerWithDefault("key.int.no", 2)).isEqualTo(2);
assertThat(configuration.get("key.int")).isEqualTo("1");
}

@Test
public void testGetLong() {
System.setProperty(ApplicationConfigurationImpl.APPLICATION_CONFIGURATION, "target/test-classes/conf/regular.conf");
ApplicationConfiguration configuration = new ApplicationConfigurationImpl();
assertThat(configuration).isNotNull();
assertThat(configuration.getLong("key.long")).isEqualTo(9999999999999L);
assertThat(configuration.getLongWithDefault("key.long", 2L)).isEqualTo(9999999999999L);
assertThat(configuration.getLongWithDefault("key.long.no", 2L)).isEqualTo(2L);
}

@Test
public void testGetBoolean() {
Expand Down Expand Up @@ -198,7 +209,7 @@ public void testEmptySubConfigurations() {

@Test
public void testAllAndProperties() {
final int numberOfPropertiesStartingWithKey = 8;
final int numberOfPropertiesStartingWithKey = 9;
System.setProperty(ApplicationConfigurationImpl.APPLICATION_CONFIGURATION, "target/test-classes/conf/regular.conf");
ApplicationConfigurationImpl configuration = new ApplicationConfigurationImpl();
assertThat(configuration).isNotNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ key.array = a,b,c

other.conf = a_file.txt

key.long = 9999999999999

5 changes: 5 additions & 0 deletions content-manager/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
<artifactId>wisdom-api</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
</dependency>

<dependency>
<groupId>org.apache.felix</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.wisdom.content.codecs;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.InflaterInputStream;

import org.apache.commons.io.IOUtils;
import org.wisdom.api.content.ContentCodec;

/**
* Abstract codec using an {@link DeflaterOutputStream} instance to encode and {@link InflaterInputStream} instance to decode.
* Subclasses of this two classes can also be used, for instance ({@link GZIPOutputStream and {@link GZIPInputStream}}
* <br/>
* Subclasses should implements {@link #getEncoderClass} and {@link #getDecoderClass} to return the chosen encoder classes.
* <br/>
* @see ContentCodec
*/
public abstract class AbstractDefInfCodec implements ContentCodec {

@Override
public InputStream encode(InputStream toEncode) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();

OutputStream encoderout;
try {
encoderout = getEncoderClass().getConstructor(OutputStream.class).newInstance(bout);
encoderout.write(IOUtils.toByteArray(toEncode));
encoderout.flush();
encoderout.close();
}
catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
//TODO notify encoding has not been done
return toEncode;
}

toEncode.close();

bout.flush();
InputStream encoded = new ByteArrayInputStream(bout.toByteArray());
bout.close();
return encoded;
}

@Override
public InputStream decode(InputStream toDecode) throws IOException {
InputStream decoderin;
try {
decoderin = getDecoderClass().getConstructor(InputStream.class).newInstance(toDecode);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
//TODO notify encoding has not been done
return toDecode;
}
return decoderin;
}

@Override
public abstract String getEncodingType();

@Override
public abstract String getContentEncodingHeaderValue();

/**
* @return Encoder class the codec use to encode data
*/
public abstract Class<? extends DeflaterOutputStream> getEncoderClass();

/**
* @return Decoder class the codec use to decode data
*/
public abstract Class<? extends InflaterInputStream> getDecoderClass();
}
Loading