Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>SimpleJPA</groupId>
<artifactId>SimpleJPA</artifactId>
<version>1.6-SNAPSHOT</version>
<version>1.6.1-SNAPSHOT</version>
<name>SimpleJPA</name>
<url>http://code.google.com/p/simplejpa</url>
<scm>
Expand Down
31 changes: 28 additions & 3 deletions core/src/main/java/com/spaceprogram/simplejpa/ObjectBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
Expand All @@ -26,6 +27,7 @@
*
* Additional Contributions
* - Yair Ben-Meir reformy@gmail.com
* - Michael Balser michael@die-balsers.de
*/
public class ObjectBuilder {

Expand Down Expand Up @@ -165,14 +167,37 @@ private static String getIdForManyToOne(EntityManagerSimpleJPA em, Method getter

private static String getValueToSet(List<Attribute> atts, String propertyName, String columnName) {
if(columnName != null) propertyName = columnName;
// Retrieve all matching attributes.
List<Attribute> matchingAtts = new ArrayList<Attribute>();
for (Attribute att : atts) {
String attName = att.getName();
if (attName.equals(propertyName)) {
String val = att.getValue();
return val;
matchingAtts.add(att);
}
}
return null;
if (matchingAtts.size() == 0) {
return null;
} else if (matchingAtts.size() == 1) {
// Value has not been split into multiple chunks.
// Simply return value.
String val = matchingAtts.get(0).getValue();
return val;
} else {
// Value has been split into multiple chunks.
// 1. Order chunks according to attached counter.
String[] chunks = new String[matchingAtts.size()];
for (int i = 0; i < matchingAtts.size(); i ++) {
String chunk = matchingAtts.get(i).getValue();
int counter = Integer.parseInt("" + chunk.charAt(chunk.length() - 4)) * 1000 + Integer.parseInt("" + chunk.charAt(chunk.length() - 3)) * 100 + Integer.parseInt("" + chunk.charAt(chunk.length() - 2)) * 10 + Integer.parseInt("" + chunk.charAt(chunk.length() - 1));
chunks[counter] = chunk.substring(0, chunk.length() - 4);
}
// 2. Append chunks.
StringBuffer val = new StringBuffer();
for (int i = 0; i < chunks.length; i ++) {
val.append(chunks[i]);
}
return val.toString();
}
}


Expand Down
88 changes: 60 additions & 28 deletions core/src/main/java/com/spaceprogram/simplejpa/operations/Save.java
Original file line number Diff line number Diff line change
@@ -1,50 +1,55 @@
package com.spaceprogram.simplejpa.operations;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.Item;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.spaceprogram.simplejpa.AnnotationInfo;
import com.spaceprogram.simplejpa.DomainHelper;
import com.spaceprogram.simplejpa.EntityManagerFactoryImpl;
import com.spaceprogram.simplejpa.EntityManagerSimpleJPA;
import com.spaceprogram.simplejpa.LazyInterceptor;
import com.spaceprogram.simplejpa.NamingHelper;
import net.sf.cglib.proxy.Factory;

import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceException;
import javax.persistence.PostPersist;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceException;
import javax.persistence.PostPersist;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;

import net.sf.cglib.proxy.Factory;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.simpledb.model.Attribute;
import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
import com.amazonaws.services.simpledb.model.PutAttributesRequest;
import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
import com.spaceprogram.simplejpa.AnnotationInfo;
import com.spaceprogram.simplejpa.EntityManagerFactoryImpl;
import com.spaceprogram.simplejpa.EntityManagerSimpleJPA;
import com.spaceprogram.simplejpa.LazyInterceptor;
import com.spaceprogram.simplejpa.NamingHelper;

/**
* User: treeder
* Date: Apr 1, 2008
* Time: 11:51:16 AM
*
* Additional Contributions
* - Michael Balser michael@die-balsers.de
*/
public class Save implements Callable {
private static Logger logger = Logger.getLogger(Save.class.getName());
Expand Down Expand Up @@ -200,8 +205,35 @@ else if(getter.getAnnotation(Id.class) != null)
}
else {
String toSet = ob != null ? em.padOrConvertIfRequired(ob) : "";
// todo: throw an exception if this is going to exceed maximum size, suggest using @Lob
attsToPut.add(new ReplaceableAttribute(columnName, toSet, true));

try {
// Check size of encoded value.
byte[] bytes = toSet.getBytes("UTF-8");
if (bytes.length > 1024) {
// Maximum size is exceeded; split value into multiple chunks.
int i = 0, pos = 0;
while (pos < bytes.length) {
int size = 1020;
// Beware: do not split encoded characters.
// (Additional bytes of an encoded character follow the pattern 10xxxxxx.)
while (pos + size < bytes.length && (bytes[pos + size] & 0xc0) == 0x80) {
size --;
}
String chunk = new String(Arrays.copyOfRange(bytes, pos, Math.min(pos + size, bytes.length)), "UTF-8");
// Add four digit counter.
String counter = Integer.toString(i / 1000 % 10) + Integer.toString(i / 100 % 10) + Integer.toString(i / 10 % 10) + Integer.toString(i % 10);
attsToPut.add(new ReplaceableAttribute(columnName, chunk + counter, i == 0));
i ++;
pos += size;
}
} else {
// Simply store string as single value.
attsToPut.add(new ReplaceableAttribute(columnName, toSet, true));
}
} catch (UnsupportedEncodingException x) {
// should never happen
throw new PersistenceException("Encoding 'UTF-8' is not supported!", x);
}
}
}

Expand Down
77 changes: 77 additions & 0 deletions core/src/test/java/com/spaceprogram/simplejpa/SplitValueTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.spaceprogram.simplejpa;

import javax.persistence.EntityManager;

import junit.framework.Assert;

import org.junit.Test;

public class SplitValueTests extends BaseTestClass {

private void doTest(String value) {
EntityManager em = factory.createEntityManager();
MyTestObject object = new MyTestObject();
object.setName(value);
em.persist(object);
em.close();

em = factory.createEntityManager();
object = em.find(MyTestObject.class, object.getId());
Assert.assertEquals(value, object.getName());
em.remove(object);
em.close();
}

@Test
public void testSmallStringValue() {
doTest("Test");
}

@Test
public void testMaximumValueWithNoSplitting() {
StringBuffer s = new StringBuffer();
for (int i = 0; i < 1024; i ++) {
s.append((char) ('a' + i % 26));
}
doTest(s.toString());
}

@Test
public void testMinimumValueWithSplitting() {
StringBuffer s = new StringBuffer();
for (int i = 0; i < 1025; i ++) {
s.append((char) ('a' + i % 26));
}
doTest(s.toString());
}

@Test
public void testValueWithLargeNumberOfSplits() {
StringBuffer s = new StringBuffer();
for (int i = 0; i < 1024 * 12 + 1; i ++) {
s.append((char) ('a' + i % 26));
}
doTest(s.toString());
}

@Test
public void testValueWithSpecialCharactersAtEvenOffset() {
StringBuffer s = new StringBuffer();
for (int i = 0; i < 1024 * 2; i ++) {
s.append('\u00e4');
}
doTest(s.toString());
}


@Test
public void testValueWithSpecialCharactersAtOddOffset() {
StringBuffer s = new StringBuffer();
s.append('a');
for (int i = 0; i < 1024 * 2; i ++) {
s.append('\u00e4');
}
doTest(s.toString());
}

}