Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit db99803

Browse files
committed
POLYGENE-304 : Added library-execution with 3 initial features.
1 parent dcea137 commit db99803

13 files changed

Lines changed: 957 additions & 2 deletions

File tree

core/api/src/main/java/org/apache/polygene/api/concern/ConcernOf.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public abstract class ConcernOf<T>
4040
* the next concern in the chain or the mixin
4141
* to be invoked.
4242
*/
43-
final
43+
@SuppressWarnings( "ConstantConditions" )
4444
@ConcernFor
45-
protected T next = null;
45+
protected final T next = null;
4646
}

libraries/execution/build.gradle

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
*
19+
*/
20+
21+
apply plugin: 'polygene-library'
22+
23+
description = "Apache Polygene™ Execution Library provides common set of execution primitives and services."
24+
25+
jar { manifest { name = "Apache Polygene™ Library - Constraints"}}
26+
27+
dependencies {
28+
api polygene.core.bootstrap
29+
30+
api libraries.commons_validator
31+
32+
runtimeOnly polygene.core.runtime
33+
34+
testImplementation polygene.core.testsupport
35+
36+
testRuntimeOnly libraries.logback
37+
}

libraries/execution/dev-status.xml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<!--
3+
~ Licensed to the Apache Software Foundation (ASF) under one
4+
~ or more contributor license agreements. See the NOTICE file
5+
~ distributed with this work for additional information
6+
~ regarding copyright ownership. The ASF licenses this file
7+
~ to you under the Apache License, Version 2.0 (the
8+
~ "License"); you may not use this file except in compliance
9+
~ with the License. You may obtain a copy of the License at
10+
~
11+
~ http://www.apache.org/licenses/LICENSE-2.0
12+
~
13+
~ Unless required by applicable law or agreed to in writing, software
14+
~ distributed under the License is distributed on an "AS IS" BASIS,
15+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
~ See the License for the specific language governing permissions and
17+
~ limitations under the License.
18+
~
19+
~
20+
-->
21+
<module xmlns="http://polygene.apache.org/schemas/2008/dev-status/1"
22+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
23+
xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1
24+
http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd">
25+
<status>
26+
<!--none,early,beta,stable,mature-->
27+
<codebase>beta</codebase>
28+
29+
<!-- none, brief, good, complete -->
30+
<documentation>good</documentation>
31+
32+
<!-- none, some, good, complete -->
33+
<unittests>some</unittests>
34+
</status>
35+
<licenses>
36+
<license>ALv2</license>
37+
</licenses>
38+
</module>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
///////////////////////////////////////////////////////////////
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
///////////////////////////////////////////////////////////////
19+
20+
[[library-execution,Execution Library]]
21+
= Execution =
22+
23+
== @Retry ==
24+
Any method can be annotated with the @Retry annotation, which means that if there is an exception thrown, then
25+
the method should be called again, for a max number of times.
26+
27+
The value() defines how many times the method will be called, if retry is triggered by the on() and unless()
28+
parameters.
29+
30+
The backoff() parameter is available to slow down the retries, which is useful for network operations or
31+
external systems that may still need more time to become available. The default is no backoff is deployed and retries
32+
are executed as fast as possible.
33+
34+
The on() parameter defines which Throwable and subclasses should be considered for retrying the method call. The
35+
default is all Throwables.
36+
37+
The unless() parameter negates the on() parameter, and if a subclass of any Throwable listed in unless() is thrown
38+
then the retry operation(s) will not take effect.
39+
40+
== ExecutionService ==
41+
The =ExecutionService= is the =java.util.concurrent.ExecutorService= provided simply as a flexible assembler for
42+
configuration of it.
43+
44+
=== Configuration Parameters ===
45+
The Configuration parameters are available in the =ExecutionServiceAssembler= via a fluent API (DSL), with the
46+
following methods
47+
48+
[snippet,java]
49+
----
50+
source=libraries/execution/src/main/java/org/apache/polygene/library/execution/assembly/ExecutionServiceAssembler.java
51+
tag=configuration
52+
----
53+
54+
55+
== ScheduledExecutionService ==
56+
The =ScheduledExecutionService= is the =java.util.concurrent.ScheduledExecutorService= provided simply as a flexible
57+
assembler for configuration of it.
58+
59+
60+
=== Configuration Parameters ===
61+
The Configuration parameters are available in the =ScheduledExecutionService= via a fluent API (DSL), with the
62+
following methods
63+
64+
[snippet,java]
65+
----
66+
source=libraries/execution/src/main/java/org/apache/polygene/library/execution/assembly/ScheduledExecutionService.java
67+
tag=configuration
68+
----
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.apache.polygene.library.execution;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.Inherited;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.Target;
7+
8+
import static java.lang.annotation.ElementType.METHOD;
9+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
10+
11+
/**
12+
* &#64;Retry is a method annotation to automatically call the method again if an exception was thrown.
13+
* <p>
14+
* By default, the method will be called twice if any {@link java.lang.Throwable} is thrown. By setting
15+
* the value, one can increase that number, and the {@link #on()} and {@link #unless()} parameters can
16+
* be used to select which Throwable (incl its subtypes) the retry will happen on.
17+
* </p>
18+
* <p>
19+
* This can only be applied to idempotent methods, and keeping in mind the ordering of Concerns may
20+
* be very significant. E.g. If the {@link RetryConcern} is "around" the
21+
* {@link org.apache.polygene.api.unitofwork.concern.UnitOfWorkConcern} then depending on the parameters on
22+
* the {@link org.apache.polygene.api.unitofwork.concern.UnitOfWorkPropagation} will determine if the
23+
* method is still idempotent or not, in particular
24+
* {@link org.apache.polygene.api.unitofwork.concern.UnitOfWorkPropagation.Propagation#REQUIRES_NEW}. Furthermore,
25+
* {@link org.apache.polygene.api.unitofwork.concern.UnitOfWorkPropagation} has its own Retry mechanism independent
26+
* of this one.
27+
* </p>
28+
*/
29+
@Retention( RUNTIME )
30+
@Target( METHOD )
31+
@Inherited
32+
@Documented
33+
public @interface Retry
34+
{
35+
/**
36+
* Number of times that the method should be called.
37+
* <p>
38+
* This number must be 1 or greater, otherwise an {@link IllegalArgumentException} is thrown.
39+
* </p>
40+
*/
41+
int value() default 2;
42+
43+
/**
44+
* List of Throwables that should trigger the Retry operation.
45+
* <p>
46+
* Default: All Throwables.
47+
* </p>
48+
*/
49+
Class<? extends Throwable>[] on() default { Throwable.class };
50+
51+
/**
52+
* List of Throwables that should NOT trigger the Retry operation, even if they are subclasses found in the on() value
53+
* <p>
54+
* Default: none.
55+
* </p>
56+
*/
57+
Class<? extends Throwable>[] unless() default {};
58+
59+
/**
60+
* Slowing down of retries.
61+
* <p>
62+
* If the backoff is greater than 0 (default), there will be a successive backoff of retrying the call,
63+
* and starting with backoff() milliseconds, the sleep time between tries will double for each try.
64+
*/
65+
int backoff() default 0;
66+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.apache.polygene.library.execution;
2+
3+
import java.lang.reflect.InvocationHandler;
4+
import java.lang.reflect.Method;
5+
import java.util.Arrays;
6+
import java.util.HashSet;
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
import org.apache.polygene.api.common.AppliesTo;
10+
import org.apache.polygene.api.concern.ConcernOf;
11+
import org.apache.polygene.api.injection.scope.Invocation;
12+
13+
import static org.apache.polygene.api.util.Classes.classHierarchy;
14+
15+
@AppliesTo( Retry.class )
16+
public class RetryConcern extends ConcernOf<InvocationHandler>
17+
implements InvocationHandler
18+
{
19+
private final int retries;
20+
private final HashSet<Class<? extends Throwable>> on;
21+
private final HashSet<Object> unless;
22+
private final int backoff;
23+
24+
@SuppressWarnings( "unchecked" )
25+
public RetryConcern( @Invocation Retry annotation )
26+
{
27+
this.retries = annotation.value();
28+
if( retries < 1 )
29+
{
30+
throw new IllegalArgumentException( "@Retry must have a positive value greater than zero." );
31+
}
32+
this.on = new HashSet<>();
33+
List<Class<? extends Throwable>> on = Arrays.asList( annotation.on() );
34+
this.on.addAll( on );
35+
36+
this.unless = new HashSet<>();
37+
List<Class<? extends Throwable>> unless = Arrays.asList( annotation.unless() );
38+
this.unless.addAll( unless );
39+
this.backoff = annotation.backoff();
40+
}
41+
42+
@Override
43+
@SuppressWarnings( { "SuspiciousMethodCalls", "ConstantConditions" } )
44+
public Object invoke( Object o, Method method, Object[] objects )
45+
throws Throwable
46+
{
47+
int count = retries;
48+
long sleep = backoff;
49+
while( true )
50+
{
51+
try
52+
{
53+
return next.invoke( o, method, objects );
54+
}
55+
catch( Throwable e )
56+
{
57+
--count;
58+
List<Class<?>> types = classHierarchy( e.getClass() ).collect( Collectors.toList() );
59+
for( Class<?> type : types )
60+
{
61+
if( this.unless.contains( type ) )
62+
{
63+
throw e;
64+
}
65+
if( count == 0 && this.on.contains( type ))
66+
{
67+
throw e;
68+
}
69+
}
70+
if( sleep > 0 )
71+
{
72+
Thread.sleep( sleep );
73+
sleep = sleep * 2;
74+
}
75+
}
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)