Skip to content

Commit d2ce331

Browse files
committed
WIP
1 parent 9bae531 commit d2ce331

File tree

6 files changed

+243
-0
lines changed

6 files changed

+243
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.arpnetworking.akka;
2+
3+
import akka.actor.ActorRef;
4+
import akka.actor.ActorSystem;
5+
import akka.actor.Props;
6+
import com.arpnetworking.commons.builder.OvalBuilder;
7+
import net.sf.oval.constraint.NotEmpty;
8+
import net.sf.oval.constraint.NotNull;
9+
import org.codehaus.jackson.map.annotate.JacksonInject;
10+
11+
import java.util.function.Function;
12+
13+
/**
14+
* Builder for actors.
15+
*
16+
* @param <B> The type of the builder
17+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
18+
*/
19+
public abstract class ActorBuilder<B extends ActorBuilder<B>> extends OvalBuilder<ActorRef> {
20+
/**
21+
* Protected constructor.
22+
*
23+
* @param createProps method to create a {@link Props} from the {@link ActorBuilder}
24+
*/
25+
protected ActorBuilder(final Function<B, Props> createProps) {
26+
super(B::createActor);
27+
_createProps = createProps;
28+
}
29+
30+
public B setActorName(final String value) {
31+
_actorName = value;
32+
return self();
33+
}
34+
35+
public B setActorSystem(final ActorSystem value) {
36+
_actorSystem = value;
37+
return self();
38+
}
39+
40+
/**
41+
* Creates an actor in the {@link ActorSystem}. DO NOT OVERRIDE.
42+
*
43+
* @return an {@link ActorRef} to a newly launched actor
44+
*/
45+
protected final ActorRef createActor(){
46+
return this._actorSystem.actorOf(_createProps.apply(self()));
47+
}
48+
49+
/**
50+
* Called by setters to always return appropriate subclass of
51+
* {@link ActorBuilder}, even from setters of base class.
52+
*
53+
* @return instance with correct {@link ActorBuilder} class type.
54+
*/
55+
protected abstract B self();
56+
57+
@NotNull
58+
@JacksonInject
59+
protected ActorSystem _actorSystem;
60+
61+
@NotNull
62+
@NotEmpty
63+
protected String _actorName;
64+
65+
private final Function<B, Props> _createProps;
66+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Copyright 2016 Inscope Metrics
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.arpnetworking.akka;
17+
18+
import akka.actor.Props;
19+
import akka.actor.UntypedActor;
20+
21+
/**
22+
* Actor that does not attempt to join a cluster.
23+
*
24+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
25+
*/
26+
public class NonJoiningClusterJoiner extends UntypedActor {
27+
/**
28+
* Static factory method for creating a {@link Props} to create a {@link NonJoiningClusterJoiner} actor.
29+
*
30+
* @return a new {@link Props}
31+
*/
32+
public static Props props() {
33+
return Props.create(NonJoiningClusterJoiner.class);
34+
}
35+
36+
/**
37+
* Static factory method for creating a {@link Props} to create a {@link NonJoiningClusterJoiner} actor from a
38+
* {@link Builder}.
39+
*
40+
* @param builder Builder to create the Props from
41+
* @return a new {@link Props}
42+
*/
43+
private static Props props(final Builder builder) {
44+
return props();
45+
}
46+
47+
/**
48+
* Public constructor.
49+
*/
50+
public NonJoiningClusterJoiner() {
51+
}
52+
53+
@Override
54+
public void onReceive(final Object message) throws Exception {
55+
unhandled(message);
56+
}
57+
58+
59+
public static class Builder extends ActorBuilder<Builder> {
60+
public Builder() {
61+
super(NonJoiningClusterJoiner::props);
62+
}
63+
64+
@Override
65+
public Builder self() {
66+
return this;
67+
}
68+
}
69+
}

src/main/java/com/arpnetworking/clusteraggregator/GuiceModule.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,14 @@ private ActorRef provideGracefulShutdownActor(final ActorSystem system, final In
358358
return system.actorOf(GuiceActorCreator.props(injector, GracefulShutdownActor.class), "graceful-shutdown");
359359
}
360360

361+
// @Provides
362+
// @Singleton
363+
// @Named("cluster-joiner")
364+
// @SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD") // Invoked reflectively by Guice
365+
// private ActorRef provideClusterJoiner(final ActorSystem system, final Injector injector) {
366+
// return system.actorOf(GuiceActorCreator.props(injector, NonJoiningClusterJoiner.class), "cluster-joiner");
367+
// }
368+
361369
@Provides
362370
@Named("cluster-host-suffix")
363371
@SuppressFBWarnings("UPM_UNCALLED_PRIVATE_METHOD") // Invoked reflectively by Guice

src/main/java/com/arpnetworking/clusteraggregator/Main.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424
import com.arpnetworking.configuration.jackson.HoconFileSource;
2525
import com.arpnetworking.configuration.jackson.JsonNodeFileSource;
2626
import com.arpnetworking.configuration.jackson.JsonNodeSource;
27+
import com.arpnetworking.configuration.jackson.akka.ActorBuilderDeserializer;
2728
import com.arpnetworking.configuration.triggers.FileTrigger;
2829
import com.arpnetworking.steno.Logger;
2930
import com.arpnetworking.utility.Configurator;
3031
import com.arpnetworking.utility.Database;
3132
import com.arpnetworking.utility.Launchable;
3233
import com.fasterxml.jackson.databind.ObjectMapper;
34+
import com.fasterxml.jackson.databind.module.SimpleModule;
3335
import com.google.common.collect.Lists;
3436
import com.google.inject.Guice;
3537
import com.google.inject.Injector;
@@ -97,6 +99,9 @@ public static void main(final String[] args) {
9799
final File configurationFile = new File(args[0]);
98100
configurator = Optional.of(new Configurator<>(Main::new, ClusterAggregatorConfiguration.class));
99101
final ObjectMapper objectMapper = ClusterAggregatorConfiguration.createObjectMapper();
102+
final SimpleModule module = new SimpleModule();
103+
module.addDeserializer(ActorRef.class, new ActorBuilderDeserializer(objectMapper));
104+
objectMapper.registerModule(module);
100105
configuration = Optional.of(new DynamicConfiguration.Builder()
101106
.setObjectMapper(objectMapper)
102107
.addSourceBuilder(getFileSourceBuilder(configurationFile, objectMapper))
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.arpnetworking.configuration.jackson.akka;
2+
3+
import akka.actor.ActorRef;
4+
import com.arpnetworking.commons.builder.Builder;
5+
import com.fasterxml.jackson.core.JsonParser;
6+
import com.fasterxml.jackson.core.JsonProcessingException;
7+
import com.fasterxml.jackson.core.TreeNode;
8+
import com.fasterxml.jackson.databind.DeserializationContext;
9+
import com.fasterxml.jackson.databind.JsonDeserializer;
10+
import com.fasterxml.jackson.databind.JsonMappingException;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.node.TextNode;
13+
14+
import java.io.IOException;
15+
16+
/**
17+
* Deserializer that will create an ActorBuilder for the given actor, then create the Actor from Guice
18+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
19+
*/
20+
public class ActorBuilderDeserializer extends JsonDeserializer<ActorRef> {
21+
/**
22+
* Public constructor.
23+
*
24+
* @param mapper the {@link ObjectMapper} to use to deserialize the {@link Builder}
25+
*/
26+
public ActorBuilderDeserializer(final ObjectMapper mapper) {
27+
_mapper = mapper;
28+
}
29+
30+
@Override
31+
public ActorRef deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
32+
final TreeNode treeNode = p.readValueAsTree();
33+
final String type = ((TextNode) treeNode.get("type")).textValue();
34+
try {
35+
final Class<?> clazz = Class.forName(type);
36+
final Class<? extends Builder<? extends ActorRef>> builder = getBuilderForClass(clazz);
37+
final Builder<? extends ActorRef> value = _mapper.readValue(treeNode.toString(), builder);
38+
return value.build();
39+
} catch (ClassNotFoundException e) {
40+
throw new JsonMappingException(p, String.format("Unable to find class %s referenced by ActorRef type", type));
41+
} finally {
42+
p.close();
43+
}
44+
}
45+
46+
@SuppressWarnings("unchecked")
47+
private static Class<? extends Builder<ActorRef>> getBuilderForClass(final Class<?> clazz)
48+
throws ClassNotFoundException {
49+
return (Class<? extends Builder<ActorRef>>) (Class.forName(
50+
clazz.getName() + "$Builder",
51+
true, // initialize
52+
clazz.getClassLoader()));
53+
}
54+
55+
private final ObjectMapper _mapper;
56+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.arpnetworking.clusteraggregator.configuration;
2+
3+
import akka.actor.ActorRef;
4+
import com.arpnetworking.akka.NonJoiningClusterJoiner;
5+
import com.arpnetworking.commons.jackson.databind.ObjectMapperFactory;
6+
import com.arpnetworking.configuration.jackson.akka.ActorBuilderDeserializer;
7+
import com.arpnetworking.utility.BaseActorTest;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.module.SimpleModule;
10+
import org.intellij.lang.annotations.Language;
11+
import org.junit.Test;
12+
13+
import java.io.IOException;
14+
15+
/**
16+
* @author Brandon Arp (brandon dot arp at inscopemetrics dot com)
17+
*/
18+
public class ActorBuilderTest extends BaseActorTest {
19+
@Test
20+
public void testBuild() {
21+
final NonJoiningClusterJoiner.Builder builder = new NonJoiningClusterJoiner.Builder();
22+
builder.setActorName("foo");
23+
builder.setActorSystem(getSystem());
24+
builder.build();
25+
}
26+
27+
@Test
28+
public void testPolyDeserialize() throws IOException {
29+
final ObjectMapper mapper = ObjectMapperFactory.createInstance();
30+
final SimpleModule module = new SimpleModule();
31+
module.addDeserializer(ActorRef.class, new ActorBuilderDeserializer(mapper));
32+
mapper.registerModule(module);
33+
34+
@Language("JSON") final String data = "{\n" +
35+
" \"type\": \"com.arpnetworking.akka.NonJoiningClusterJoiner\"\n" +
36+
"}";
37+
final ActorRef ref = mapper.readValue(data, ActorRef.class);
38+
}
39+
}

0 commit comments

Comments
 (0)