Return-Path: X-Original-To: apmail-zest-commits-archive@minotaur.apache.org Delivered-To: apmail-zest-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4B96C17546 for ; Tue, 21 Apr 2015 11:50:14 +0000 (UTC) Received: (qmail 5299 invoked by uid 500); 21 Apr 2015 11:50:14 -0000 Delivered-To: apmail-zest-commits-archive@zest.apache.org Received: (qmail 5232 invoked by uid 500); 21 Apr 2015 11:50:14 -0000 Mailing-List: contact commits-help@zest.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zest.apache.org Delivered-To: mailing list commits@zest.apache.org Received: (qmail 5133 invoked by uid 99); 21 Apr 2015 11:50:14 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Apr 2015 11:50:14 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E558DE0D65; Tue, 21 Apr 2015 11:50:13 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: paulmerlin@apache.org To: commits@zest.apache.org Date: Tue, 21 Apr 2015 11:50:17 -0000 Message-Id: <249abe096be849538bd7ff3534bd4207@git.apache.org> In-Reply-To: <44c1d215a4984039ac56399268ee67b0@git.apache.org> References: <44c1d215a4984039ac56399268ee67b0@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [05/18] zest-sandbox git commit: Move Qi4j related projects in a `qi4j/` subfolder http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoExtendCommand.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoExtendCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoExtendCommand.java new file mode 100644 index 0000000..f4145f7 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoExtendCommand.java @@ -0,0 +1,68 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import java.io.IOException; +import java.io.RandomAccessFile; + +/** + * The DataFile has been extended at the end. + * + * To undo this we simply set the Length of the file to the previously known length. + * Block Structure + * [blockSize] 4 bytes + * [usage] 1 byte (0=Unused, 1=prime, 2=mirror, 3=primeChanged, 4=mirrorChanged) + * [instanceVersion] 8 bytes + * [schemaVersion] 4 bytes + * [identitySize] 1 byte + * [identity] IDENTITY_MAX_LENGTH bytes + * [mirrorPointer] 8 bytes + * [primeDataLength] 4 bytes + * [primeData] n bytes + * [mirrorDataLength] 4 bytes + * [mirrorData] n bytes + */ +public class UndoExtendCommand + implements UndoCommand +{ + private long previousLength; + + public UndoExtendCommand( long previousLength ) + { + this.previousLength = previousLength; + } + + public void undo( RandomAccessFile dataFile, IdentityFile idFile ) throws IOException + { + dataFile.setLength( previousLength ); + dataFile.seek( dataFile.length() ); + dataFile.writeInt( -1 ); // Put in the EOF + } + + public void save( RandomAccessFile undoJournal ) throws IOException + { + undoJournal.writeLong( previousLength ); + } + + static UndoExtendCommand load( RandomAccessFile undoJournal ) + throws IOException + { + long position = undoJournal.readLong(); + return new UndoExtendCommand( position ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoManager.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoManager.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoManager.java new file mode 100644 index 0000000..a9dc23e --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoManager.java @@ -0,0 +1,23 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +public interface UndoManager +{ + void saveUndoCommand( UndoCommand command ); +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoModifyCommand.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoModifyCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoModifyCommand.java new file mode 100644 index 0000000..2331725 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoModifyCommand.java @@ -0,0 +1,81 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import java.io.IOException; +import java.io.RandomAccessFile; + +/** + * Record has been modified and we can restore it. + * + * Block Structure + * [blockSize] 4 bytes + * [usage] 1 byte (0=Unused, 1=prime, 2=mirror, 3=primeChanged, 4=mirrorChanged) + * [instanceVersion] 8 bytes + * [schemaVersion] 4 bytes + * [identitySize] 1 byte + * [identity] IDENTITY_MAX_LENGTH bytes + * [mirrorPointer] 8 bytes + * [primeDataLength] 4 bytes + * [primeData] n bytes + * [mirrorDataLength] 4 bytes + * [mirrorData] n bytes + */ +public class UndoModifyCommand + implements UndoCommand +{ + private long position; + private byte usage; + private long instanceVersion; + private int schemaVersion; + + public UndoModifyCommand( long position, byte usage, long instanceVersion, int schemaVersion ) + { + this.position = position; + this.usage = usage; + this.instanceVersion = instanceVersion; + this.schemaVersion = schemaVersion; + } + + public void undo( RandomAccessFile dataFile, IdentityFile idFile ) throws IOException + { + dataFile.seek( position + 4 ); + dataFile.writeByte( usage ); + dataFile.writeLong( instanceVersion ); + dataFile.writeInt( schemaVersion ); + } + + public void save( RandomAccessFile undoJournal ) + throws IOException + { + undoJournal.writeLong( position ); + undoJournal.writeByte( usage ); + undoJournal.writeLong( instanceVersion ); + undoJournal.writeInt( schemaVersion ); + } + + static UndoCommand load( RandomAccessFile undoJournal ) + throws IOException + { + long position = undoJournal.readLong(); + byte usage = undoJournal.readByte(); + long instanceVersion = undoJournal.readLong(); + int schemaVersion = undoJournal.readInt(); + return new UndoModifyCommand( position, usage, instanceVersion, schemaVersion ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoNewIdentityCommand.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoNewIdentityCommand.java b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoNewIdentityCommand.java new file mode 100644 index 0000000..9293513 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/main/java/org/qi4j/entitystore/swift/UndoNewIdentityCommand.java @@ -0,0 +1,53 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import org.qi4j.spi.entity.QualifiedIdentity; +import org.qi4j.api.entity.EntityReference; + +import java.io.IOException; +import java.io.RandomAccessFile; + +public class UndoNewIdentityCommand + implements UndoCommand +{ + private EntityReference reference; + + public UndoNewIdentityCommand( EntityReference reference ) + { + this.reference = reference; + } + + public void undo( RandomAccessFile dataFile, IdentityFile idFile ) throws IOException + { + idFile.drop( reference ); + } + + public void save( RandomAccessFile undoJournal ) throws IOException + { + undoJournal.writeUTF( reference.toString() ); + } + + static UndoNewIdentityCommand load( RandomAccessFile undoJournal ) + throws IOException + { + String idString = undoJournal.readUTF(); + EntityReference ref = new EntityReference( idString ); + return new UndoNewIdentityCommand( ref ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/main/resources/org/qi4j/entitystore/quick/QuickEntityStoreService.properties ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/main/resources/org/qi4j/entitystore/quick/QuickEntityStoreService.properties b/qi4j/extensions/entitystore-swift/src/main/resources/org/qi4j/entitystore/quick/QuickEntityStoreService.properties new file mode 100644 index 0000000..32422c2 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/main/resources/org/qi4j/entitystore/quick/QuickEntityStoreService.properties @@ -0,0 +1,17 @@ + +### Configuration for the Quick EntityStore. +### The commented out properties are the default values if not specified. + + +### The recovery system is needed to ensure a consistent database after a non-managed shutdown, such +### power-failure, JVM crash and "kill -9" +## If there is an Undo file on the file system, use it to undo the pending changes. +# recover=true + +### Storage Directory is the place (relative to current working directory) where the database +### will store its files. This directory needs to be dedicated to Quick EntityStore. +# storageDirectory=qi4j/quickstore + +### TurboMode disables the use of regular Java serialization and uses custom Objcet streams +### for performance reasons. +# turboMode=false \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/DataFileTest.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/DataFileTest.java b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/DataFileTest.java new file mode 100644 index 0000000..783b416 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/DataFileTest.java @@ -0,0 +1,184 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import org.junit.Assert; +import org.junit.Test; +import org.qi4j.api.entity.EntityReference; + +import java.io.File; + +public class DataFileTest +{ + @Test + public void whenPuttingDataThenExpectSameDataBack() + throws Exception + { + File dir = new File( "swift-store" ); + RecordManager man = new RecordManager( dir, false ); + try + { + EntityReference ref = createReference( "12345678" ); + String data = "Hej hopp du glade man!!"; + DataBlock originalData = new DataBlock( ref, data.getBytes(), 81273, 91283 ); + man.putData( originalData ); + + DataBlock retrieveData = man.readData( ref ); + Assert.assertEquals( "Incorrect Data retrieved.", originalData, retrieveData ); + } + finally + { + FileUtils.delete( dir ); + } + } + + @Test + public void whenPutting100DataWithIndividualCommitsThenExpectSameDataBack() + throws Exception + { + File dir = new File( "swift-store" ); + RecordManager man = new RecordManager( dir, false ); + try + { + EntityReference[] ids = new EntityReference[100]; + String[] values = new String[100]; + int[] schemas = new int[100]; + long[] versions = new long[100]; + long t0 = System.currentTimeMillis(); + for( int i = 0; i < 100; i++ ) + { + ids[ i ] = createReference( "habba" + i ); + values[ i ] = "Hej hopp du glade man!!" + Math.random(); + DataBlock originalData = new DataBlock( ids[ i ], values[ i ].getBytes(), versions[ i ], schemas[ i ] ); + man.putData( originalData ); + man.commit(); + } + long t1 = System.currentTimeMillis(); + System.out.println( "Thruoughput: " + 100000 / ( t1 - t0 ) + " creations/sec" ); + for( int i = 0; i < 100; i++ ) + { + DataBlock data = man.readData( ids[ i ] ); + Assert.assertEquals( "Incorrect Data retrieved.", ids[ i ], data.reference ); + Assert.assertEquals( "Incorrect Data retrieved.", versions[ i ], data.instanceVersion ); + Assert.assertEquals( "Incorrect Data retrieved.", values[ i ], new String( data.data ) ); + Assert.assertEquals( "Incorrect Data retrieved.", schemas[ i ], data.schemaVersion ); + } + } + finally + { + FileUtils.delete( dir ); + } + } + + @Test + public void whenPutting100DataWithSingleCommitThenExpectSameDataBack() + throws Exception + { + File dir = new File( "swift-store" ); + RecordManager man = new RecordManager( dir, false ); + try + { + EntityReference[] ids = new EntityReference[100]; + String[] values = new String[100]; + int[] schemas = new int[100]; + long[] versions = new long[100]; + long t0 = System.currentTimeMillis(); + for( int i = 0; i < 100; i++ ) + { + ids[ i ] = createReference( "habba" + i ); + values[ i ] = "Hej hopp du glade man!!" + Math.random(); + DataBlock originalData = new DataBlock( ids[ i ], values[ i ].getBytes(), versions[ i ], schemas[ i ] ); + man.putData( originalData ); + } + man.commit(); + long t1 = System.currentTimeMillis(); + System.out.println( "Thruoughput: " + 100000 / ( t1 - t0 ) + " creations/sec" ); + for( int i = 0; i < 100; i++ ) + { + DataBlock data = man.readData( ids[ i ] ); + Assert.assertEquals( "Incorrect Data retrieved.", ids[ i ], data.reference ); + Assert.assertEquals( "Incorrect Data retrieved.", versions[ i ], data.instanceVersion ); + Assert.assertEquals( "Incorrect Data retrieved.", values[ i ], new String( data.data ) ); + Assert.assertEquals( "Incorrect Data retrieved.", schemas[ i ], data.schemaVersion ); + } + } + finally + { + FileUtils.delete( dir ); + } + } + + + @Test + public void whenEntityReferenceIsAtMaxThenExpectSameDataBack() + throws Exception + { + File dir = new File( "swift-store" ); + RecordManager man = new RecordManager( dir, false ); + try + { + EntityReference ref = createReference( "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678912" ); + String data = "Hej hopp du glade man!!"; + DataBlock originalData = new DataBlock( ref, data.getBytes(), 81273, 91283 ); + man.putData( originalData ); + man.commit(); + + DataBlock retrieveData = man.readData( ref ); + Assert.assertEquals( "Incorrect Data retrieved.", originalData, retrieveData ); + } + finally + { + FileUtils.delete( dir ); + } + + } + + @Test + public void whenTooLongEntityReferenceThenExpectException() + throws Exception + { + File dir = new File( "swift-store" ); + RecordManager man = new RecordManager( dir, false ); + try + { + StringBuffer buf = new StringBuffer(); + for( int i=0 ; i < 129 ; i++ ) + buf.append( (i % 10) ); + EntityReference ref = createReference( buf.toString() ); + + String data = "Hej hopp du glade man!!"; + DataBlock originalData = new DataBlock( ref, data.getBytes(), 81273, 91283 ); + man.putData( originalData ); + Assert.fail( "Exceeeding max length didn't cause Exception." ); + } + catch( IdentityTooLongException e ) + { + // Expected. + } + finally + { + FileUtils.delete( dir ); + } + + } + + private EntityReference createReference( String identity ) + { + return new EntityReference( identity ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/IdentityFileTest.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/IdentityFileTest.java b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/IdentityFileTest.java new file mode 100644 index 0000000..6af5d81 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/IdentityFileTest.java @@ -0,0 +1,196 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import java.io.File; +import java.io.IOException; +import java.util.Random; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; +import org.qi4j.api.entity.EntityReference; + +@SuppressWarnings( { "ResultOfMethodCallIgnored" } ) +public class IdentityFileTest +{ + private File idFile; + private IdentityFile file; + + @Test + public void whenCreatingNewIdentityFileThenSucceed() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 64, 1000 ); + } + + @Test + public void whenCreatingAnEntryThenGetTheResultBack() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 64, 1000 ); + populateRandom( file ); + long value = 9783249823L; + EntityReference identity = createIdentity( "SomeIdentity" ); + file.remember( identity, value ); + long recalled = file.find( identity ); + Assert.assertEquals( "Wrong position retrieved for item.", value, recalled ); + } + + @Test + public void whenCreating50EntriesThenGetTheResultBack() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 64, 1000 ); + populateRandom( file ); + long[] pos = new long[50]; + for( int i = 0; i < 50; i++ ) + { + pos[ i ] = (long) ( Math.random() * Long.MAX_VALUE ); + EntityReference identity = createIdentity( "Identity-" + i ); + file.remember( identity, pos[ i ] ); + } + + for( int i = 0; i < 50; i++ ) + { + EntityReference identity = createIdentity( "Identity-" + i ); + long recalled = file.find( identity ); + Assert.assertEquals( "Wrong position retrieved for item " + i + ".", pos[ i ], recalled ); + } + } + + + @Test + public void whenIdentityIsLongerThanAllowedExpectException() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 24, 1000 ); + try + { + EntityReference identity = createIdentity( "12345678901" ); + file.remember( identity, 827349813743908274L ); + Assert.fail( "Should not allow this long identity." ); + } + catch( IdentityTooLongException e ) + { + // expected + } + } + + @Test + public void whenNotEnoughSpaceIsAvailableExpectThatCanStillStore() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 64, 1 ); + long[] pos = new long[150]; + for( int i = 0; i < 150; i++ ) + { + pos[ i ] = (long) ( Math.random() * Long.MAX_VALUE ); + EntityReference identity = createIdentity( "Identity-" + i ); + file.remember( identity, pos[ i ] ); + } + + for( int i = 0; i < 150; i++ ) + { + EntityReference identity = createIdentity( "Identity-" + i ); + long recalled = file.find( identity ); + Assert.assertEquals( "Wrong position retrieved for item " + i + ".", pos[ i ], recalled ); + } + } + + @Test + public void whenDroppingAnIdentityExpectMinusOneWhenLookingUp() + throws Exception + { + idFile = new File( "swift-store" ); + idFile.mkdirs(); + file = IdentityFile.create( idFile, 64, 5 ); + long[] pos = new long[150]; + for( int i = 0; i < 150; i++ ) + { + pos[ i ] = (long) ( Math.random() * Long.MAX_VALUE ); + EntityReference identity = createIdentity( "Identity-" + i ); + file.remember( identity, pos[ i ] ); + } + + for( int i = 0; i < 150; i++ ) + { + EntityReference identity = createIdentity( "Identity-" + i ); + file.drop( identity ); + } + + for( int i = 0; i < 150; i++ ) + { + EntityReference identity = createIdentity( "Identity-" + i ); + Assert.assertEquals( "Identity entry not gone.", -1, file.find( identity ) ); + } + } + + @After + public void cleanUp() + { + try + { + file.close(); + } + catch( IOException e ) + { + e.printStackTrace(); + } + delete( idFile ); + } + + private void delete( File file ) + { + if( file.isDirectory() ) + { + for( File child : file.listFiles() ) + { + delete( child ); + } + } + file.delete(); + } + + private EntityReference createIdentity( String identity ) + { + return new EntityReference( identity ); + } + + private void populateRandom( IdentityFile file ) + throws IOException + { + Random rnd = new Random(); + int max = (int) ( file.entries() * 0.5 ); + for( int i = 0; i < max; i++ ) + { + String id = String.valueOf( rnd.nextInt(16) ); + EntityReference ref = new EntityReference( id ); + file.remember(ref, i); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftEntityStoreTest.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftEntityStoreTest.java b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftEntityStoreTest.java new file mode 100644 index 0000000..e039475 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftEntityStoreTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2008 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.entitystore.swift; + +import org.qi4j.api.common.Visibility; +import org.qi4j.api.value.ValueSerialization; +import org.qi4j.bootstrap.AssemblyException; +import org.qi4j.bootstrap.ModuleAssembly; +import org.qi4j.test.entity.AbstractEntityStoreTest; +import org.qi4j.spi.uuid.UuidIdentityGeneratorService; +import org.qi4j.test.EntityTestAssembler; +import org.qi4j.valueserialization.orgjson.OrgJsonValueSerializationService; + +public class SwiftEntityStoreTest extends AbstractEntityStoreTest +{ + public void assemble( ModuleAssembly module ) + throws AssemblyException + { + super.assemble( module ); + module.services( SwiftEntityStoreService.class, UuidIdentityGeneratorService.class ); + module.services( OrgJsonValueSerializationService.class ).taggedWith( ValueSerialization.Formats.JSON ); + + ModuleAssembly config = module.layer().module( "config" ); + config.entities( SwiftConfiguration.class ).visibleIn( Visibility.layer ); + new EntityTestAssembler().assemble( config ); + } + +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftStorePerformanceTest.java ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftStorePerformanceTest.java b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftStorePerformanceTest.java new file mode 100644 index 0000000..affae56 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/test/java/org/qi4j/entitystore/swift/SwiftStorePerformanceTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Niclas Hedhman. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.qi4j.entitystore.swift; + +// import org.qi4j.test.entity.performance.AbstractEntityStorePerformanceTest; +import org.junit.Ignore; +import org.qi4j.bootstrap.Assembler; + +@Ignore( "Needs org.qi4j.test.performance dependency" ) +public class SwiftStorePerformanceTest // extends AbstractEntityStorePerformanceTest +{ + public SwiftStorePerformanceTest() + { + // super( "SwiftEntityStore", createAssembler() ); + } + + private static Assembler createAssembler() + { + return new SwiftEntityStoreAssembler( "config" ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/entitystore-swift/src/test/resources/org/qi4j/entitystore/swift/SwiftEntityStoreService.properties ---------------------------------------------------------------------- diff --git a/qi4j/extensions/entitystore-swift/src/test/resources/org/qi4j/entitystore/swift/SwiftEntityStoreService.properties b/qi4j/extensions/entitystore-swift/src/test/resources/org/qi4j/entitystore/swift/SwiftEntityStoreService.properties new file mode 100644 index 0000000..56cc119 --- /dev/null +++ b/qi4j/extensions/entitystore-swift/src/test/resources/org/qi4j/entitystore/swift/SwiftEntityStoreService.properties @@ -0,0 +1 @@ +storageDirectory=target/swiftdb http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/extensions/pom.xml ---------------------------------------------------------------------- diff --git a/qi4j/extensions/pom.xml b/qi4j/extensions/pom.xml new file mode 100644 index 0000000..7093373 --- /dev/null +++ b/qi4j/extensions/pom.xml @@ -0,0 +1,25 @@ + + + org.qi4j.sandbox + qi4j-sandbox + 0-SNAPSHOT + + 4.0.0 + qi4j-sandbox-extensions + Qi4j Sandbox Extensions - Build POM + pom + + + entitystore-jndi + entitystore-cassandra + entitystore-jgroups + entitystore-rmi + entitystore-s3 + entitystore-swift + + + + + http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/dev-status.xml ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/dev-status.xml b/qi4j/libraries/beans/dev-status.xml new file mode 100644 index 0000000..0c93156 --- /dev/null +++ b/qi4j/libraries/beans/dev-status.xml @@ -0,0 +1,14 @@ + + + + early + + none + + some + + + + ALv2 + + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/pom.xml ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/pom.xml b/qi4j/libraries/beans/pom.xml new file mode 100644 index 0000000..c8c36c7 --- /dev/null +++ b/qi4j/libraries/beans/pom.xml @@ -0,0 +1,41 @@ + + 4.0.0 + + org.qi4j.sandbox + qi4j-sandbox-libraries + 0-SNAPSHOT + + org.qi4j.library + org.qi4j.library.beans + Qi4j Library - Beans + + + org.qi4j.core + org.qi4j.core.api + + + org.qi4j.core + org.qi4j.core.spi + + + org.qi4j.core + org.qi4j.core.bootstrap + + + org.qi4j.core + org.qi4j.core.runtime + runtime + + + org.qi4j.core + org.qi4j.core.testsupport + test + + + junit + junit + test + + + http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Getters.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Getters.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Getters.java new file mode 100644 index 0000000..14bca23 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Getters.java @@ -0,0 +1,21 @@ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesToFilter; + +import java.lang.reflect.Method; + +/** + * Filter for getter methods. Method name must match "get*" or "is*" or "has*". + */ +public class Getters implements AppliesToFilter +{ + public static final MethodPrefixFilter GET = new MethodPrefixFilter( "get" ); + public static final MethodPrefixFilter IS = new MethodPrefixFilter( "is" ); + public static final MethodPrefixFilter HAS = new MethodPrefixFilter( "has" ); + public static final AppliesToFilter GETTERS = new OrAppliesToFilter( GET, IS, HAS ); + + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class modelClass ) + { + return GETTERS.appliesTo( method, mixin, compositeType, modelClass ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Iterables.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Iterables.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Iterables.java new file mode 100644 index 0000000..fe82b96 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Iterables.java @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Wen Tao. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesToFilter; + +import java.beans.Introspector; +import java.lang.reflect.Method; + +public class Iterables implements PropertyNameExtractor, AppliesToFilter +{ + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class fragmentClass ) + { + return matches( method.getName() ); + } + + public boolean matches( String methodName ) + { + return methodName.endsWith( "Iterator" ) || "iterator".equals( methodName ); + } + + public String extractPropertyName( String methodName ) + { + if( !matches( methodName ) ) + { + return null; + } + return Introspector.decapitalize( methodName.substring( 0, methodName.length() - 8 ) ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/MethodPrefixFilter.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/MethodPrefixFilter.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/MethodPrefixFilter.java new file mode 100644 index 0000000..bcb7634 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/MethodPrefixFilter.java @@ -0,0 +1,47 @@ +/* + * Copyright 2008 Wen Tao. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesToFilter; + +import java.beans.Introspector; +import java.lang.reflect.Method; + +public class MethodPrefixFilter implements PropertyNameExtractor, AppliesToFilter +{ + private String prefix; + + public MethodPrefixFilter( String prefix ) + { + this.prefix = prefix; + } + + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class fragmentClass ) + { + return matches( method.getName() ); + } + + public boolean matches( String methodName ) + { + return methodName.startsWith( prefix ); + } + + public String extractPropertyName( String methodName ) + { + if( !matches( methodName ) ) + { + return null; + } + return Introspector.decapitalize( methodName.substring( prefix.length() ) ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/OrAppliesToFilter.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/OrAppliesToFilter.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/OrAppliesToFilter.java new file mode 100644 index 0000000..87a4673 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/OrAppliesToFilter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2008 Wen Tao. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesToFilter; + +import java.lang.reflect.Method; + +public final class OrAppliesToFilter + implements AppliesToFilter +{ + private final AppliesToFilter[] filters; + + public OrAppliesToFilter( AppliesToFilter... filters ) + { + this.filters = filters; + } + + public final boolean appliesTo( Method method, Class mixin, Class compositeType, Class fragmentClass ) + { + for( AppliesToFilter filter : filters ) + { + if( filter.appliesTo( method, mixin, compositeType, fragmentClass ) ) + { + return true; + } + } + return false; + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Properties.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Properties.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Properties.java new file mode 100644 index 0000000..920b349 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Properties.java @@ -0,0 +1,108 @@ +/* + * Copyright 2008 Wen Tao. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +class Properties +{ + private Map properties = new HashMap(); + private static final String PREFIX_LIST_NAME = "l:"; + private static final String PREFIX_VALUE_NAME = "v:"; + + public Object get( String propertyName ) + { + String name = encodeValueName( propertyName ); + return properties.get( name ); + } + + public void set( String propertyName, Object value ) + { + String name = encodeValueName( propertyName ); + if( value == null ) + { + properties.remove( name ); + } + else + { + properties.put( name, value ); + } + } + + public void add( String propertyName, Object value ) + { + String name = encodeListName( propertyName ); + ArrayList list = (ArrayList) properties.get( name ); + if( list == null ) + { + list = new ArrayList(); + properties.put( name, list ); + } + list.add( value ); + } + + public void remove( String propertyName, Object value ) + { + String name = encodeListName( propertyName ); + ArrayList list = (ArrayList) properties.get( name ); + if( list != null ) + { + list.remove( value ); + if( list.size() == 0 ) + { + properties.remove( name ); + } + } + } + + public Iterator iterator( String propertyName ) + { + String name = encodeListName( propertyName ); + ArrayList list = (ArrayList) properties.get( name ); + if( list != null ) + { + return list.iterator(); + } + return new Iterator() + { + public boolean hasNext() + { + return false; + } + + public Object next() + { + return null; + } + + public void remove() + { + } + }; + } + + private String encodeValueName( String propertyName ) + { + return PREFIX_VALUE_NAME + propertyName; + } + + private String encodeListName( String propertyName ) + { + return PREFIX_LIST_NAME + propertyName; + } + +} + http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertiesMixin.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertiesMixin.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertiesMixin.java new file mode 100644 index 0000000..4032870 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertiesMixin.java @@ -0,0 +1,142 @@ +/* + * Copyright 2007 Rickard Öberg. All Rights Reserved. + * Copyright 2007 Alin Dreghiciu. All Rights Reserved. + * Copyright 2007 Edward Yakop. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesTo; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * Generic property mixin. Methods in interface + * can be of the following types: + * setFoo = set property named foo + * getFoo = get property named foo + * addFoo = add object to list named foo + * removeFoo = remove object from list named foo + * fooIterator - return an iterator over the list of Foos + */ +@AppliesTo( { Getters.class, Setters.class, Iterables.class } ) +public class PropertiesMixin implements InvocationHandler +{ + private static final PropertyHandler[] HANDLERS = new PropertyHandler[] + { + new AbstractPropertyHandler( Setters.SET ) + { + protected Object handleProperty( Properties properties, String propertyName, Object[] args ) + { + properties.set( propertyName, args[ 0 ] ); + return null; + } + }, + new GetPropertyHandler( Getters.GET ), + new GetPropertyHandler( Getters.IS ), + new GetPropertyHandler( Getters.HAS ), + new AbstractPropertyHandler( Setters.ADD ) + { + public Object handleProperty( Properties properties, String propertyName, Object[] args ) + { + properties.add( propertyName, args[ 0 ] ); + return null; + } + }, + new AbstractPropertyHandler( Setters.REMOVE ) + { + protected Object handleProperty( Properties properties, String propertyName, Object[] args ) + { + properties.remove( propertyName, args[ 0 ] ); + return null; + } + }, + new AbstractPropertyHandler( new Iterables() ) + { + protected Object handleProperty( Properties properties, String propertyName, Object[] args ) + { + return properties.iterator( propertyName ); + } + } + }; + + // Attributes ---------------------------------------------------- + Properties properties; + + /** + * Construct and empty properties mixins. + * + * @since 0.1.0 + */ + public PropertiesMixin() + { + properties = new Properties(); + } + + // InvocationHandler implementation ------------------------------ + @SuppressWarnings( "unchecked" ) + public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable + { + String methodName = method.getName(); + for( PropertyHandler handler : HANDLERS ) + { + if( handler.shouldHandle( methodName ) ) + { + return handler.handleInvocation( properties, methodName, args ); + } + } + return null; + } + + private interface PropertyHandler + { + boolean shouldHandle( String methodName ); + + Object handleInvocation( Properties properties, String methodName, Object[] args ); + } + + private static abstract class AbstractPropertyHandler implements PropertyHandler + { + private PropertyNameExtractor propertyNameExtractor; + + public AbstractPropertyHandler( PropertyNameExtractor propertyNameExtractor ) + { + this.propertyNameExtractor = propertyNameExtractor; + } + + public Object handleInvocation( Properties properties, String methodName, Object[] args ) + { + String propertyName = propertyNameExtractor.extractPropertyName( methodName ); + return handleProperty( properties, propertyName, args ); + } + + protected abstract Object handleProperty( Properties properties, String propertyName, Object[] args ); + + public boolean shouldHandle( String methodName ) + { + return propertyNameExtractor.extractPropertyName( methodName ) != null; + } + } + + private static final class GetPropertyHandler extends AbstractPropertyHandler + { + public GetPropertyHandler( PropertyNameExtractor propertyNameExtractor ) + { + super( propertyNameExtractor ); + } + + protected Object handleProperty( Properties properties, String propertyName, Object[] args ) + { + return properties.get( propertyName ); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertyNameExtractor.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertyNameExtractor.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertyNameExtractor.java new file mode 100644 index 0000000..1ad2d53 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/PropertyNameExtractor.java @@ -0,0 +1,18 @@ +/* + * Copyright 2008 Wen Tao. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package org.qi4j.library.beans.properties; + +public interface PropertyNameExtractor +{ + String extractPropertyName( String methodName ); +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Setters.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Setters.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Setters.java new file mode 100644 index 0000000..19d1404 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/properties/Setters.java @@ -0,0 +1,21 @@ +package org.qi4j.library.beans.properties; + +import org.qi4j.api.common.AppliesToFilter; + +import java.lang.reflect.Method; + +/** + * Filter for setter methods. Method name must match "set*","add*" or "remove*". + */ +public class Setters implements AppliesToFilter +{ + public static final MethodPrefixFilter SET = new MethodPrefixFilter( "set" ); + public static final MethodPrefixFilter ADD = new MethodPrefixFilter( "add" ); + public static final MethodPrefixFilter REMOVE = new MethodPrefixFilter( "remove" ); + public static final AppliesToFilter SETTERS = new OrAppliesToFilter( SET, ADD, REMOVE ); + + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class modelClass ) + { + return SETTERS.appliesTo( method, mixin, compositeType, modelClass ); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingIterator.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingIterator.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingIterator.java new file mode 100644 index 0000000..c8bb012 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingIterator.java @@ -0,0 +1,53 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import org.qi4j.api.composite.TransientBuilderFactory; + +import java.util.Iterator; +import org.qi4j.api.association.AssociationDescriptor; + +public class DelegatingIterator + implements Iterator +{ + private Iterator source; + private final AssociationDescriptor info; + private final TransientBuilderFactory cbf; + + public DelegatingIterator( Iterator source, AssociationDescriptor info, TransientBuilderFactory cbf ) + { + this.source = source; + this.info = info; + this.cbf = cbf; + } + + public boolean hasNext() + { + return source.hasNext(); + } + + public Object next() + { + return Wrapper.wrap( source.next(), info, cbf ); + } + + public void remove() + { + source.remove(); + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingListIterator.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingListIterator.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingListIterator.java new file mode 100644 index 0000000..4dc5fb5 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/DelegatingListIterator.java @@ -0,0 +1,83 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import org.qi4j.api.composite.TransientBuilderFactory; + +import java.util.ListIterator; +import org.qi4j.api.association.AssociationDescriptor; + +public class DelegatingListIterator + implements ListIterator +{ + private ListIterator source; + private final AssociationDescriptor info; + private final TransientBuilderFactory cbf; + + public DelegatingListIterator( ListIterator source, AssociationDescriptor info, TransientBuilderFactory cbf ) + { + this.source = source; + this.info = info; + this.cbf = cbf; + } + + public boolean hasNext() + { + return source.hasNext(); + } + + public Object next() + { + return Wrapper.wrap( source.next(), info, cbf ); + } + + public boolean hasPrevious() + { + return source.hasPrevious(); + } + + public Object previous() + { + return Wrapper.wrap( source.previous(), info, cbf ); + } + + public int nextIndex() + { + return source.nextIndex(); + } + + public int previousIndex() + { + return source.previousIndex(); + } + + public void remove() + { + source.remove(); + } + + public void set( Object o ) + { + throw new UnsupportedOperationException( "Read Only." ); + } + + public void add( Object o ) + { + throw new UnsupportedOperationException( "Read Only." ); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanAssociation.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanAssociation.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanAssociation.java new file mode 100644 index 0000000..a30e495 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanAssociation.java @@ -0,0 +1,97 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import org.qi4j.api.common.QualifiedName; +import org.qi4j.api.association.Association; +import org.qi4j.api.composite.TransientBuilder; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.UndeclaredThrowableException; +import org.qi4j.api.association.AssociationDescriptor; + +public class JavabeanAssociation + implements Association +{ + private final JavabeanMixin javabeanMixin; + private final AssociationDescriptor descriptor; + public final Method pojoMethod; + + public JavabeanAssociation( JavabeanMixin javabeanMixin, AssociationDescriptor descriptor, Method pojoMethod ) + { + this.javabeanMixin = javabeanMixin; + this.descriptor = descriptor; + this.pojoMethod = pojoMethod; + } + + public T metaInfo( Class infoType ) + { + return descriptor.metaInfo( infoType ); + } + + public QualifiedName qualifiedName() + { + return descriptor.qualifiedName(); + } + + public Type type() + { + return descriptor.type(); + } + + public boolean isImmutable() + { + return descriptor.isImmutable(); + } + + public boolean isAggregated() + { + return descriptor.isAggregated(); + } + + public Object get() + { + try + { + Object resultObject = pojoMethod.invoke( javabeanMixin.pojo ); + Class type = (Class) type(); + if( type.isInterface() ) + { + TransientBuilder builder = javabeanMixin.cbf.newTransientBuilder( type ); + builder.use( resultObject ); + return builder.newInstance(); + } + return resultObject; + } + catch( IllegalAccessException e ) + { + throw new IllegalArgumentException( "POJO is not compatible with JavaBeans specification. Method must be public: " + pojoMethod ); + } + catch( InvocationTargetException e ) + { + throw new UndeclaredThrowableException( e.getTargetException() ); + } + } + + public void set( Object associated ) throws IllegalArgumentException + { + //TODO: Auto-generated, need attention. + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanManyAssociation.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanManyAssociation.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanManyAssociation.java new file mode 100644 index 0000000..c8a96b8 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanManyAssociation.java @@ -0,0 +1,202 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import org.qi4j.api.common.QualifiedName; +import org.qi4j.api.association.AssociationDescriptor; +import org.qi4j.api.association.ManyAssociation; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.List; + +public class JavabeanManyAssociation + implements ManyAssociation +{ + private final JavabeanMixin javabeanMixin; + private final AssociationDescriptor descriptor; + private final Method pojoMethod; + + public JavabeanManyAssociation( JavabeanMixin javabeanMixin, AssociationDescriptor descriptor, Method pojoMethod ) + { + this.javabeanMixin = javabeanMixin; + this.descriptor = descriptor; + this.pojoMethod = pojoMethod; + } + + public T metaInfo( Class infoType ) + { + return descriptor.metaInfo( infoType ); + } + + public QualifiedName qualifiedName() + { + return descriptor.qualifiedName(); + } + + public Type type() + { + return descriptor.type(); + } + + public boolean isImmutable() + { + return descriptor.isImmutable(); + } + + public boolean isAggregated() + { + return descriptor.isAggregated(); + } + + public int size() + { + return delegate().size(); + } + + public boolean isEmpty() + { + return delegate().isEmpty(); + } + + public int count() + { + return 0; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean contains( Object object ) + { + return delegate().contains( Wrapper.unwrap( object ) ); + } + + public boolean add( int i, Object entity ) + { + return false; //To change body of implemented methods use File | Settings | File Templates. + } + + public Iterator iterator() + { + return new DelegatingIterator( delegate().iterator(), descriptor, javabeanMixin.cbf ); + } + + public Object[] toArray() + { + Object[] objects = delegate().toArray(); + Object[] wrapped = new Object[objects.length]; + for( int i = 0; i < objects.length; i++ ) + { + wrapped[ i ] = Wrapper.wrap( objects[ i ], descriptor, javabeanMixin.cbf ); + } + return wrapped; + } + + public boolean add( Object object ) + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public boolean remove( Object object ) + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public Object get( int i ) + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public List toList() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public Set toSet() + { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean addAll( Collection collection ) + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public void clear() + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public boolean retainAll( Collection collection ) + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public boolean removeAll( Collection collection ) + { + throw new UnsupportedOperationException( "Read/only." ); + } + + public boolean containsAll( Collection collection ) + { + for( Object obj : collection ) + { + if( !contains( Wrapper.unwrap( obj ) ) ) + { + return false; + } + } + return true; + } + + public Object[] toArray( Object[] objects ) + { + Object[] array = delegate().toArray( objects ); + for( int i = 0; i < array.length; i++ ) + { + array[ i ] = Wrapper.wrap( array[ i ], descriptor, javabeanMixin.cbf ); + } + return array; + } + + private Set delegate() + { + try + { + Object resultObject = pojoMethod.invoke( javabeanMixin.pojo ); + return (Set) resultObject; + } + catch( IllegalAccessException e ) + { + throw new IllegalArgumentException( "Javabean is not compatible with JavaBeans specification. Method must be public: " + pojoMethod ); + } + catch( ClassCastException e ) + { + throw new IllegalArgumentException( "Javabean and Qi4j models are not compatible. Expected a java.util.Set in return type of " + pojoMethod ); + } + catch( InvocationTargetException e ) + { + throw new UndeclaredThrowableException( e.getTargetException() ); + } + } + + +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanMixin.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanMixin.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanMixin.java new file mode 100644 index 0000000..b6b6772 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanMixin.java @@ -0,0 +1,139 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.qi4j.library.beans.support; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.HashMap; +import org.qi4j.api.Qi4j; +import org.qi4j.api.common.AppliesTo; +import org.qi4j.api.common.AppliesToFilter; +import org.qi4j.api.composite.Composite; +import org.qi4j.api.composite.TransientBuilderFactory; +import org.qi4j.api.association.Association; +import org.qi4j.api.association.AssociationDescriptor; +import org.qi4j.api.association.AssociationStateDescriptor; +import org.qi4j.api.association.ManyAssociation; +import org.qi4j.api.composite.CompositeDescriptor; +import org.qi4j.api.composite.StateDescriptor; +import org.qi4j.api.composite.StatefulCompositeDescriptor; +import org.qi4j.api.injection.scope.Structure; +import org.qi4j.api.injection.scope.This; +import org.qi4j.api.injection.scope.Uses; +import org.qi4j.api.property.Property; +import org.qi4j.api.property.PropertyDescriptor; +import org.qi4j.api.structure.Module; + +@AppliesTo( { JavabeanMixin.JavabeanSupportFilter.class } ) +public class JavabeanMixin + implements JavabeanSupport, InvocationHandler +{ + private HashMap handlers; + + @Structure TransientBuilderFactory cbf; + Object pojo; + + public JavabeanMixin( @Structure Module module, @This Composite thisComposite, @Uses Object pojo ) + { + this.pojo = pojo; + this.handlers = new HashMap(); + CompositeDescriptor thisDescriptor = Qi4j.FUNCTION_DESCRIPTOR_FOR.map( thisComposite ); + if( thisDescriptor instanceof StatefulCompositeDescriptor ) + { + StateDescriptor stateDescriptor = ( (StatefulCompositeDescriptor) thisDescriptor ).state(); + for( PropertyDescriptor propDesc : stateDescriptor.properties() ) + { + Method pojoMethod = findMethod( pojo, propDesc.qualifiedName().name() ); + handlers.put( propDesc.accessor(), new JavabeanProperty( this, propDesc, pojoMethod ) ); + } + if( stateDescriptor instanceof AssociationStateDescriptor ) + { + AssociationStateDescriptor assocStateDesc = (AssociationStateDescriptor) stateDescriptor; + for( AssociationDescriptor assocDesc : assocStateDesc.associations() ) + { + Method pojoMethod = findMethod( pojo, assocDesc.qualifiedName().name() ); + handlers.put( assocDesc.accessor(), new JavabeanAssociation( this, assocDesc, pojoMethod ) ); + } + for( AssociationDescriptor assocDesc : assocStateDesc.manyAssociations() ) + { + Method pojoMethod = findMethod( pojo, assocDesc.qualifiedName().name() ); + handlers.put( assocDesc.accessor(), new JavabeanManyAssociation( this, assocDesc, pojoMethod ) ); + } + } + } + } + + private Method findMethod( Object pojo, String name ) + { + String methodName = "get" + Character.toUpperCase( name.charAt( 0 ) ) + name.substring( 1 ); + Method pojoMethod; + try + { + pojoMethod = pojo.getClass().getMethod( methodName ); + } + catch( NoSuchMethodException e ) + { + methodName = "is" + Character.toUpperCase( name.charAt( 0 ) ) + name.substring( 1 ); + try + { + pojoMethod = pojo.getClass().getMethod( methodName ); + } + catch( NoSuchMethodException e1 ) + { + throw new IllegalArgumentException( methodName + " is not present in " + pojo.getClass() ); + } + } + return pojoMethod; + } + + public Object getJavabean() + { + return pojo; + } + + public void setJavabean( Object data ) + { + pojo = data; + } + + public Object invoke( Object proxy, Method method, Object[] args ) + throws Throwable + { + synchronized( this ) + { + return handlers.get( method ); + } + } + + public static class JavabeanSupportFilter + implements AppliesToFilter + { + public boolean appliesTo( Method method, Class mixin, Class compositeType, Class modifierClass ) + { + String methodName = method.getName(); + Class retType = method.getReturnType(); + return Property.class.isAssignableFrom( retType ) || + Association.class.isAssignableFrom( retType ) || + ManyAssociation.class.isAssignableFrom( retType ) || + "getJavabean".equals( methodName ) || "setJavabean".equals( methodName ); + } + } + +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanProperty.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanProperty.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanProperty.java new file mode 100644 index 0000000..6ca01f7 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanProperty.java @@ -0,0 +1,123 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.Arrays; +import java.util.List; +import org.qi4j.api.composite.TransientBuilder; +import org.qi4j.api.composite.TransientBuilderFactory; +import org.qi4j.api.property.Property; +import org.qi4j.api.property.PropertyDescriptor; + +public class JavabeanProperty implements Property +{ + private final JavabeanMixin javabeanMixin; + private final PropertyDescriptor descriptor; + private final Method pojoMethod; + + public JavabeanProperty( JavabeanMixin javabeanMixin, PropertyDescriptor descriptor, Method pojoMethod ) + { + this.javabeanMixin = javabeanMixin; + this.descriptor = descriptor; + this.pojoMethod = pojoMethod; + } + + public Object get() + { + try + { + Object resultObject = pojoMethod.invoke( javabeanMixin.pojo ); + return wrap( javabeanMixin.cbf, resultObject ); + } + catch( IllegalAccessException e ) + { + throw new IllegalArgumentException( "POJO is not compatible with JavaBeans specification. Method must be public: " + pojoMethod ); + } + catch( InvocationTargetException e ) + { + throw new UndeclaredThrowableException( e.getTargetException() ); + } + } + + private Object wrap( TransientBuilderFactory factory, Object resultObject ) + { + if( resultObject == null ) + { + return null; + } + Type type = descriptor.type(); + if( type instanceof Class ) + { + Class clazz = (Class) type; + if( clazz.isInterface() ) + { + if( clazz.equals( List.class ) ) + { + if( resultObject.getClass().isArray() ) + { + resultObject = Arrays.asList( (Object[]) resultObject ); + } + } + if( clazz.isArray() ) + { + if( List.class.isAssignableFrom( resultObject.getClass() ) ) + { + resultObject = ( (List) resultObject ).toArray(); + } + } + TransientBuilder builder = factory.newTransientBuilder( clazz ); + builder.use( resultObject ); + return builder.newInstance(); + } + } + if( type instanceof ParameterizedType ) + { + if( !resultObject.getClass().equals( type ) ) + { + ParameterizedType paramtype = (ParameterizedType) type; + Type rawType = paramtype.getRawType(); + Type actType = paramtype.getActualTypeArguments()[ 0 ]; + if( List.class.isAssignableFrom( (Class) rawType ) ) + { + if( !( actType instanceof Class ) || + ( (Class) actType ).isInstance( resultObject ) ) + { + String message = "The type " + paramtype + " is not compatible with " + resultObject.getClass(); + throw new IllegalArgumentException( message ); + } + if( resultObject.getClass().isArray() ) + { + resultObject = Arrays.asList( (Object[]) resultObject ); + } + } + } + } + return resultObject; + } + + public void set( Object newValue ) + throws IllegalArgumentException, IllegalStateException + { + //TODO: Auto-generated, need attention. + } +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanSupport.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanSupport.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanSupport.java new file mode 100644 index 0000000..faa9e96 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/JavabeanSupport.java @@ -0,0 +1,33 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.qi4j.library.beans.support; + +import org.qi4j.api.mixin.Mixins; + +/** + * This mixin type is used to have a POJO (Spring's definition) as the backing implementation + * of the mixin state. + */ +@Mixins( JavabeanMixin.class ) +public interface JavabeanSupport +{ + T getJavabean(); + + void setJavabean( T data ); +} http://git-wip-us.apache.org/repos/asf/zest-sandbox/blob/d4dd9c17/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/Wrapper.java ---------------------------------------------------------------------- diff --git a/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/Wrapper.java b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/Wrapper.java new file mode 100644 index 0000000..d717f75 --- /dev/null +++ b/qi4j/libraries/beans/src/main/java/org/qi4j/library/beans/support/Wrapper.java @@ -0,0 +1,47 @@ +/* + * Copyright 2008 Niclas Hedhman. All rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.qi4j.library.beans.support; + +import org.qi4j.api.composite.TransientBuilderFactory; +import org.qi4j.api.composite.TransientBuilder; +import org.qi4j.api.association.AssociationDescriptor; + +public class Wrapper +{ + static Object wrap( Object resultObject, AssociationDescriptor info, TransientBuilderFactory cbf ) + { + Class type = (Class) info.type(); + if( type.isInterface() ) + { + TransientBuilder builder = cbf.newTransientBuilder( type ); + builder.use( resultObject ); + return builder.newInstance(); + } + return resultObject; + } + + static Object unwrap( Object object ) + { + if( object instanceof JavabeanSupport ) + { + return ( (JavabeanSupport) object ).getJavabean(); + } + return object; + } + +}