This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-saga.git
commit de1479a6e0e6d352e4e24ca2cb45b97207485146 Author: seanyinx <[email protected]> AuthorDate: Fri Dec 22 16:13:56 2017 +0800 SCB-96 sent serialized message pre transactional Signed-off-by: seanyinx <[email protected]> --- omega/omega-transaction/pom.xml | 35 ++++++++- .../saga/omega/transaction/MessageSender.java | 22 ++++++ .../saga/omega/transaction/MessageSerializer.java | 22 ++++++ .../transaction/PreTransactionInterceptor.java | 32 +++++++++ .../saga/omega/transaction/TransactionAspect.java | 48 +++++++++++++ .../omega/transaction/TransactionAspectConfig.java | 32 +++++++++ .../transaction/PreTransactionInterceptorTest.java | 49 +++++++++++++ .../transaction/TransactionInterceptionTest.java | 82 ++++++++++++++++++++++ .../omega/transaction/TransactionTestMain.java | 28 ++++++++ .../transaction/TransactionalUserService.java | 38 ++++++++++ .../servicecomb/saga/omega/transaction/User.java | 49 +++++++++++++ .../saga/omega/transaction/UserRepository.java | 23 ++++++ 12 files changed, 459 insertions(+), 1 deletion(-) diff --git a/omega/omega-transaction/pom.xml b/omega/omega-transaction/pom.xml index b47e073..569e07f 100644 --- a/omega/omega-transaction/pom.xml +++ b/omega/omega-transaction/pom.xml @@ -31,8 +31,41 @@ <dependencies> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-jdbc</artifactId> + <artifactId>spring-boot-starter</artifactId> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-all</artifactId> + </dependency> + <dependency> + <groupId>com.github.seanyinx</groupId> + <artifactId>unit-scaffolding</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> </project> \ No newline at end of file diff --git a/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSender.java b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSender.java new file mode 100644 index 0000000..ab7bbaa --- /dev/null +++ b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSender.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +public interface MessageSender { + void send(byte[] message); +} diff --git a/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSerializer.java b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSerializer.java new file mode 100644 index 0000000..1a88f13 --- /dev/null +++ b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/MessageSerializer.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +public interface MessageSerializer { + byte[] serialize(Object[] message); +} diff --git a/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptor.java b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptor.java new file mode 100644 index 0000000..089ba32 --- /dev/null +++ b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptor.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +class PreTransactionInterceptor { + private final MessageSender sender; + private final MessageSerializer serializer; + + PreTransactionInterceptor(MessageSender sender, MessageSerializer serializer) { + this.sender = sender; + this.serializer = serializer; + } + + void intercept(Object... message) { + sender.send(serializer.serialize(message)); + } +} diff --git a/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspect.java b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspect.java new file mode 100644 index 0000000..00f283a --- /dev/null +++ b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspect.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Aspect +class TransactionAspect { + private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final PreTransactionInterceptor preTransactionInterceptor; + + + TransactionAspect(MessageSerializer serializer, MessageSender sender) { + this.preTransactionInterceptor = new PreTransactionInterceptor(sender, serializer); + } + + @Around("execution(@javax.transaction.Transactional * *(..))") + Object advise(ProceedingJoinPoint joinPoint) throws Throwable { + Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); + LOG.debug("Intercepting transactional method {}", method.toString()); + + preTransactionInterceptor.intercept(joinPoint.getArgs()); + return joinPoint.proceed(); + } +} diff --git a/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspectConfig.java b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspectConfig.java new file mode 100644 index 0000000..5a9cd5e --- /dev/null +++ b/omega/omega-transaction/src/main/java/io/servicecomb/saga/omega/transaction/TransactionAspectConfig.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; + +@Configuration +@EnableAspectJAutoProxy +class TransactionAspectConfig { + + @Bean + TransactionAspect transactionAspect(MessageSerializer serializer, MessageSender sender) { + return new TransactionAspect(serializer, sender); + } +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptorTest.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptorTest.java new file mode 100644 index 0000000..fd7414e --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/PreTransactionInterceptorTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +public class PreTransactionInterceptorTest { + private final List<byte[]> messages = new ArrayList<>(); + + private final MessageSender sender = messages::add; + private final MessageSerializer serializer = messages -> { + if (messages[0] instanceof String) { + return ((String) messages[0]).getBytes(); + } + throw new IllegalArgumentException("Expected instance of String, but was " + messages.getClass()); + }; + + private final String message = uniquify("message"); + private final PreTransactionInterceptor interceptor = new PreTransactionInterceptor(sender, serializer); + + @Test + public void sendsSerializedMessage() throws Exception { + interceptor.intercept(message); + + assertThat(messages, contains(message.getBytes())); + } +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionInterceptionTest.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionInterceptionTest.java new file mode 100644 index 0000000..495ed27 --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionInterceptionTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import static com.seanyinx.github.unit.scaffolding.Randomness.uniquify; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringRunner; + +import io.servicecomb.saga.omega.transaction.TransactionInterceptionTest.MessageConfig; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = {TransactionTestMain.class, MessageConfig.class}) +public class TransactionInterceptionTest { + private final String username = uniquify("username"); + private final String email = uniquify("email"); + + @Autowired + private List<byte[]> messages; + + @Autowired + private TransactionalUserService userService; + + @Test + public void sendsUserToRemote_BeforeTransaction() throws Exception { + userService.add(new User(username, email)); + + assertThat(messages, contains((username + ":" + email).getBytes())); + } + + @Configuration + static class MessageConfig { + private final List<byte[]> messages = new ArrayList<>(); + + @Bean + List<byte[]> messages() { + return messages; + } + + @Bean + MessageSender sender() { + return messages::add; + } + + @Bean + MessageSerializer serializer() { + return messages -> { + if (messages[0] instanceof User) { + User user = ((User) messages[0]); + return (user.username() + ":" + user.email()).getBytes(); + } + throw new IllegalArgumentException("Expected instance of User, but was " + messages.getClass()); + }; + } + } + +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionTestMain.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionTestMain.java new file mode 100644 index 0000000..1df292c --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionTestMain.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TransactionTestMain { + public static void main(String[] args) { + SpringApplication.run(TransactionTestMain.class, args); + } +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionalUserService.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionalUserService.java new file mode 100644 index 0000000..d4346a0 --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/TransactionalUserService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import javax.transaction.Transactional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +class TransactionalUserService { + private final UserRepository userRepository; + + @Autowired + TransactionalUserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Transactional + void add(User user) { + userRepository.save(user); + } +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/User.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/User.java new file mode 100644 index 0000000..f8034a7 --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/User.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class User { + @Id + @GeneratedValue + private long id; + + private String username; + private String email; + + public User(String username, String email) { + this.username = username; + this.email = email; + } + + public long id() { + return id; + } + + public String username() { + return username; + } + + public String email() { + return email; + } +} diff --git a/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/UserRepository.java b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/UserRepository.java new file mode 100644 index 0000000..60cf93f --- /dev/null +++ b/omega/omega-transaction/src/test/java/io/servicecomb/saga/omega/transaction/UserRepository.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.servicecomb.saga.omega.transaction; + +import org.springframework.data.repository.CrudRepository; + +public interface UserRepository extends CrudRepository<User, Long> { +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
