├── .gitignore
├── README.txt
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── neo4j
│ └── smack
│ ├── Neo4jServer.java
│ ├── Smack.java
│ ├── api
│ ├── BasePropertyContainerService.java
│ ├── DataOperationsDiscoveryService.java
│ ├── DataOperationsService.java
│ ├── DatabaseService.java
│ ├── IndexService.java
│ ├── NodeService.java
│ ├── RelationshipService.java
│ ├── RestService.java
│ ├── TransactionService.java
│ ├── TraversalService.java
│ └── UrlReverseLookerUpper.java
│ ├── gcfree
│ ├── MutableString.java
│ └── MutableStringConverter.java
│ ├── pipeline
│ ├── CombinedHandler.java
│ ├── DaemonThreadFactory.java
│ ├── DefaultExceptionHandler.java
│ ├── RingBufferWorkPipeline.java
│ ├── core
│ │ ├── CoreWorkPipeline.java
│ │ ├── DeserializationHandler.java
│ │ ├── RoutingHandler.java
│ │ ├── TransactionPreparationHandler.java
│ │ ├── WorkDivisionHandler.java
│ │ ├── WorkPublisher.java
│ │ ├── WorkTransactionPreparer.java
│ │ └── event
│ │ │ ├── CorePipelineEvent.java
│ │ │ └── TransactionWork.java
│ ├── database
│ │ ├── DatabaseWorkPerformer.java
│ │ ├── DatabaseWorkPipeline.java
│ │ ├── ExceptionOutputWriter.java
│ │ ├── ThreadTransactionManagement.java
│ │ ├── TransactionRegistry.java
│ │ └── event
│ │ │ ├── DatabaseWork.java
│ │ │ ├── DefaultInvocationImpl.java
│ │ │ ├── Invocation.java
│ │ │ ├── NettyChannelBackedOutput.java
│ │ │ └── Output.java
│ ├── event
│ │ ├── Fallible.java
│ │ └── WorkTransactionMode.java
│ └── http
│ │ ├── CommonHeaderValues.java
│ │ ├── HttpDecoder.java
│ │ ├── HttpEncoder.java
│ │ ├── HttpHeaderContainer.java
│ │ ├── HttpHeaderDecoder.java
│ │ ├── HttpHeaderName.java
│ │ ├── HttpHeaderNames.java
│ │ ├── HttpTokens.java
│ │ ├── NettyChannelTrackingHandler.java
│ │ ├── NettyHttpHandler.java
│ │ └── NettyHttpPipelineFactory.java
│ ├── routing
│ ├── AnnotationBasedRoutingDefinition.java
│ ├── Endpoint.java
│ ├── InvocationVerb.java
│ ├── NotFoundEndpoint.java
│ ├── PathVariables.java
│ ├── ResettableQueryStringDecoder.java
│ ├── ResourceNotFoundException.java
│ ├── Routable.java
│ ├── RouteDefinitionEntry.java
│ ├── RouteEntry.java
│ ├── Router.java
│ ├── RoutingDefinition.java
│ ├── SimpleEndpoint.java
│ └── annotation
│ │ ├── DeserializeWith.java
│ │ ├── SerializeWith.java
│ │ └── Transactional.java
│ └── serialization
│ ├── DeserializationException.java
│ ├── DeserializationStrategy.java
│ ├── Deserializer.java
│ ├── IdentifiableEnum.java
│ ├── IdentifiableEnumDeserializer.java
│ ├── JsonDeserializer.java
│ ├── JsonSerializer.java
│ ├── SerializationException.java
│ ├── SerializationFactory.java
│ ├── SerializationStrategy.java
│ ├── Serializer.java
│ └── strategy
│ ├── ExceptionSerializationStrategy.java
│ ├── NodeSerializationStrategy.java
│ ├── PropertyContainerDeserialization.java
│ ├── PropertyContainerDeserializationStrategy.java
│ ├── PropertyContainerSerializationStrategy.java
│ ├── PropertyValueDeserializationStrategy.java
│ ├── PropertyValueSerializationStrategy.java
│ ├── RelationshipCreationDescription.java
│ ├── RelationshipCreationDeserializationStrategy.java
│ ├── RelationshipSerializationStrategy.java
│ ├── TransactionStateDeserialization.java
│ └── TransactionStateDeserializationStrategy.java
└── test
└── java
└── org
└── neo4j
└── smack
├── gcfree
└── TestMutableStringConverter.java
├── integration
└── api
│ ├── ClientIdIT.java
│ ├── DataAPIRootIT.java
│ ├── ErrorHandlingIT.java
│ ├── NodeServiceIT.java
│ ├── RelationshipServiceIT.java
│ └── TransactionServiceIT.java
├── performance
├── LoadGeneratingRunnable.java
├── NetworkLatency.java
├── NetworkThroughput.java
└── PerfTestServer.java
├── pipeline
├── core
│ └── TestWorkTransactionPreparer.java
└── http
│ ├── TestHttpDecoder.java
│ ├── TestHttpHeaderContainer.java
│ ├── TestHttpHeaderDecoder.java
│ └── TestHttpHeaderName.java
├── routing
├── TestAnnotationBasedRoutingDefinition.java
├── TestResettableQueryStringDecoder.java
└── TestRouter.java
├── serialization
├── TestDeserializationStrategy.java
├── TestJsonDeserializer.java
├── TestSerializationStrategy.java
└── strategy
│ ├── SerializationStrategyTestBase.java
│ ├── TestNodeSerializationStrategy.java
│ ├── TestPropertyContainerDeserializationStrategy.java
│ ├── TestRelationshipCreationDeserializationStrategy.java
│ ├── TestRelationshipSerializationStrategy.java
│ └── TestTransactionStateDeserializationStrategy.java
└── test
└── util
├── AbstractRestFunctionalTestBase.java
├── FixedRequestClient.java
├── JaxRsResponse.java
├── JsonHelper.java
├── PerformanceRoutes.java
├── PipelinedHttpClient.java
├── REST.java
├── RESTDocsGenerator.java
├── RestRequest.java
├── ServerHelper.java
├── ServerHolder.java
├── SharedSmackServerTestBase.java
├── Transactor.java
└── UnitOfWork.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 | .settings
4 | target
5 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/neo4j-contrib/fast-http/7f912fdff7cab9f31dc79a7628d11c2ba80bf0e8/README.txt
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/Neo4jServer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack;
21 |
22 | import java.io.IOException;
23 |
24 | import org.neo4j.graphdb.GraphDatabaseService;
25 | import org.neo4j.kernel.EmbeddedGraphDatabase;
26 | import org.neo4j.smack.api.DatabaseService;
27 |
28 | public class Neo4jServer {
29 |
30 | private Smack smackServer;
31 |
32 | public static void main(String[] args) throws IOException {
33 | final Neo4jServer neo4jServer = new Neo4jServer(args[0], Integer.parseInt(args[1]), new EmbeddedGraphDatabase(args[2]));
34 | neo4jServer.start();
35 | System.in.read();
36 | neo4jServer.stop();
37 | }
38 |
39 | public Neo4jServer(String host, int port, GraphDatabaseService db) {
40 | smackServer = new Smack(host, port, db);
41 | smackServer.addRoute("/db/data", new DatabaseService("/db/data"));
42 | }
43 |
44 | public void start() {
45 | smackServer.start();
46 | }
47 |
48 | public void stop() {
49 | smackServer.stop();
50 | }
51 |
52 | public Smack getSmackServer() {
53 | return smackServer;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/Smack.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack;
2 |
3 | import java.net.InetSocketAddress;
4 | import java.util.concurrent.Executors;
5 |
6 | import org.jboss.netty.bootstrap.ServerBootstrap;
7 | import org.jboss.netty.channel.group.ChannelGroup;
8 | import org.jboss.netty.channel.group.DefaultChannelGroup;
9 | import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
10 | import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
11 | import org.neo4j.graphdb.GraphDatabaseService;
12 | import org.neo4j.smack.pipeline.DaemonThreadFactory;
13 | import org.neo4j.smack.pipeline.DefaultExceptionHandler;
14 | import org.neo4j.smack.pipeline.core.CoreWorkPipeline;
15 | import org.neo4j.smack.pipeline.core.DeserializationHandler;
16 | import org.neo4j.smack.pipeline.core.RoutingHandler;
17 | import org.neo4j.smack.pipeline.core.TransactionPreparationHandler;
18 | import org.neo4j.smack.pipeline.core.WorkDivisionHandler;
19 | import org.neo4j.smack.pipeline.http.NettyHttpPipelineFactory;
20 | import org.neo4j.smack.routing.Endpoint;
21 | import org.neo4j.smack.routing.Router;
22 | import org.neo4j.smack.routing.RoutingDefinition;
23 |
24 | public class Smack {
25 |
26 | private int port;
27 | private String host;
28 | private Router router = new Router();
29 | private ServerBootstrap netty;
30 |
31 | private CoreWorkPipeline inputPipeline;
32 |
33 | private ServerSocketChannelFactory channelFactory;
34 | private ChannelGroup openChannels = new DefaultChannelGroup("SmackServer");
35 | private GraphDatabaseService database;
36 | private WorkDivisionHandler workDivisionHandler;
37 | private DefaultExceptionHandler exceptionHandler;
38 |
39 | public Smack(String host, int port, GraphDatabaseService db) {
40 | this.host = host;
41 | this.port = port;
42 | this.database = db;
43 | }
44 |
45 | public void start() {
46 |
47 | router.compileRoutes();
48 |
49 | // MAIN PIPELINE
50 |
51 | exceptionHandler = new DefaultExceptionHandler();
52 | workDivisionHandler = new WorkDivisionHandler(database, exceptionHandler);
53 |
54 | inputPipeline = new CoreWorkPipeline(exceptionHandler,
55 | new RoutingHandler(router),
56 | new DeserializationHandler(),
57 | new TransactionPreparationHandler(),
58 | workDivisionHandler);
59 |
60 | inputPipeline.start();
61 |
62 | // NETTY
63 |
64 | channelFactory =
65 | new NioServerSocketChannelFactory(
66 | Executors.newCachedThreadPool(new DaemonThreadFactory("SocketMaster")),
67 | Executors.newCachedThreadPool(new DaemonThreadFactory("SocketSlave")));
68 | netty = new ServerBootstrap(channelFactory);
69 |
70 | // Set up the event pipeline factory.
71 | netty.setPipelineFactory(new NettyHttpPipelineFactory(inputPipeline, openChannels));
72 |
73 | // Bind and start to accept incoming connections.
74 | openChannels.add(netty.bind(new InetSocketAddress(host, port)));
75 |
76 | }
77 |
78 | public void stop() {
79 | if (openChannels!=null) openChannels.close().awaitUninterruptibly();
80 | if (channelFactory!=null) channelFactory.releaseExternalResources();
81 | if (workDivisionHandler!=null) workDivisionHandler.stop();
82 | if (inputPipeline!=null) inputPipeline.stop();
83 | }
84 |
85 | public void addRoute(String route, RoutingDefinition target) {
86 | router.addRoute(route, target);
87 | }
88 |
89 | public void addRoute(String route, Endpoint target) {
90 | router.addRoute(route, target);
91 | }
92 |
93 | public void addRoute(String route, Object target) {
94 | router.addRoute(route, target);
95 | }
96 |
97 | public GraphDatabaseService getDatabase() {
98 | return database;
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/BasePropertyContainerService.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import org.neo4j.graphdb.PropertyContainer;
4 | import org.neo4j.smack.pipeline.database.event.Invocation;
5 | import org.neo4j.smack.serialization.strategy.PropertyContainerDeserialization;
6 |
7 | public class BasePropertyContainerService
8 | {
9 |
10 | protected UrlReverseLookerUpper url = new UrlReverseLookerUpper();
11 |
12 | protected long getNodeId(Invocation invocation)
13 | {
14 | return invocation.getLongParameter(UrlReverseLookerUpper.NODE_ID_NAME, -1l);
15 | }
16 |
17 | protected long getRelationshipId(Invocation invocation)
18 | {
19 | return invocation.getLongParameter(UrlReverseLookerUpper.RELATIONSHIP_ID_NAME, -1l);
20 | }
21 |
22 | protected String getPropertyKey(Invocation invocation)
23 | {
24 | return invocation.getStringParameter(UrlReverseLookerUpper.PROPERTY_KEY_NAME, null);
25 | }
26 |
27 | protected void setProperties(PropertyContainer entity, PropertyContainerDeserialization props)
28 | {
29 | while(props.hasMoreProperties())
30 | {
31 | props.nextProperty();
32 | entity.setProperty(props.propertyKey(), props.propertyValue());
33 | }
34 | }
35 |
36 | protected void removeAllProperties(PropertyContainer entity)
37 | {
38 | for(String key: entity.getPropertyKeys())
39 | {
40 | entity.removeProperty(key);
41 | }
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/DataOperationsDiscoveryService.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import javax.ws.rs.GET;
4 | import javax.ws.rs.Path;
5 |
6 | import org.neo4j.smack.pipeline.database.event.Invocation;
7 | import org.neo4j.smack.pipeline.database.event.Output;
8 |
9 | public class DataOperationsDiscoveryService {
10 |
11 | @GET
12 | @Path("")
13 | public void getServiceDescription(Invocation invocation, Output result)
14 | {
15 | result.ok();
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/DataOperationsService.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import org.neo4j.smack.routing.RoutingDefinition;
4 |
5 | public class DataOperationsService extends RoutingDefinition {
6 |
7 | public DataOperationsService(String dataAPIPath) {
8 | addRoute("", new NodeService());
9 | addRoute("", new RelationshipService());
10 | addRoute("", new IndexService(dataAPIPath));
11 | addRoute("", new TraversalService(dataAPIPath));
12 | addRoute("", new DataOperationsDiscoveryService());
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/DatabaseService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.api;
21 |
22 | import org.neo4j.smack.routing.RoutingDefinition;
23 |
24 | public class DatabaseService extends RoutingDefinition {
25 |
26 | public DatabaseService(String dataPath) {
27 | addRoute("/tx", new TransactionService());
28 |
29 | addRoute("", new DataOperationsService(dataPath));
30 | addRoute("/tx/{tx_id}", new DataOperationsService(dataPath));
31 | }
32 | }
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/NodeService.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import javax.ws.rs.DELETE;
4 | import javax.ws.rs.GET;
5 | import javax.ws.rs.POST;
6 | import javax.ws.rs.PUT;
7 | import javax.ws.rs.Path;
8 |
9 | import org.neo4j.graphdb.Node;
10 | import org.neo4j.smack.pipeline.database.event.Invocation;
11 | import org.neo4j.smack.pipeline.database.event.Output;
12 | import org.neo4j.smack.routing.annotation.DeserializeWith;
13 | import org.neo4j.smack.routing.annotation.SerializeWith;
14 | import org.neo4j.smack.routing.annotation.Transactional;
15 | import org.neo4j.smack.serialization.strategy.NodeSerializationStrategy;
16 | import org.neo4j.smack.serialization.strategy.PropertyContainerDeserialization;
17 | import org.neo4j.smack.serialization.strategy.PropertyContainerDeserializationStrategy;
18 | import org.neo4j.smack.serialization.strategy.PropertyContainerSerializationStrategy;
19 | import org.neo4j.smack.serialization.strategy.PropertyValueDeserializationStrategy;
20 | import org.neo4j.smack.serialization.strategy.PropertyValueSerializationStrategy;
21 |
22 | public class NodeService extends BasePropertyContainerService
23 | {
24 |
25 | @POST
26 | @Transactional
27 | @Path(UrlReverseLookerUpper.PATH_NODES)
28 | @DeserializeWith(PropertyContainerDeserializationStrategy.class)
29 | @SerializeWith(NodeSerializationStrategy.class)
30 | public void createNode(Invocation invocation, Output result)
31 | {
32 | Node node = invocation.getDB().createNode();
33 |
34 | setProperties(node, invocation.getContent());
35 |
36 | result.createdAt(url.reverse(node), node);
37 | }
38 |
39 | @GET
40 | @Path(UrlReverseLookerUpper.PATH_NODE)
41 | @SerializeWith(NodeSerializationStrategy.class)
42 | public void getNode(Invocation invocation, Output result)
43 | {
44 | result.ok( invocation.getDB().getNodeById(getNodeId(invocation)) );
45 | }
46 |
47 | @DELETE
48 | @Transactional
49 | @Path(UrlReverseLookerUpper.PATH_NODE)
50 | public void deleteNode(Invocation invocation, Output result)
51 | {
52 | invocation.getDB().getNodeById(getNodeId(invocation)).delete();
53 | result.ok();
54 | }
55 |
56 | @PUT
57 | @Transactional
58 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTIES)
59 | @DeserializeWith(PropertyContainerDeserializationStrategy.class)
60 | public void setAllNodeProperties(Invocation invocation, Output result)
61 | {
62 | Node node = invocation.getDB().getNodeById(getNodeId(invocation));
63 |
64 | removeAllProperties(node);
65 | setProperties(node, invocation.getContent());
66 |
67 | result.okNoContent();
68 | }
69 |
70 | @GET
71 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTIES)
72 | @SerializeWith(PropertyContainerSerializationStrategy.class)
73 | public void getAllNodeProperties(Invocation invocation, Output result)
74 | {
75 | result.ok(invocation.getDB().getNodeById(getNodeId(invocation)));
76 | }
77 |
78 | @PUT
79 | @Transactional
80 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTY)
81 | @DeserializeWith(PropertyValueDeserializationStrategy.class)
82 | public void setNodeProperty(Invocation invocation, Output result)
83 | {
84 | Node node = invocation.getDB().getNodeById(getNodeId(invocation));
85 |
86 | node.setProperty(invocation.getStringParameter(UrlReverseLookerUpper.PROPERTY_KEY_NAME), invocation.getContent());
87 |
88 | result.okNoContent();
89 | }
90 |
91 | @GET
92 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTY)
93 | @SerializeWith(PropertyValueSerializationStrategy.class)
94 | public void getNodeProperty(Invocation invocation, Output result)
95 | {
96 | Node node = invocation.getDB().getNodeById(getNodeId(invocation));
97 | result.ok(node.getProperty(invocation.getStringParameter(UrlReverseLookerUpper.PROPERTY_KEY_NAME)));
98 | }
99 |
100 | @DELETE
101 | @Transactional
102 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTY)
103 | public void deleteNodeProperty(Invocation invocation, Output result)
104 | {
105 | Node node = invocation.getDB().getNodeById(getNodeId(invocation));
106 | node.removeProperty(invocation.getStringParameter(UrlReverseLookerUpper.PROPERTY_KEY_NAME));
107 | result.ok();
108 | }
109 |
110 | @DELETE
111 | @Transactional
112 | @Path(UrlReverseLookerUpper.PATH_NODE_PROPERTIES)
113 | public void deleteAllNodeProperties(Invocation invocation, Output result)
114 | {
115 | Node node = invocation.getDB().getNodeById(getNodeId(invocation));
116 | removeAllProperties(node);
117 | result.ok();
118 | }
119 | }
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/RestService.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import java.net.URI;
4 | import java.net.URISyntaxException;
5 | import java.util.Arrays;
6 | import java.util.Collections;
7 | import java.util.LinkedHashSet;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import javax.ws.rs.core.MediaType;
12 |
13 | import org.neo4j.server.rest.paging.LeaseManager;
14 | import org.neo4j.server.rest.paging.RealClock;
15 | import org.neo4j.server.rest.repr.BadInputException;
16 | import org.neo4j.server.rest.repr.ExtensionInjector;
17 | import org.neo4j.server.rest.repr.OutputFormat;
18 | import org.neo4j.server.rest.repr.RepresentationFormatRepository;
19 | import org.neo4j.smack.pipeline.database.event.Invocation;
20 |
21 | /**
22 | * @author mh
23 | * @since 11.12.11
24 | */
25 | public class RestService
26 | {
27 | private static final LeaseManager leaseManager = new LeaseManager(new RealClock());
28 | public static final String NODE_ID_NAME = "nodeId";
29 | protected static final String PATH_NODES = "node";
30 | protected static final String PATH_NODE = PATH_NODES + "/{" + NODE_ID_NAME + "}";
31 | public static final String RELATIONSHIP_ID_NAME = "relationshipId";
32 | protected static final String PATH_NODE_RELATIONSHIPS = PATH_NODE + "/relationships";
33 | protected static final String PATH_RELATIONSHIP = "relationship/{" + RELATIONSHIP_ID_NAME + "}";
34 | RepresentationFormatRepository repository = new RepresentationFormatRepository(new ExtensionInjector() {
35 | @Override
36 | public Map> getExensionsFor(Class> aClass) {
37 | return Collections.emptyMap();
38 | }
39 | });
40 |
41 | private final String dataPath;
42 |
43 | public RestService(String dataPath) {
44 | this.dataPath = dataPath;
45 | }
46 |
47 | long extractId(Object uri) throws BadInputException {
48 | try {
49 | return Long.parseLong(uri.toString().substring(uri.toString().lastIndexOf("/") + 1));
50 | } catch (NumberFormatException ex) {
51 | throw new BadInputException(ex);
52 | } catch (NullPointerException ex) {
53 | throw new BadInputException(ex);
54 | }
55 | }
56 |
57 | protected OutputFormat createOutputFormat(Invocation invocation) throws URISyntaxException {
58 | final URI uri = new URI(dataPath);
59 | return repository.outputFormat(Arrays.asList(MediaType.APPLICATION_JSON_TYPE), uri);
60 | }
61 |
62 | protected Long getNodeId(Invocation invocation) {
63 | return getLongParameter(invocation, NODE_ID_NAME);
64 | }
65 | protected Long getRelationshipId(Invocation invocation) {
66 | return getLongParameter(invocation, RELATIONSHIP_ID_NAME);
67 | }
68 |
69 | protected Long getLongParameter(Invocation invocation, String key) {
70 | return invocation.getLongParameter(key, -1l);
71 | }
72 | protected Long getLongParameter(Invocation invocation, String key, Long defaultValue) {
73 | final Long value = getLongParameter(invocation, key);
74 | return value == null ? defaultValue : value;
75 | }
76 |
77 | protected String getParameter(Invocation invocation, String key) {
78 | return invocation.getPathVariables().getParameter(key);
79 | }
80 |
81 | protected Long getId(Invocation invocation) {
82 | return getLongParameter(invocation, "id");
83 | }
84 |
85 |
86 | protected String getKey(Invocation invocation) {
87 | return getParameter(invocation, "key");
88 | }
89 |
90 | @SuppressWarnings("unchecked")
91 | protected Map readMap(Invocation invocation) {
92 | return invocation.getContent(Map.class);
93 | }
94 |
95 | @SuppressWarnings("serial")
96 | public static class AmpersandSeparatedCollection extends LinkedHashSet {
97 | public AmpersandSeparatedCollection(String path) {
98 | for (String e : path.split("&")) {
99 | if (e.trim()
100 | .length() > 0) {
101 | add(e);
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/TransactionService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.api;
21 |
22 | import javax.ws.rs.POST;
23 | import javax.ws.rs.PUT;
24 | import javax.ws.rs.Path;
25 |
26 | import org.neo4j.smack.pipeline.database.TransactionRegistry;
27 | import org.neo4j.smack.pipeline.database.event.Invocation;
28 | import org.neo4j.smack.pipeline.database.event.Output;
29 | import org.neo4j.smack.routing.annotation.DeserializeWith;
30 | import org.neo4j.smack.routing.annotation.Transactional;
31 | import org.neo4j.smack.serialization.strategy.TransactionStateDeserialization;
32 | import org.neo4j.smack.serialization.strategy.TransactionStateDeserializationStrategy;
33 |
34 | public class TransactionService {
35 |
36 | private static final UrlReverseLookerUpper url = new UrlReverseLookerUpper();
37 |
38 | @POST
39 | @Path("")
40 | public void createTransaction(Invocation req, Output res) {
41 | TransactionRegistry txs = req.getTxRegistry();
42 | Long txId = req.getTxId();
43 |
44 | txs.createTransaction(txId);
45 |
46 | res.createdAt(url.reverseTransaction(txId));
47 | }
48 |
49 | @PUT
50 | @Path("/{tx_id}/state")
51 | @Transactional
52 | @DeserializeWith(TransactionStateDeserializationStrategy.class)
53 | public void setTransactionState(Invocation req, Output res) throws Exception {
54 | TransactionRegistry txs = req.getTxRegistry();
55 |
56 | switch(req.getContent()) {
57 | case COMMITTED:
58 | txs.commitCurrentTransaction();
59 | break;
60 | case ROLLED_BACK:
61 | txs.rollbackCurrentTransaction();
62 | break;
63 | default:
64 | throw new IllegalArgumentException("Only COMMITTED and ROLLED_BACK transaction states can be set.");
65 | }
66 |
67 | res.ok();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/api/UrlReverseLookerUpper.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.api;
2 |
3 | import org.neo4j.graphdb.Node;
4 | import org.neo4j.graphdb.Relationship;
5 |
6 | /**
7 | * Central authority for url lookups.
8 | * Dead simple right now, but to be expanded down the road.
9 | *
10 | * TODO: Perhaps move path constants into their own class?
11 | */
12 | public class UrlReverseLookerUpper {
13 |
14 | //
15 | // Path variable keys
16 | //
17 |
18 |
19 | public static final String PROPERTY_KEY_NAME = "key";
20 |
21 | public static final String NODE_ID_NAME = "node_id";
22 |
23 | public static final String RELATIONSHIP_ID_NAME = "relationship_id";
24 | public static final String RELATIONSHIP_DIRECTION_NAME = "direction";
25 | public static final String RELATIONSHIP_TYPES_NAME = "types";
26 |
27 | public static final String PATH_NODES = "node";
28 | public static final String PATH_NODE = PATH_NODES + "/{" + NODE_ID_NAME + "}";
29 | public static final String PATH_NODE_PROPERTIES = PATH_NODE + "/properties";
30 | public static final String PATH_NODE_PROPERTY = PATH_NODE_PROPERTIES + "/{" + PROPERTY_KEY_NAME + "}";
31 |
32 | //
33 | // Paths
34 | //
35 |
36 | public static final String PATH_NODE_RELATIONSHIPS = PATH_NODE + "/relationships";
37 | public static final String PATH_RELATIONSHIP = "relationship/{" + RELATIONSHIP_ID_NAME + "}";
38 |
39 | public static final String PATH_NODE_RELATIONSHIPS_W_DIR = PATH_NODE_RELATIONSHIPS + "/{"+RELATIONSHIP_DIRECTION_NAME+"}";
40 | public static final String PATH_NODE_RELATIONSHIPS_W_DIR_N_TYPES = PATH_NODE_RELATIONSHIPS_W_DIR + "/{"+RELATIONSHIP_TYPES_NAME+"}";
41 | public static final String PATH_RELATIONSHIP_PROPERTIES = PATH_RELATIONSHIP + "/properties";
42 | public static final String PATH_RELATIONSHIP_PROPERTY = PATH_RELATIONSHIP_PROPERTIES + "/{"+PROPERTY_KEY_NAME+"}";
43 |
44 | public String reverse(Node node)
45 | {
46 | return "/db/data/node/" + node.getId();
47 | }
48 |
49 | public String reverse(Relationship rel)
50 | {
51 | return "/db/data/relationship/" + rel.getId();
52 | }
53 |
54 | public String reverseTransaction(Long txId)
55 | {
56 | return "/db/data/tx/" + txId;
57 | }
58 |
59 | // TODO: This is used by deserializers,
60 | // see if we can write a special deserializer
61 | // that extracts this id without creating garbage.
62 | public static long nodeId(String string)
63 | {
64 | String [] parts = string.split("\\/");
65 | return Long.valueOf(parts[parts.length-1]);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/gcfree/MutableString.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.gcfree;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * A mutable String implementation. Uses more memory than
7 | * native java strings and is slower, but can be recycled.
8 | *
9 | * In high-throughput applications, this can be very useful
10 | * as the performance impact of GC is high, and we can pool
11 | * mutable string objects, so we don't need GC.
12 | */
13 | public class MutableString {
14 |
15 | private char [] chars;
16 | private int length = 0;
17 |
18 | public MutableString(String string)
19 | {
20 | chars = string.toCharArray();
21 | length = chars.length;
22 | }
23 |
24 | public MutableString(int initialCapacity)
25 | {
26 | chars = new char[initialCapacity];
27 | length = 0;
28 | }
29 |
30 | public void append(char character)
31 | {
32 | try {
33 | chars[length++] = character;
34 | } catch(ArrayIndexOutOfBoundsException e) {
35 | ensureCapacity(length);
36 | chars[length] = character;
37 | }
38 | }
39 |
40 | public void setTo(MutableString value)
41 | {
42 | ensureCapacity(value.length);
43 | length = value.length;
44 | char [] other = value.chars;
45 | for(int i=0;i=l;i--) {
23 | digit = Character.digit(chars[i], 10);
24 |
25 | if(digit != -1) {
26 | longValue = longValue + (digit * multiplier);
27 | multiplier *= 10;
28 | } else {
29 | throw new NumberFormatException("I don't know how to convert " + value + " to a long.");
30 | }
31 | }
32 | return longValue;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/CombinedHandler.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline;
2 |
3 | import com.lmax.disruptor.WorkHandler;
4 |
5 | public class CombinedHandler implements WorkHandler {
6 |
7 | private WorkHandler[] handlers;
8 |
9 | public CombinedHandler(WorkHandler ... handlers) {
10 | this.handlers = handlers;
11 | }
12 |
13 | @Override
14 | public void onEvent(E event) throws Exception
15 | {
16 | for(WorkHandler handler : handlers)
17 | {
18 | handler.onEvent(event);
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/DaemonThreadFactory.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline;
2 |
3 | import java.util.concurrent.ThreadFactory;
4 |
5 | /**
6 | * @author mh
7 | * @since 14.11.11
8 | */
9 | public class DaemonThreadFactory implements ThreadFactory {
10 |
11 | private String baseName;
12 | private int threadNo = 0;
13 |
14 | public DaemonThreadFactory(String threadBaseName) {
15 | this.baseName = threadBaseName;
16 | }
17 |
18 | @Override
19 | public Thread newThread(Runnable runnable) {
20 | final Thread thread = new Thread(runnable);
21 | thread.setName(baseName + "-" + threadNo++);
22 | thread.setDaemon(true);
23 | return thread;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/DefaultExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline;
2 |
3 | import org.neo4j.smack.pipeline.event.Fallible;
4 |
5 | import com.lmax.disruptor.ExceptionHandler;
6 |
7 | public class DefaultExceptionHandler implements ExceptionHandler {
8 |
9 | @Override
10 | public void handleEventException(Throwable ex, long sequence, Object event)
11 | {
12 | ex.printStackTrace();
13 | if(event instanceof Fallible) {
14 | ((Fallible)event).setFailed(ex);
15 | }
16 | }
17 |
18 | @Override
19 | public void handleOnStartException(Throwable ex)
20 | {
21 | ex.printStackTrace();
22 | }
23 |
24 | @Override
25 | public void handleOnShutdownException(Throwable ex)
26 | {
27 | ex.printStackTrace();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/RingBufferWorkPipeline.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline;
2 |
3 | /**
4 | * @author mh
5 | * @since 27.11.11
6 | */
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.concurrent.ExecutorService;
11 | import java.util.concurrent.Executors;
12 | import java.util.concurrent.atomic.AtomicLong;
13 |
14 | import com.lmax.disruptor.BusySpinWaitStrategy;
15 | import com.lmax.disruptor.EventFactory;
16 | import com.lmax.disruptor.ExceptionHandler;
17 | import com.lmax.disruptor.MultiThreadedClaimStrategy;
18 | import com.lmax.disruptor.RingBuffer;
19 | import com.lmax.disruptor.SequenceBarrier;
20 | import com.lmax.disruptor.Sequencer;
21 | import com.lmax.disruptor.WorkHandler;
22 | import com.lmax.disruptor.WorkProcessor;
23 |
24 |
25 | public class RingBufferWorkPipeline {
26 |
27 | protected RingBuffer ringBuffer;
28 |
29 | private final ExceptionHandler exceptionHandler;
30 |
31 | private List> processors = new ArrayList>();
32 |
33 | private ExecutorService workers;
34 |
35 | private final List> handlers = new ArrayList>();
36 |
37 | private final EventFactory eventFactory;
38 |
39 | private String nameForThreads;
40 |
41 | private int bufferSize;
42 |
43 | public RingBufferWorkPipeline(String nameForThreads, final EventFactory eventFactory, final ExceptionHandler exceptionHandler, int bufferSize) {
44 | this.nameForThreads = nameForThreads;
45 | this.eventFactory = eventFactory;
46 | this.exceptionHandler = exceptionHandler;
47 | this.bufferSize = bufferSize;
48 | }
49 |
50 | public void start() {
51 | if (handlers.isEmpty()) throw new IllegalStateException("No Handlers configured on Pipeline");
52 | final int numEventProcessors = handlers.size();
53 | workers = Executors.newFixedThreadPool(numEventProcessors, new DaemonThreadFactory(nameForThreads));
54 |
55 | ringBuffer = new RingBuffer(
56 | eventFactory,
57 | new MultiThreadedClaimStrategy(bufferSize),
58 | new BusySpinWaitStrategy());
59 |
60 | WorkProcessor processor = null;
61 | for (WorkHandler handler : handlers)
62 | {
63 | processor = scheduleEventProcessor(processor, handler);
64 | processors.add(processor);
65 | }
66 | ringBuffer.setGatingSequences(processor.getSequence());
67 |
68 | }
69 |
70 | private WorkProcessor scheduleEventProcessor(WorkProcessor predecessor, WorkHandler handler)
71 | {
72 | WorkProcessor newProcessor = new WorkProcessor(ringBuffer, barrierFor(predecessor), handler, exceptionHandler, newSequence());
73 | workers.submit(newProcessor);
74 | return newProcessor;
75 | }
76 |
77 | private SequenceBarrier barrierFor(WorkProcessor predecessor) {
78 | if (predecessor == null) return ringBuffer.newBarrier();
79 | return ringBuffer.newBarrier(predecessor.getSequence());
80 | }
81 |
82 | private AtomicLong newSequence() {
83 | return new AtomicLong(Sequencer.INITIAL_CURSOR_VALUE);
84 | }
85 |
86 | public void stop() {
87 | for (WorkProcessor processor : processors) {
88 | processor.halt();
89 | }
90 | workers.shutdown();
91 | }
92 |
93 | public RingBuffer getRingBuffer() {
94 | return ringBuffer;
95 | }
96 |
97 | public void addHandler(WorkHandler handler)
98 | {
99 | handlers.add(handler);
100 | }
101 |
102 | }
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/CoreWorkPipeline.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.core;
2 |
3 | import org.jboss.netty.buffer.ChannelBuffer;
4 | import org.jboss.netty.channel.Channel;
5 | import org.neo4j.smack.pipeline.CombinedHandler;
6 | import org.neo4j.smack.pipeline.RingBufferWorkPipeline;
7 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
8 | import org.neo4j.smack.routing.InvocationVerb;
9 |
10 | import com.lmax.disruptor.ExceptionHandler;
11 |
12 | public class CoreWorkPipeline extends RingBufferWorkPipeline implements WorkPublisher {
13 |
14 | @SuppressWarnings("unchecked")
15 | public CoreWorkPipeline(ExceptionHandler exceptionHandler,
16 | RoutingHandler routingHandler, DeserializationHandler deserializationHandler,
17 | TransactionPreparationHandler tranasctionPreparationHandler, WorkDivisionHandler workDivisionHandler)
18 | {
19 | super("CoreWorkEventHandler", CorePipelineEvent.FACTORY, exceptionHandler, 1024 * 4);
20 | addHandler(new CombinedHandler(
21 | routingHandler,
22 | deserializationHandler));
23 | addHandler(new CombinedHandler(
24 | tranasctionPreparationHandler,
25 | workDivisionHandler));
26 | }
27 |
28 | @Override
29 | public void addWork(Long connectionId, InvocationVerb verb, String path,
30 | ChannelBuffer content, Channel channel, boolean keepAlive)
31 | {
32 | long sequenceNo = ringBuffer.next();
33 | CorePipelineEvent event = ringBuffer.get(sequenceNo);
34 |
35 | event.reset(connectionId, verb, path, content, channel, keepAlive);
36 |
37 | ringBuffer.publish(sequenceNo);
38 | }
39 |
40 | @Override
41 | public void addFailure(Long connectionId, Channel channel, Throwable cause)
42 | {
43 | long sequenceNo = ringBuffer.next();
44 | CorePipelineEvent event = ringBuffer.get(sequenceNo);
45 |
46 | event.reset(connectionId, channel, cause);
47 |
48 | ringBuffer.publish(sequenceNo);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/DeserializationHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.core;
21 |
22 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
23 | import org.neo4j.smack.serialization.Deserializer;
24 | import org.neo4j.smack.serialization.SerializationFactory;
25 |
26 | import com.lmax.disruptor.WorkHandler;
27 |
28 |
29 | public class DeserializationHandler implements WorkHandler {
30 |
31 | SerializationFactory serializationFactory = new SerializationFactory();
32 |
33 | public void onEvent(final CorePipelineEvent event)
34 | throws Exception {
35 | if(!event.hasFailed()) {
36 | Deserializer d = serializationFactory.getDeserializer(event.getInputBuffer());
37 | event.setDeserializedContent(event.getEndpoint().getDeserializationStrategy().deserialize(d));
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/RoutingHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.core;
21 |
22 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
23 | import org.neo4j.smack.routing.Router;
24 |
25 | import com.lmax.disruptor.WorkHandler;
26 |
27 | public class RoutingHandler implements WorkHandler {
28 |
29 | private Router router;
30 |
31 | public RoutingHandler(Router router) {
32 | this.router = router;
33 | }
34 |
35 | public void onEvent(final CorePipelineEvent event) throws Exception
36 | {
37 | if(!event.hasFailed())
38 | {
39 | event.setEndpoint(router.route(event));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/TransactionPreparationHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.core;
21 |
22 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
23 |
24 | import com.lmax.disruptor.WorkHandler;
25 |
26 |
27 | public class TransactionPreparationHandler implements WorkHandler
28 | {
29 | private WorkTransactionPreparer txPrepare = new WorkTransactionPreparer();
30 |
31 | @Override
32 | public void onEvent(CorePipelineEvent event)
33 | {
34 | if(!event.hasFailed())
35 | {
36 | txPrepare.prepare(event);
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/WorkDivisionHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.core;
21 |
22 | import org.apache.log4j.Logger;
23 | import org.neo4j.graphdb.GraphDatabaseService;
24 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
25 | import org.neo4j.smack.pipeline.database.DatabaseWorkPipeline;
26 | import org.neo4j.smack.pipeline.database.ThreadTransactionManagement;
27 | import org.neo4j.smack.pipeline.database.TransactionRegistry;
28 |
29 | import com.lmax.disruptor.ExceptionHandler;
30 | import com.lmax.disruptor.WorkHandler;
31 |
32 | /**
33 | * Takes a prepared RequestEvent, packages it into DatabaseWork, and
34 | * assigns that work to a worker based on the connection ID (same connection
35 | * always goes to the same worker).
36 | */
37 | public class WorkDivisionHandler implements WorkHandler {
38 |
39 | private final static Logger logger = Logger.getLogger(WorkDivisionHandler.class);
40 |
41 | private static final int NUM_DATABASE_WORK_EXECUTORS = 4;
42 |
43 | private final GraphDatabaseService database;
44 | private final DatabaseWorkPipeline[] workers = new DatabaseWorkPipeline[NUM_DATABASE_WORK_EXECUTORS];
45 | private final ExceptionHandler exceptionHandler;
46 |
47 | public WorkDivisionHandler(GraphDatabaseService database, ExceptionHandler exceptionHandler) {
48 | this.database = database;
49 | this.exceptionHandler = exceptionHandler;
50 | start();
51 | }
52 |
53 | @Override
54 | public void onEvent(CorePipelineEvent event)
55 | {
56 | int workerId = (int) (event.getConnectionId() % NUM_DATABASE_WORK_EXECUTORS);
57 | workers[workerId].addWork(event);
58 | }
59 |
60 | public void stop() {
61 | for (DatabaseWorkPipeline worker : workers) {
62 | stopWorker(worker);
63 | }
64 | }
65 |
66 | private void start() {
67 | for (int i = 0; i < NUM_DATABASE_WORK_EXECUTORS; i++) {
68 | TransactionRegistry txs = new TransactionRegistry(database);
69 | ThreadTransactionManagement txManage = new ThreadTransactionManagement(txs);
70 | DatabaseWorkPipeline worker = new DatabaseWorkPipeline(database, txs, txManage, exceptionHandler);
71 | workers[i] = worker;
72 | worker.start();
73 | }
74 | }
75 |
76 | private void stopWorker(DatabaseWorkPipeline worker) {
77 | try {
78 | if (worker == null) {
79 | logger.warn("Worker is null");
80 | return;
81 | }
82 | worker.stop();
83 | } catch (Exception e) {
84 | logger.error("Error stopping worker", e);
85 | }
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/WorkPublisher.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.core;
2 |
3 | import org.jboss.netty.buffer.ChannelBuffer;
4 | import org.jboss.netty.channel.Channel;
5 | import org.neo4j.smack.routing.InvocationVerb;
6 |
7 | public interface WorkPublisher {
8 |
9 | void addWork(Long connectionId, InvocationVerb verb, String path,
10 | ChannelBuffer content, Channel channel, boolean keepAlive);
11 |
12 | void addFailure(Long connectionId, Channel channel, Throwable cause);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/WorkTransactionPreparer.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.core;
2 |
3 | import org.neo4j.smack.pipeline.core.event.TransactionWork;
4 | import org.neo4j.smack.pipeline.event.WorkTransactionMode;
5 |
6 |
7 | public class WorkTransactionPreparer {
8 |
9 | private long txIds = 0l;
10 |
11 | public void prepare(TransactionWork event)
12 | {
13 | WorkTransactionMode txMode = WorkTransactionMode.NO_TRANSACTION;
14 |
15 | if(event.isTransactional())
16 | {
17 | txMode = WorkTransactionMode.OPEN_TRANSACTION;
18 | }
19 |
20 | long txId = event.getTransactionId();
21 |
22 | // Did the request come in with a tx id?
23 | if (txId == -1l)
24 | {
25 | // Nope, generate one
26 | txId = txIds ++;
27 |
28 | // If this seemed like an open transaction, since client
29 | // did not provide a tx id, it is a single transaction.
30 | if(txMode == WorkTransactionMode.OPEN_TRANSACTION) {
31 | txMode = WorkTransactionMode.SINGLE_TRANSACTION;
32 | }
33 |
34 | event.setTransactionId(txId);
35 | }
36 |
37 | event.setTransactionMode(txMode);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/core/event/TransactionWork.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.core.event;
2 |
3 | import org.neo4j.smack.pipeline.event.WorkTransactionMode;
4 |
5 |
6 | public interface TransactionWork {
7 |
8 | boolean isTransactional();
9 |
10 | long getTransactionId();
11 |
12 | void setTransactionId(Long txId);
13 |
14 | WorkTransactionMode getTransactionMode();
15 |
16 | void setTransactionMode(WorkTransactionMode txMode);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/DatabaseWorkPerformer.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.database;
2 |
3 | import org.neo4j.smack.pipeline.database.event.DatabaseWork;
4 |
5 | import com.lmax.disruptor.WorkHandler;
6 |
7 | /**
8 | * Calls work.perform() from within
9 | * an appropriate transactional context.
10 | */
11 | public class DatabaseWorkPerformer implements WorkHandler {
12 |
13 | @Override
14 | public void onEvent(DatabaseWork work) throws Exception
15 | {
16 | try
17 | {
18 | work.perform();
19 | } catch(Exception e) {
20 | // TODO: Logging
21 | e.printStackTrace();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/DatabaseWorkPipeline.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.database;
2 |
3 | import org.neo4j.graphdb.GraphDatabaseService;
4 | import org.neo4j.smack.pipeline.RingBufferWorkPipeline;
5 | import org.neo4j.smack.pipeline.core.event.CorePipelineEvent;
6 | import org.neo4j.smack.pipeline.database.event.DatabaseWork;
7 |
8 | import com.lmax.disruptor.ExceptionHandler;
9 |
10 | public class DatabaseWorkPipeline extends RingBufferWorkPipeline
11 | {
12 |
13 | // Each database work pipeline keeps track of its own transactions
14 | private TransactionRegistry txs;
15 | private GraphDatabaseService database;
16 |
17 | private final ThreadTransactionManagement txManage;
18 |
19 | public DatabaseWorkPipeline(GraphDatabaseService database, TransactionRegistry txs, ThreadTransactionManagement txManage,
20 | ExceptionHandler exceptionHandler)
21 | {
22 | super("DatabaseWorkHandler", DatabaseWork.FACTORY, exceptionHandler, 512);
23 | this.txs = txs;
24 | this.txManage = txManage;
25 | this.database = database;
26 |
27 | addHandler(new DatabaseWorkPerformer());
28 | }
29 |
30 | public void addWork(CorePipelineEvent event)
31 | {
32 |
33 | long sequenceId = ringBuffer.next();
34 | DatabaseWork work = ringBuffer.get(sequenceId);
35 |
36 | if(!event.hasFailed()) {
37 | work.reset(
38 | event.getEndpoint(),
39 | event.getChannel(),
40 | event.getIsPersistentConnection(),
41 | event.getPath(),
42 | event.getTransactionId(),
43 | event.getTransactionMode(),
44 | event.getPathVariables(),
45 | event.getDeserializedContent(),
46 | database,
47 | txs,
48 | txManage);
49 | } else {
50 | work.reset(
51 | event.getChannel(),
52 | event.getIsPersistentConnection(),
53 | event.getTransactionId(),
54 | event.getTransactionMode(),
55 | database,
56 | txs,
57 | txManage,
58 | event.getFailureCause());
59 | }
60 |
61 | ringBuffer.publish(sequenceId);
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/ExceptionOutputWriter.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.database;
2 |
3 | import java.lang.reflect.InvocationTargetException;
4 | import java.util.Collections;
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | import javax.management.relation.RelationNotFoundException;
9 |
10 | import org.jboss.netty.handler.codec.http.HttpResponseStatus;
11 | import org.neo4j.graphdb.NotFoundException;
12 | import org.neo4j.server.rest.domain.EndNodeNotFoundException;
13 | import org.neo4j.server.rest.domain.StartNodeNotFoundException;
14 | import org.neo4j.server.rest.repr.BadInputException;
15 | import org.neo4j.server.rest.web.NoSuchPropertyException;
16 | import org.neo4j.server.rest.web.NodeNotFoundException;
17 | import org.neo4j.server.rest.web.OperationFailureException;
18 | import org.neo4j.server.rest.web.PropertyValueException;
19 | import org.neo4j.server.rest.web.RelationshipNotFoundException;
20 | import org.neo4j.smack.pipeline.database.event.NettyChannelBackedOutput;
21 | import org.neo4j.smack.routing.ResourceNotFoundException;
22 | import org.neo4j.smack.serialization.SerializationStrategy;
23 | import org.neo4j.smack.serialization.strategy.ExceptionSerializationStrategy;
24 |
25 | /**
26 | * @author mh
27 | * @since 05.12.11
28 | */
29 | public class ExceptionOutputWriter {
30 |
31 | private static final SerializationStrategy exceptionSerializationStrategy = new ExceptionSerializationStrategy();
32 |
33 | private static final Map, HttpResponseStatus> exceptionToStatusMap = Collections.unmodifiableMap(new HashMap, HttpResponseStatus>()
34 | {
35 |
36 | private static final long serialVersionUID = -5937199711856466595L;
37 |
38 | {
39 | put(ResourceNotFoundException.class, HttpResponseStatus.NOT_FOUND);
40 | put(NodeNotFoundException.class, HttpResponseStatus.NOT_FOUND);
41 | put(RelationNotFoundException.class, HttpResponseStatus.NOT_FOUND);
42 | put(ArrayStoreException.class, HttpResponseStatus.BAD_REQUEST);
43 | put(BadInputException.class, HttpResponseStatus.BAD_REQUEST);
44 | put(OperationFailureException.class, HttpResponseStatus.INTERNAL_SERVER_ERROR);
45 | put(NoSuchPropertyException.class, HttpResponseStatus.NOT_FOUND);
46 | put(RelationshipNotFoundException.class, HttpResponseStatus.NOT_FOUND);
47 | put(ClassCastException.class, HttpResponseStatus.BAD_REQUEST);
48 | put(StartNodeNotFoundException.class, HttpResponseStatus.NOT_FOUND);
49 | put(EndNodeNotFoundException.class, HttpResponseStatus.NOT_FOUND);
50 | put(PropertyValueException.class, HttpResponseStatus.BAD_REQUEST);
51 | put(UnsupportedOperationException.class, HttpResponseStatus.METHOD_NOT_ALLOWED);
52 | put(NotFoundException.class, HttpResponseStatus.NOT_FOUND);
53 | put(IllegalArgumentException.class, HttpResponseStatus.BAD_REQUEST);
54 |
55 | }
56 | });
57 |
58 | public void write(NettyChannelBackedOutput output, Throwable e)
59 | {
60 | output.send(getErrorStatus(e), e, null, exceptionSerializationStrategy);
61 | }
62 |
63 | private HttpResponseStatus getErrorStatus(Throwable ex) {
64 | if (ex instanceof InvocationTargetException) {
65 | ex = ((InvocationTargetException)ex).getTargetException();
66 | }
67 | for (Map.Entry, HttpResponseStatus> entry : exceptionToStatusMap.entrySet()) {
68 | if (entry.getKey().isInstance(ex)) return entry.getValue();
69 | }
70 | return HttpResponseStatus.INTERNAL_SERVER_ERROR;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/ThreadTransactionManagement.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.database;
2 |
3 | import javax.transaction.HeuristicMixedException;
4 | import javax.transaction.HeuristicRollbackException;
5 | import javax.transaction.InvalidTransactionException;
6 | import javax.transaction.RollbackException;
7 | import javax.transaction.SystemException;
8 |
9 | import org.neo4j.smack.pipeline.event.WorkTransactionMode;
10 |
11 | public class ThreadTransactionManagement {
12 |
13 | private final TransactionRegistry txs;
14 |
15 | public ThreadTransactionManagement(TransactionRegistry txs)
16 | {
17 | this.txs = txs;
18 | }
19 |
20 | public void beforeWork(WorkTransactionMode txMode, long txId) throws SystemException, InvalidTransactionException
21 | {
22 | switch(txMode)
23 | {
24 | case OPEN_TRANSACTION:
25 | txs.selectCurrentTransaction(txId);
26 | break;
27 |
28 | case SINGLE_TRANSACTION:
29 | txs.createTransaction(txId);
30 | txs.selectCurrentTransaction(txId);
31 | break;
32 |
33 | case NO_TRANSACTION:
34 | txs.suspendCurrentTransaction();
35 | break;
36 | }
37 | }
38 |
39 | public void afterWork(WorkTransactionMode txMode, long txId) throws InvalidTransactionException, RollbackException, SystemException, IllegalStateException, SecurityException, HeuristicMixedException, HeuristicRollbackException
40 | {
41 | switch(txMode)
42 | {
43 | case SINGLE_TRANSACTION:
44 | txs.commitCurrentTransaction();
45 | break;
46 |
47 | case OPEN_TRANSACTION:
48 | case NO_TRANSACTION:
49 | break;
50 | }
51 | }
52 |
53 | public void onWorkFailure(WorkTransactionMode txMode, long txId) throws InvalidTransactionException, IllegalStateException, SecurityException, HeuristicMixedException, HeuristicRollbackException, RollbackException, SystemException
54 | {
55 | switch(txMode)
56 | {
57 | case OPEN_TRANSACTION:
58 | case SINGLE_TRANSACTION:
59 | txs.rollbackCurrentTransaction();
60 | break;
61 |
62 | case NO_TRANSACTION:
63 | break;
64 | }
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/event/DefaultInvocationImpl.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.database.event;
21 |
22 | import org.neo4j.graphdb.GraphDatabaseService;
23 | import org.neo4j.smack.pipeline.database.TransactionRegistry;
24 | import org.neo4j.smack.routing.PathVariables;
25 |
26 | /**
27 | * Note: There are lots of these instances, keep it as slim as possible to
28 | * keep memory usage down.
29 | */
30 | public class DefaultInvocationImpl implements Invocation {
31 |
32 | private PathVariables pathVariables;
33 | private Object content;
34 |
35 | private GraphDatabaseService database;
36 | private TransactionRegistry txRegistry;
37 | private long txId = -1l;
38 | private String path;
39 |
40 | @Override
41 | public PathVariables getPathVariables() {
42 | return pathVariables;
43 | }
44 |
45 | @Override
46 | @SuppressWarnings("unchecked")
47 | public T getContent() {
48 | return (T)content;
49 | }
50 |
51 | @Override
52 | public T getContent(Class type) {
53 | if (content==null) return null;
54 | if (type.isInstance(content)) return type.cast(content);
55 | throw new ClassCastException("Expected "+type+" found "+content.getClass());
56 | }
57 |
58 | @Override
59 | public GraphDatabaseService getDB() {
60 | return database;
61 | }
62 |
63 | @Override
64 | public TransactionRegistry getTxRegistry() {
65 | return txRegistry;
66 | }
67 |
68 | @Override
69 | public long getTxId() {
70 | return txId;
71 | }
72 |
73 | @Override
74 | public String getPath() {
75 | return path;
76 | }
77 |
78 | @Override
79 | public long getLongParameter(String name, long defaultValue)
80 | {
81 | return pathVariables.getLongParameter(name, defaultValue);
82 | }
83 |
84 | @Override
85 | public String getStringParameter(String name)
86 | {
87 | return pathVariables.getParameter(name);
88 | }
89 |
90 | @Override
91 | public String getStringParameter(String name, String defaultValue)
92 | {
93 | return pathVariables.getParameter(name, defaultValue);
94 | }
95 |
96 | protected void reset(String path, long txId, PathVariables pathVariables, Object content, GraphDatabaseService database, TransactionRegistry txRegistry)
97 | {
98 | this.path = path;
99 | this.pathVariables = pathVariables;
100 | this.content = content;
101 |
102 | this.database = database;
103 | this.txRegistry = txRegistry;
104 | this.txId = txId;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/event/Invocation.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.database.event;
21 |
22 | import org.neo4j.graphdb.GraphDatabaseService;
23 | import org.neo4j.smack.pipeline.database.TransactionRegistry;
24 | import org.neo4j.smack.routing.PathVariables;
25 |
26 | public interface Invocation {
27 |
28 | public PathVariables getPathVariables();
29 |
30 | public T getContent();
31 |
32 | public T getContent(Class type);
33 |
34 | public GraphDatabaseService getDB();
35 |
36 | public TransactionRegistry getTxRegistry();
37 |
38 | public long getTxId();
39 |
40 | public String getPath();
41 |
42 | // Path variable management
43 |
44 | public long getLongParameter(String nodeIdName, long defaultValue);
45 |
46 | public String getStringParameter(String nodePropertyKeyName);
47 |
48 | public String getStringParameter(String nodePropertyKeyName, String defaultValue);
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/database/event/Output.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.database.event;
2 |
3 |
4 | public interface Output {
5 |
6 | public void created();
7 |
8 | public void created(Object value);
9 |
10 | public void createdAt(String location);
11 |
12 | public void createdAt(String location, Object value);
13 |
14 | public void ok();
15 |
16 | public void ok(Object value);
17 |
18 | public void okNoContent();
19 |
20 | public void okAt(String location, Object value);
21 |
22 | public void notFound();
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/event/Fallible.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.event;
2 |
3 | public interface Fallible {
4 |
5 | public void setFailed(Throwable exception);
6 |
7 | public Throwable getFailureCause();
8 |
9 | public boolean hasFailed();
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/event/WorkTransactionMode.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.event;
2 |
3 | public enum WorkTransactionMode {
4 |
5 | /**
6 | * Perform an invocation in a single transaction,
7 | * opened and closed specifically for this piece of
8 | * work.
9 | */
10 | SINGLE_TRANSACTION,
11 |
12 | /**
13 | * Perform an invocation in an ongoing, already opened
14 | * transaction.
15 | */
16 | OPEN_TRANSACTION,
17 |
18 | /**
19 | * Perform this work outside of the scope of a transaction.
20 | */
21 | NO_TRANSACTION
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/CommonHeaderValues.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.http;
2 |
3 | import org.neo4j.smack.gcfree.MutableString;
4 |
5 | public class CommonHeaderValues {
6 |
7 | /**
8 | * {@code "base64"}
9 | */
10 | public static final MutableString BASE64 = new MutableString("base64");
11 | /**
12 | * {@code "binary"}
13 | */
14 | public static final MutableString BINARY = new MutableString("binary");
15 | /**
16 | * {@code "bytes"}
17 | */
18 | public static final MutableString BYTES = new MutableString("bytes");
19 | /**
20 | * {@code "charset"}
21 | */
22 | public static final MutableString CHARSET = new MutableString("charset");
23 | /**
24 | * {@code "chunked"}
25 | */
26 | public static final MutableString CHUNKED = new MutableString("chunked");
27 | /**
28 | * {@code "close"}
29 | */
30 | public static final MutableString CLOSE = new MutableString("close");
31 | /**
32 | * {@code "compress"}
33 | */
34 | public static final MutableString COMPRESS = new MutableString("compress");
35 | /**
36 | * {@code "100-continue"}
37 | */
38 | public static final MutableString CONTINUE = new MutableString("100-continue");
39 | /**
40 | * {@code "deflate"}
41 | */
42 | public static final MutableString DEFLATE = new MutableString("deflate");
43 | /**
44 | * {@code "gzip"}
45 | */
46 | public static final MutableString GZIP = new MutableString("gzip");
47 | /**
48 | * {@code "identity"}
49 | */
50 | public static final MutableString IDENTITY = new MutableString("identity");
51 | /**
52 | * {@code "keep-alive"}
53 | */
54 | public static final MutableString KEEP_ALIVE = new MutableString("keep-alive");
55 | /**
56 | * {@code "max-age"}
57 | */
58 | public static final MutableString MAX_AGE = new MutableString("max-age");
59 | /**
60 | * {@code "max-stale"}
61 | */
62 | public static final MutableString MAX_STALE = new MutableString("max-stale");
63 | /**
64 | * {@code "min-fresh"}
65 | */
66 | public static final MutableString MIN_FRESH = new MutableString("min-fresh");
67 | /**
68 | * {@code "must-revalidate"}
69 | */
70 | public static final MutableString MUST_REVALIDATE = new MutableString("must-revalidate");
71 | /**
72 | * {@code "no-cache"}
73 | */
74 | public static final MutableString NO_CACHE = new MutableString("no-cache");
75 | /**
76 | * {@code "no-store"}
77 | */
78 | public static final MutableString NO_STORE = new MutableString("no-store");
79 | /**
80 | * {@code "no-transform"}
81 | */
82 | public static final MutableString NO_TRANSFORM = new MutableString("no-transform");
83 | /**
84 | * {@code "none"}
85 | */
86 | public static final MutableString NONE = new MutableString("none");
87 | /**
88 | * {@code "only-if-cached"}
89 | */
90 | public static final MutableString ONLY_IF_CACHED = new MutableString("only-if-cached");
91 | /**
92 | * {@code "private"}
93 | */
94 | public static final MutableString PRIVATE = new MutableString("private");
95 | /**
96 | * {@code "proxy-revalidate"}
97 | */
98 | public static final MutableString PROXY_REVALIDATE = new MutableString("proxy-revalidate");
99 | /**
100 | * {@code "public"}
101 | */
102 | public static final MutableString PUBLIC = new MutableString("public");
103 | /**
104 | * {@code "quoted-printable"}
105 | */
106 | public static final MutableString QUOTED_PRINTABLE = new MutableString("quoted-printable");
107 | /**
108 | * {@code "s-maxage"}
109 | */
110 | public static final MutableString S_MAXAGE = new MutableString("s-maxage");
111 | /**
112 | * {@code "trailers"}
113 | */
114 | public static final MutableString TRAILERS = new MutableString("trailers");
115 | /**
116 | * {@code "Upgrade"}
117 | */
118 | public static final MutableString UPGRADE = new MutableString("Upgrade");
119 | /**
120 | * {@code "WebSocket"}
121 | */
122 | public static final MutableString WEBSOCKET = new MutableString("WebSocket");
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/HttpEncoder.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.http;
2 |
3 | import org.jboss.netty.channel.Channel;
4 | import org.jboss.netty.channel.ChannelHandlerContext;
5 |
6 | // TODO: Write a garbage free encoder :)
7 | public class HttpEncoder {
8 |
9 | public void encode(ChannelHandlerContext ctx, Channel channel, Object msg) {
10 |
11 | // if (msg instanceof HttpMessage) {
12 | // HttpMessage m = (HttpMessage) msg;
13 | // boolean chunked = this.chunked = HttpCodecUtil.isTransferEncodingChunked(m);
14 | // ChannelBuffer header = ChannelBuffers.dynamicBuffer(
15 | // channel.getConfig().getBufferFactory());
16 | // encodeInitialLine(header, m);
17 | // encodeHeaders(header, m);
18 | // header.writeByte(CR);
19 | // header.writeByte(LF);
20 | //
21 | // ChannelBuffer content = m.getContent();
22 | // if (!content.readable()) {
23 | // return header; // no content
24 | // } else if (chunked) {
25 | // throw new IllegalArgumentException(
26 | // "HttpMessage.content must be empty " +
27 | // "if Transfer-Encoding is chunked.");
28 | // } else {
29 | // return wrappedBuffer(header, content);
30 | // }
31 | // }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/HttpHeaderContainer.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.http;
2 |
3 | import java.util.Arrays;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | import org.neo4j.smack.gcfree.MutableString;
8 |
9 | public class HttpHeaderContainer {
10 |
11 | /**
12 | * Garbage free container type for header values.
13 | * Is not iterable (since that would mean we can't be
14 | * garbage free), so instead to loop over, use a pattern like:
15 | *
16 | * MutableString current = values.get(0);
17 | * for( int i=0, l=values.size() ; i 0) {
33 | return values[0];
34 | }
35 | return null;
36 | }
37 |
38 | /**
39 | * Copies the contents of value into a free slot.
40 | * @param value
41 | */
42 | public void add(MutableString value)
43 | {
44 | if(numValues == values.length) {
45 | makeInternalValueStoreBigger();
46 | }
47 | values[numValues++].setTo(value);
48 | }
49 |
50 | public MutableString get(int i)
51 | {
52 | if(i < numValues) {
53 | return values[i];
54 | }
55 | return null;
56 | }
57 |
58 | public int size() {
59 | return numValues;
60 | }
61 |
62 | public void clear()
63 | {
64 | numValues = 0;
65 | }
66 |
67 | protected int currentCapacity() {
68 | return values.length;
69 | }
70 |
71 | private void makeInternalValueStoreBigger()
72 | {
73 | int newStartIndex = values.length;
74 | values = Arrays.copyOf(values, values.length * 2);
75 | initializeValueStore(newStartIndex, values.length);
76 | }
77 |
78 | private void initializeValueStore(int newStartIndex, int length)
79 | {
80 | for(int i=newStartIndex;i headers = new HashMap();
88 |
89 | public MutableString getHeader(HttpHeaderName name)
90 | {
91 | if(headers.containsKey(name)) {
92 | return headers.get(name).first();
93 | } else {
94 | return null;
95 | }
96 | }
97 |
98 | public HttpHeaderValues getHeaders(HttpHeaderName name)
99 | {
100 | return headers.get(name);
101 | }
102 |
103 | public void addHeader(HttpHeaderName headerName, MutableString value)
104 | {
105 | if(!headers.containsKey(headerName)) {
106 | headers.put(headerName, new HttpHeaderValues());
107 | }
108 | headers.get(headerName).add(value);
109 | }
110 |
111 | public void clear()
112 | {
113 | // TODO: This creates an iterator, refactor.
114 | for(HttpHeaderValues v : headers.values()) {
115 | v.clear();
116 | }
117 | }
118 |
119 | public void removeHeader(HttpHeaderName name)
120 | {
121 | headers.get(name).clear();
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/HttpHeaderName.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.http;
2 |
3 | import org.neo4j.smack.gcfree.MutableString;
4 |
5 | public class HttpHeaderName {
6 |
7 | private MutableString name;
8 |
9 | public HttpHeaderName(String string)
10 | {
11 | this.name = new MutableString(string);
12 | }
13 |
14 | public boolean equalsString(MutableString headerName)
15 | {
16 | return headerName.equals(name);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/HttpTokens.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.pipeline.http;
2 |
3 | import java.nio.charset.Charset;
4 |
5 | import org.jboss.netty.util.CharsetUtil;
6 |
7 | public class HttpTokens {
8 |
9 | public static final byte SP = 32;
10 |
11 | //tab ' '
12 | public static final byte HT = 9;
13 |
14 | /**
15 | * Carriage return
16 | */
17 | public static final byte CR = 13;
18 |
19 | /**
20 | * Equals '='
21 | */
22 | public static final byte EQUALS = 61;
23 |
24 | /**
25 | * Line feed character
26 | */
27 | public static final byte LF = 10;
28 |
29 | /**
30 | * carriage return line feed
31 | */
32 | public static final byte[] CRLF = new byte[] { CR, LF };
33 |
34 | /**
35 | * Colon ':'
36 | */
37 | public static final byte COLON = 58;
38 |
39 | /**
40 | * Semicolon ';'
41 | */
42 | public static final byte SEMICOLON = 59;
43 |
44 | /**
45 | * comma ','
46 | */
47 | public static final byte COMMA = 44;
48 |
49 | public static final byte DOUBLE_QUOTE = '"';
50 |
51 | public static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/NettyChannelTrackingHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.http;
21 |
22 | import org.jboss.netty.channel.ChannelHandlerContext;
23 | import org.jboss.netty.channel.ChannelStateEvent;
24 | import org.jboss.netty.channel.SimpleChannelHandler;
25 | import org.jboss.netty.channel.group.ChannelGroup;
26 |
27 | public class NettyChannelTrackingHandler extends SimpleChannelHandler {
28 |
29 | private final ChannelGroup openChannels;
30 |
31 | public NettyChannelTrackingHandler(ChannelGroup openChannels) {
32 | this.openChannels = openChannels;
33 | }
34 |
35 | @Override
36 | public void channelOpen(
37 | ChannelHandlerContext ctx, ChannelStateEvent e) {
38 | openChannels.add(ctx.getChannel());
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/NettyHttpHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.http;
21 |
22 | import java.util.concurrent.atomic.AtomicLong;
23 |
24 | import org.jboss.netty.channel.Channel;
25 | import org.jboss.netty.channel.ChannelHandlerContext;
26 | import org.jboss.netty.channel.ChannelStateEvent;
27 | import org.jboss.netty.channel.ExceptionEvent;
28 | import org.jboss.netty.channel.MessageEvent;
29 | import org.jboss.netty.channel.SimpleChannelHandler;
30 | import org.neo4j.smack.pipeline.core.WorkPublisher;
31 |
32 | public class NettyHttpHandler extends SimpleChannelHandler {
33 |
34 | private HttpDecoder httpDecoder;
35 |
36 | private AtomicLong connectionId;
37 |
38 | private WorkPublisher workBuffer;
39 |
40 | public NettyHttpHandler(WorkPublisher workBuffer, AtomicLong connectionIdGenerator) {
41 | this.workBuffer = workBuffer;
42 | this.httpDecoder = new HttpDecoder(workBuffer);
43 | this.connectionId = connectionIdGenerator;
44 | }
45 |
46 | @Override
47 | public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
48 | throws Exception {
49 | httpDecoder.messageReceived(ctx, e);
50 | }
51 |
52 | @Override
53 | public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
54 | ctx.setAttachment(connectionId.incrementAndGet());
55 | }
56 |
57 | // TODO: I think this catches both upstream and downstream
58 | // exceptions. Only upstream exceptions should get added to
59 | // the work buffer like this, down stream exceptions need
60 | // to be handled differently, otherwise we will append
61 | // an error for a requst that failed back to the beginning of
62 | // the list of jobs.
63 | @Override
64 | public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
65 | throws Exception {
66 | Channel ch = e.getChannel();
67 | Throwable cause = e.getCause();
68 |
69 | Long connectionId = (Long)ctx.getAttachment();
70 | workBuffer.addFailure(connectionId, ch, cause);
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/pipeline/http/NettyHttpPipelineFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.pipeline.http;
21 |
22 | import java.util.concurrent.atomic.AtomicLong;
23 |
24 | import org.jboss.netty.channel.ChannelPipeline;
25 | import org.jboss.netty.channel.ChannelPipelineFactory;
26 | import org.jboss.netty.channel.Channels;
27 | import org.jboss.netty.channel.group.ChannelGroup;
28 | import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
29 | import org.neo4j.smack.pipeline.core.WorkPublisher;
30 |
31 | public class NettyHttpPipelineFactory implements ChannelPipelineFactory {
32 |
33 | private WorkPublisher workConsumer;
34 | private ChannelGroup openChannels;
35 | private AtomicLong connectionIdGenerator;
36 |
37 | public NettyHttpPipelineFactory(WorkPublisher workBuffer, ChannelGroup openChannels) {
38 | this.workConsumer = workBuffer;
39 | this.openChannels = openChannels;
40 | this.connectionIdGenerator = new AtomicLong();
41 | }
42 |
43 | public ChannelPipeline getPipeline() throws Exception {
44 | // Create a default pipeline implementation.
45 | ChannelPipeline pipeline = Channels.pipeline();
46 |
47 | // Uncomment the following line if you want HTTPS
48 | // SSLEngine engine =
49 | // SecureChatSslContextFactory.getServerContext().createSSLEngine();
50 | // engine.setUseClientMode(false);
51 | // pipeline.addLast("ssl", new SslHandler(engine));
52 |
53 | pipeline.addLast("channeltracker",new NettyChannelTrackingHandler(openChannels));
54 |
55 | // TODO: Replace with our own response encoder
56 | pipeline.addLast("encoder", new HttpResponseEncoder());
57 | //pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
58 |
59 | pipeline.addLast("handler", new NettyHttpHandler(workConsumer, connectionIdGenerator));
60 | return pipeline;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/Endpoint.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | import org.neo4j.smack.pipeline.database.event.Invocation;
23 | import org.neo4j.smack.pipeline.database.event.Output;
24 | import org.neo4j.smack.serialization.DeserializationStrategy;
25 | import org.neo4j.smack.serialization.SerializationStrategy;
26 |
27 | public interface Endpoint {
28 |
29 | // TODO java7 use method-handle
30 | public void invoke(Invocation invocation, Output result) throws Exception;
31 | public InvocationVerb getVerb();
32 | public DeserializationStrategy> getDeserializationStrategy();
33 | public SerializationStrategy> getSerializationStrategy();
34 |
35 | public boolean isTransactional();
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/InvocationVerb.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | public enum InvocationVerb {
23 | GET,
24 | PUT,
25 | POST,
26 | DELETE,
27 | HEAD;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/NotFoundEndpoint.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.routing;
2 |
3 | import org.neo4j.smack.pipeline.database.event.Invocation;
4 | import org.neo4j.smack.pipeline.database.event.Output;
5 | import org.neo4j.smack.serialization.DeserializationStrategy;
6 | import org.neo4j.smack.serialization.SerializationStrategy;
7 |
8 | public class NotFoundEndpoint implements Endpoint {
9 |
10 | @Override
11 | public void invoke(Invocation invocation, Output result)
12 | throws Exception
13 | {
14 | result.notFound();
15 | }
16 |
17 | @Override
18 | public InvocationVerb getVerb()
19 | {
20 | return InvocationVerb.GET;
21 | }
22 |
23 | @Override
24 | public DeserializationStrategy> getDeserializationStrategy()
25 | {
26 | return DeserializationStrategy.NO_OP;
27 | }
28 |
29 | @Override
30 | public SerializationStrategy> getSerializationStrategy()
31 | {
32 | return SerializationStrategy.NO_OP;
33 | }
34 |
35 | @Override
36 | public boolean isTransactional()
37 | {
38 | return false;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/PathVariables.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | import java.util.HashMap;
23 | import java.util.List;
24 | import java.util.Map;
25 | import java.util.regex.MatchResult;
26 |
27 | import com.sun.jersey.server.impl.uri.PathPattern;
28 |
29 | public class PathVariables {
30 |
31 | private Map pathVariables = new HashMap();
32 |
33 | public void add(MatchResult matched, PathPattern routePattern) {
34 | List vars = routePattern.getTemplate().getTemplateVariables();
35 | for(int i=0,l=vars.size();i> parameters) {
57 | for (Map.Entry> entry : parameters.entrySet()) {
58 | if (entry.getValue()==null && entry.getValue().isEmpty()) continue;
59 | pathVariables.put(entry.getKey(),entry.getValue().get(0));
60 | }
61 | }
62 |
63 | public void reset() {
64 | pathVariables.clear();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/ResourceNotFoundException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | public class ResourceNotFoundException extends RuntimeException {
23 |
24 | public ResourceNotFoundException(String string) {
25 | super(string);
26 | }
27 |
28 | /**
29 | *
30 | */
31 | private static final long serialVersionUID = -2095648980547335471L;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/Routable.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.routing;
2 |
3 |
4 | public interface Routable {
5 |
6 | String getPath();
7 |
8 | InvocationVerb getVerb();
9 |
10 | PathVariables getPathVariables();
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/RouteDefinitionEntry.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 |
23 | public class RouteDefinitionEntry {
24 |
25 | private final String path;
26 | private final Endpoint endpoint;
27 |
28 | public RouteDefinitionEntry(String path, Endpoint endpoint) {
29 | this.path = path;
30 | this.endpoint = endpoint;
31 | }
32 |
33 | public String getPath() {
34 | return path;
35 | }
36 |
37 | public Endpoint getEndpoint() {
38 | return endpoint;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return String.format("RouteDefinitionEntry{path='%s', endpoint=%s}", path, endpoint);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/RouteEntry.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 |
23 | import com.sun.jersey.server.impl.uri.PathPattern;
24 |
25 | public class RouteEntry {
26 |
27 | protected PathPattern pattern;
28 |
29 | protected Endpoint getEndpoint;
30 | protected Endpoint putEndpoint;
31 | protected Endpoint postEndpoint;
32 | protected Endpoint deleteEndpoint;
33 | protected Endpoint headEndpoint;
34 |
35 | public void setEndpoint(InvocationVerb verb, Endpoint endpoint) {
36 | switch(verb) {
37 | case GET:
38 | getEndpoint = endpoint;
39 | break;
40 | case PUT:
41 | putEndpoint = endpoint;
42 | break;
43 | case POST:
44 | postEndpoint = endpoint;
45 | break;
46 | case DELETE:
47 | deleteEndpoint = endpoint;
48 | break;
49 | case HEAD:
50 | headEndpoint = endpoint;
51 | break;
52 | }
53 | }
54 |
55 | public Endpoint getEndpoint(InvocationVerb verb) {
56 | switch(verb) {
57 | case GET:
58 | return getEndpoint;
59 | case PUT:
60 | return putEndpoint;
61 | case POST:
62 | return postEndpoint;
63 | case DELETE:
64 | return deleteEndpoint;
65 | case HEAD:
66 | return headEndpoint;
67 | }
68 | return null;
69 | }
70 |
71 | public String toString() {
72 | return "Route ["+pattern+"] {GET:"+getEndpoint+", PUT:"+putEndpoint+", POST:"+postEndpoint+", DELETE:"+deleteEndpoint+", HEAD:"+headEndpoint+"}";
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/Router.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | import java.util.LinkedHashMap;
23 | import java.util.Map;
24 | import java.util.regex.MatchResult;
25 |
26 | import org.apache.log4j.Logger;
27 |
28 | import com.sun.jersey.server.impl.uri.PathPattern;
29 | import com.sun.jersey.server.impl.uri.PathTemplate;
30 |
31 | public class Router extends RoutingDefinition {
32 |
33 | private RouteEntry [] routes;
34 | private static final Logger logger = Logger.getLogger(Router.class);
35 |
36 | private static Endpoint notFoundEndpoint = new NotFoundEndpoint();
37 |
38 | private final ResettableQueryStringDecoder queryStringDecoder = new ResettableQueryStringDecoder();
39 |
40 | public Endpoint route(Routable routable)
41 | {
42 |
43 | String path = routable.getPath();
44 |
45 | queryStringDecoder.resetWith(path);
46 | routable.getPathVariables().add(queryStringDecoder.getParameters());
47 |
48 | // TODO: parallelize routing ?? (overhead ?)
49 | // Potentially desert the regex approach and go
50 | // with something that builds a tree structure with the path
51 | // segments of the enpoint paths, traversing it to find endpoint?
52 | for(RouteEntry route : routes)
53 | {
54 | MatchResult matchResult = route.pattern.match(path);
55 | if(matchResult != null)
56 | {
57 | Endpoint endpoint = route.getEndpoint(routable.getVerb());
58 | if(endpoint != null) {
59 | routable.getPathVariables().add(matchResult, route.pattern); // todo is this the best way ?
60 | return endpoint;
61 | }
62 | return notFoundEndpoint;
63 | }
64 | }
65 | return notFoundEndpoint;
66 | }
67 |
68 | public void compileRoutes() {
69 | Map routeMap = new LinkedHashMap();
70 |
71 | for(RouteDefinitionEntry definition : getRouteDefinitionEntries())
72 | {
73 | if(!routeMap.containsKey(definition.getPath()))
74 | {
75 | logger.debug("Adding Route: "+definition.getEndpoint().getVerb() +" to: "+ definition.getPath());
76 | routeMap.put(definition.getPath(), createRoute(definition));
77 | }
78 |
79 | RouteEntry route = routeMap.get(definition.getPath());
80 | route.setEndpoint(definition.getEndpoint().getVerb(), definition.getEndpoint());
81 | // todo what happens if multiple paths have differnt verbs?
82 | }
83 |
84 | // Debug print routing table
85 | // for(RouteEntry route : routeMap.values())
86 | // System.out.println(route);
87 |
88 | routes = routeMap.values().toArray(new RouteEntry[routeMap.size()]);
89 | }
90 |
91 | private RouteEntry createRoute(RouteDefinitionEntry definition) {
92 | RouteEntry route = new RouteEntry();
93 | final PathTemplate template = new PathTemplate(definition.getPath());
94 | route.pattern = new PathPattern(template, definition.getPath().equals("") ? "/" : "");
95 | return route;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/RoutingDefinition.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing;
21 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 |
26 | public class RoutingDefinition {
27 |
28 | protected List entries = new ArrayList();
29 |
30 | public void addRoute(String route, Object target) {
31 | addRoute(route, new AnnotationBasedRoutingDefinition(target));
32 | }
33 |
34 | public void addRoute(String route, RoutingDefinition target) {
35 | for(RouteDefinitionEntry subRoute : target.getRouteDefinitionEntries()) {
36 | addRoute(route + subRoute.getPath(), subRoute.getEndpoint());
37 | }
38 | }
39 |
40 | public void addRoute(String route, Endpoint target) {
41 | entries.add(new RouteDefinitionEntry(route, target));
42 | }
43 |
44 | public List getRouteDefinitionEntries() {
45 | return entries;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/SimpleEndpoint.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.routing;
2 |
3 | import org.neo4j.smack.serialization.DeserializationStrategy;
4 | import org.neo4j.smack.serialization.SerializationStrategy;
5 |
6 | public abstract class SimpleEndpoint implements Endpoint {
7 |
8 | @Override
9 | public InvocationVerb getVerb()
10 | {
11 | return InvocationVerb.GET;
12 | }
13 |
14 | @Override
15 | public DeserializationStrategy> getDeserializationStrategy()
16 | {
17 | return DeserializationStrategy.NO_OP;
18 | }
19 |
20 | @Override
21 | public SerializationStrategy> getSerializationStrategy()
22 | {
23 | return SerializationStrategy.NO_OP;
24 | }
25 |
26 | @Override
27 | public boolean isTransactional()
28 | {
29 | return false;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/annotation/DeserializeWith.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing.annotation;
21 |
22 | import java.lang.annotation.ElementType;
23 | import java.lang.annotation.Retention;
24 | import java.lang.annotation.RetentionPolicy;
25 | import java.lang.annotation.Target;
26 |
27 | import org.neo4j.smack.serialization.DeserializationStrategy;
28 |
29 |
30 | @Target({ElementType.METHOD})
31 | @Retention(RetentionPolicy.RUNTIME)
32 | public @interface DeserializeWith {
33 |
34 | Class extends DeserializationStrategy>> value();
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/annotation/SerializeWith.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.routing.annotation;
21 |
22 | import java.lang.annotation.ElementType;
23 | import java.lang.annotation.Retention;
24 | import java.lang.annotation.RetentionPolicy;
25 | import java.lang.annotation.Target;
26 |
27 | import org.neo4j.smack.serialization.SerializationStrategy;
28 |
29 | @Target({ElementType.METHOD})
30 | @Retention(RetentionPolicy.RUNTIME)
31 | public @interface SerializeWith {
32 |
33 | Class extends SerializationStrategy>> value();
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/routing/annotation/Transactional.java:
--------------------------------------------------------------------------------
1 | package org.neo4j.smack.routing.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target({ElementType.TYPE, ElementType.METHOD})
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Transactional {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/serialization/DeserializationException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.serialization;
21 |
22 |
23 | public class DeserializationException extends RuntimeException {
24 |
25 | /**
26 | *
27 | */
28 | private static final long serialVersionUID = -1139734926756347307L;
29 |
30 | public DeserializationException(String string) {
31 | this(string,null);
32 | }
33 |
34 | public DeserializationException(String string, Throwable e) {
35 | super(string, e);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/org/neo4j/smack/serialization/DeserializationStrategy.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2002-2011 "Neo Technology,"
3 | * Network Engine for Objects in Lund AB [http://neotechnology.com]
4 | *
5 | * This file is part of Neo4j.
6 | *
7 | * Neo4j is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 | package org.neo4j.smack.serialization;
21 |
22 |
23 | public interface DeserializationStrategy {
24 |
25 | public static final DeserializationStrategy