Skip to content

Commit

Permalink
initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
vardlokkur committed May 29, 2013
1 parent 819afce commit aee6550
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pl.ais.commons.domain.security;

import java.io.Serializable;

import javax.annotation.Nonnull;

/**
* Defines the API contract for the cryptographic service.
*
* @param <T> defines the type of unencrypted value
* @author Warlock, AIS.PL
* @since 1.0.2
*/
public interface CryptographicService<T> extends Serializable {

/**
* Decrypts the value.
*
* @param value the value to decrypt
* @return decrypted value
*/
@Nonnull
T decrypt(@Nonnull DecryptableValue<T> value);

/**
* Encrypts given value.
*
* @param value the value to encrypt
* @return encrypted value
*/
@Nonnull
DecryptableValue<T> encrypt(@Nonnull T value);

}
97 changes: 97 additions & 0 deletions src/main/java/pl/ais/commons/domain/security/DecryptableValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package pl.ais.commons.domain.security;

import java.io.Serializable;
import java.util.Arrays;

import javax.annotation.Nonnull;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;

import pl.ais.commons.domain.stereotype.ValueObject;

/**
* Decryptable value.
*
* @param <T> defines the type of unencrypted value
* @author Warlock, AIS.PL
* @since 1.0.2
*/
@ValueObject
public final class DecryptableValue<T> implements Serializable {

private transient T decryptedValue;

private final CryptographicService<T> decryptor;

private final byte[] encryptedValue;

/**
* Constructs new instance.
*
* @param decryptor decryptor which will be used to decrypt value
* @param encryptedValue encrypted value, which will be enclosed by the created instance
*/
public DecryptableValue(@Nonnull final CryptographicService<T> decryptor, @Nonnull final byte[] encryptedValue) {
super();
if ((null == decryptor) || (null == encryptedValue)) {
throw new IllegalArgumentException("Both decryptor and encrypted value cannot be null.");
}
this.decryptor = decryptor;
this.encryptedValue = Arrays.copyOf(encryptedValue, encryptedValue.length);
}

/**
* Decrypts the value.
*
* @return decrypted value
*/
@Nonnull
public T decrypt() {
if (null == decryptedValue) {
decryptedValue = decryptor.decrypt(this);
}
return decryptedValue;
}

/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@SuppressWarnings("rawtypes")
@Override
public boolean equals(final Object object) {
boolean result = (this == object);
if (!result && (null != object) && (getClass() == object.getClass())) {
final DecryptableValue other = (DecryptableValue) object;
result = new EqualsBuilder().append(decryptor, other.decryptor)
.append(encryptedValue, other.encryptedValue).isEquals();
}
return result;
}

/**
* @return the encrypted value
*/
@Nonnull
public byte[] getEncryptedValue() {
return Arrays.copyOf(encryptedValue, encryptedValue.length);
}

/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(decryptor).append(encryptedValue).toHashCode();
}

/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new ToStringBuilder(this).append("decryptor", decryptor).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package pl.ais.commons.domain.security;

import java.nio.charset.Charset;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;

import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;

import pl.ais.commons.domain.stereotype.DomainService;

/**
* Pass-through implementation of cryptographic service.
*
* <p>
* This implementation in fact doesn't perform any encryption. Returned {@link DecryptableValue} holds
* the unencrypted data passed through.
* </p>
*
* @author Warlock, AIS.PL
* @since 1.0.2
*/
@ThreadSafe
@DomainService
public final class PassThroughCryptographicService implements CryptographicService<String> {

private final String charsetName;

/**
* Constructs new instance using default charset of this JVM for the string conversions.
*/
public PassThroughCryptographicService() {
this(Charset.defaultCharset());
}

/**
* Constructs new instance.
*
* @param charset the charset which should be used for the string conversions
*/
public PassThroughCryptographicService(@Nonnull final Charset charset) {
super();
if (null == charset) {
throw new IllegalArgumentException("Charset cannot be null.");
}
this.charsetName = charset.name();
}

/**
* {@inheritDoc}
*/
@Override
@Nonnull
public String decrypt(@Nonnull final DecryptableValue<String> value) {
if (null == value) {
throw new IllegalArgumentException();
}
return new String(value.getEncryptedValue(), Charset.forName(charsetName));
}

/**
* {@inheritDoc}
*/
@Override
@Nonnull
public DecryptableValue<String> encrypt(@Nonnull final String value) {
if (null == value) {
throw new IllegalArgumentException();
}
return new DecryptableValue<>(this, value.getBytes(Charset.forName(charsetName)));
}

/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object object) {
boolean result = (this == object);
if (!result && (null != object) && (getClass() == object.getClass())) {
final PassThroughCryptographicService other = (PassThroughCryptographicService) object;
result = charsetName.equals(other.charsetName);
}
return result;
}

/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return new HashCodeBuilder().append(charsetName).toHashCode();
}

/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return new ToStringBuilder(this).append("charsetName", charsetName).build();
}

}
34 changes: 34 additions & 0 deletions src/main/java/pl/ais/commons/domain/stereotype/DomainService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package pl.ais.commons.domain.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Service;

/**
* Indicates that an annotated class is a Domain Service.
*
* @author Warlock, AIS.PL
* @since 1.0.2
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Service
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public @interface DomainService {

/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
*
* @return the suggested component name, if any
*/
String value() default "";

}
28 changes: 28 additions & 0 deletions src/main/java/pl/ais/commons/domain/stereotype/ValueObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package pl.ais.commons.domain.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.annotation.concurrent.Immutable;

/**
* Indicates that an annotated class is a Value Object.
*
* @see <a href="http://martinfowler.com/eaaCatalog/valueObject.html">Value Object (Patterns of Enterprise Application Architecture)</a>
* @see <a href="http://en.wikipedia.org/wiki/Value_object">Value Object (Wikipedia)</a>
*
* @author Warlock, AIS.PL
* @since 1.0.2
*/
@Documented
@Immutable
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ValueObject {

// Empty by design ...

}

0 comments on commit aee6550

Please sign in to comment.