├── docker
├── .dockerignore
├── README.md
├── Dockerfile
└── start.sh
├── atomhopper
└── src
│ ├── main
│ ├── resources
│ │ └── META-INF
│ │ │ ├── placeholder-for-h2-db
│ │ │ └── atom-server.cfg.xml
│ └── webapp
│ │ └── META-INF
│ │ ├── PlaceholderForAtomHopperH2Files
│ │ ├── PlaceholderForAtomHopperLogFiles
│ │ ├── context.xml
│ │ └── template-logback.xml
│ └── deb
│ └── control
│ └── control
├── documentation
├── src
│ └── resources
│ │ ├── figures
│ │ ├── .gitignore
│ │ ├── ah.odg
│ │ ├── ah-intro.png
│ │ └── .~lock.ah.odg#
│ │ ├── samples
│ │ ├── .gitignore
│ │ ├── ah-feedhead.xml
│ │ ├── ah-atom-entry-simple.xml
│ │ ├── ah-namespace-feed-products.xml
│ │ ├── ah-log4j-properties.txt
│ │ ├── ah-namespace-feed-news.xml
│ │ ├── ah-multifeed-atom-server.cfg.xml
│ │ ├── ah-web.xml
│ │ ├── ah-application-context-db-h2.xml
│ │ └── ah-application-context-db-mysql.xml
│ │ └── img
│ │ ├── atomhopper-logo.png
│ │ └── atomhopper-sponsored-by-rackspace.png
├── .gitignore
├── .~lock.README.md#
├── README.md
└── devops.json
├── test-util
├── src
│ ├── test
│ │ └── java
│ │ │ └── org
│ │ │ └── atomhopper
│ │ │ └── util
│ │ │ └── .gitignore
│ └── main
│ │ └── java
│ │ └── org
│ │ └── atomhopper
│ │ └── util
│ │ └── TestHelper.java
└── pom.xml
├── adapters
├── jdbc
│ └── src
│ │ ├── main
│ │ ├── resources
│ │ │ └── ddl
│ │ │ │ └── jdbc
│ │ │ │ ├── add-unique-constraint.sql
│ │ │ │ ├── serial-modification.sql
│ │ │ │ ├── atomhopper-entries-default-timestamp.sql
│ │ │ │ ├── add-eventtype-tenantid.sql
│ │ │ │ ├── atomhopper-database-schema-ddl-postgres.sql
│ │ │ │ └── atomhopper-fresh-schema-ddl-postgres.sql
│ │ └── java
│ │ │ └── org
│ │ │ └── atomhopper
│ │ │ └── jdbc
│ │ │ ├── query
│ │ │ └── SearchType.java
│ │ │ ├── adapter
│ │ │ └── JdbcFeedInformation.java
│ │ │ └── model
│ │ │ └── PersistedEntry.java
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── atomhopper
│ │ └── jdbc
│ │ └── adapter
│ │ └── JdbcFeedInformationTest.java
├── migration
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ └── org
│ │ │ └── atomhopper
│ │ │ └── migration
│ │ │ ├── domain
│ │ │ ├── MigrationReadFrom.java
│ │ │ └── MigrationWriteTo.java
│ │ │ └── adapter
│ │ │ └── MigrationFeedInformation.java
│ └── pom.xml
├── hibernate
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── atomhopper
│ │ │ │ ├── hibernate
│ │ │ │ ├── actions
│ │ │ │ │ ├── SimpleSessionAction.java
│ │ │ │ │ ├── ComplexSessionAction.java
│ │ │ │ │ └── PersistAction.java
│ │ │ │ ├── query
│ │ │ │ │ └── CategoryCriteriaGenerator.java
│ │ │ │ ├── adapter
│ │ │ │ │ └── HibernateFeedInformation.java
│ │ │ │ └── HibernateSessionManager.java
│ │ │ │ └── dbal
│ │ │ │ ├── AtomDatabaseException.java
│ │ │ │ └── FeedRepository.java
│ │ └── resources
│ │ │ ├── dbscript
│ │ │ └── DBMaintenanceSQL.txt
│ │ │ └── ddl
│ │ │ └── postgres
│ │ │ └── atomhopper-database-schema-ddl-postgres.sql
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── atomhopper
│ │ └── hibernate
│ │ ├── actions
│ │ └── PersistActionTest.java
│ │ ├── HibernateFeedRepositoryTestMain.java
│ │ └── adapter
│ │ └── HibernateFeedPublisherTest.java
├── mongodb
│ ├── src
│ │ ├── main
│ │ │ └── java
│ │ │ │ └── org
│ │ │ │ └── atomhopper
│ │ │ │ └── mongodb
│ │ │ │ ├── query
│ │ │ │ └── CategoryCriteriaGenerator.java
│ │ │ │ ├── domain
│ │ │ │ └── PersistedCategory.java
│ │ │ │ └── adapter
│ │ │ │ ├── MongodbFeedInformation.java
│ │ │ │ └── MongodbUtilities.java
│ │ └── test
│ │ │ └── java
│ │ │ └── org
│ │ │ └── atomhopper
│ │ │ └── mongodb
│ │ │ └── adapter
│ │ │ ├── MongodbFeedInformationTest.java
│ │ │ └── MongodbUtilitiesTest.java
│ └── pom.xml
└── postgres-adapter
│ ├── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── atomhopper
│ │ │ │ └── postgres
│ │ │ │ ├── query
│ │ │ │ ├── EntryRowMapper.java
│ │ │ │ └── EntryResultSetExtractor.java
│ │ │ │ ├── adapter
│ │ │ │ └── PostgresFeedInformation.java
│ │ │ │ └── model
│ │ │ │ └── PersistedEntry.java
│ │ └── resources
│ │ │ └── ddl
│ │ │ └── postgres
│ │ │ └── atomhopper-database-schema-ddl-postgres.sql
│ └── test
│ │ └── java
│ │ └── org
│ │ └── atomhopper
│ │ └── postgres
│ │ ├── query
│ │ └── CategoryStringGeneratorTest.java
│ │ └── adapter
│ │ └── PostgresFeedInformationTest.java
│ └── pom.xml
├── hopper
└── src
│ ├── main
│ ├── java
│ │ └── org
│ │ │ └── atomhopper
│ │ │ ├── adapter
│ │ │ ├── TemplateTarget.java
│ │ │ ├── AtomHopperAdapter.java
│ │ │ ├── request
│ │ │ │ ├── adapter
│ │ │ │ │ ├── PutEntryRequest.java
│ │ │ │ │ ├── DeleteEntryRequest.java
│ │ │ │ │ ├── GetEntryRequest.java
│ │ │ │ │ ├── PostEntryRequest.java
│ │ │ │ │ ├── GetCategoriesRequest.java
│ │ │ │ │ ├── impl
│ │ │ │ │ │ ├── RequestParsingException.java
│ │ │ │ │ │ ├── PutEntryRequestImpl.java
│ │ │ │ │ │ ├── DeleteEntryRequestImpl.java
│ │ │ │ │ │ ├── GetEntryRequestImpl.java
│ │ │ │ │ │ ├── GetCategoriesRequestImpl.java
│ │ │ │ │ │ ├── PostEntryRequestImpl.java
│ │ │ │ │ │ └── GetFeedRequestImpl.java
│ │ │ │ │ └── GetFeedRequest.java
│ │ │ │ ├── feed
│ │ │ │ │ ├── FeedRequest.java
│ │ │ │ │ └── AbstractFeedRequest.java
│ │ │ │ ├── entry
│ │ │ │ │ ├── EntryRequest.java
│ │ │ │ │ └── AbstractEntryRequest.java
│ │ │ │ ├── RequestQueryParameter.java
│ │ │ │ ├── ClientRequest.java
│ │ │ │ └── AbstractClientRequest.java
│ │ │ ├── PublicationException.java
│ │ │ ├── impl
│ │ │ │ ├── AbstractDisabledAdapter.java
│ │ │ │ ├── DisabledFeedInformation.java
│ │ │ │ ├── DisabledPublisher.java
│ │ │ │ └── DisabledFeedSource.java
│ │ │ ├── NotImplemented.java
│ │ │ ├── FeedInformation.java
│ │ │ ├── jpa
│ │ │ │ ├── PersistedFeed.java
│ │ │ │ └── PersistedCategory.java
│ │ │ ├── FeedPublisher.java
│ │ │ └── FeedSource.java
│ │ │ ├── util
│ │ │ ├── uri
│ │ │ │ ├── template
│ │ │ │ │ ├── TemplateTargetKey.java
│ │ │ │ │ ├── TemplateParameters.java
│ │ │ │ │ ├── URITemplate.java
│ │ │ │ │ ├── URITemplateParameter.java
│ │ │ │ │ └── EnumKeyedTemplateParameters.java
│ │ │ │ ├── UriToUrlResolver.java
│ │ │ │ ├── URISchemeMapper.java
│ │ │ │ ├── ClasspathSchemeMapper.java
│ │ │ │ └── CustomSchemeResolver.java
│ │ │ ├── config
│ │ │ │ ├── resource
│ │ │ │ │ ├── ConfigurationResource.java
│ │ │ │ │ ├── ConfigurationResourceException.java
│ │ │ │ │ ├── file
│ │ │ │ │ │ └── FileConfigurationResource.java
│ │ │ │ │ └── uri
│ │ │ │ │ │ └── URIConfigurationResource.java
│ │ │ │ ├── ConfigurationParser.java
│ │ │ │ ├── ConfigurationParserException.java
│ │ │ │ └── AbstractConfigurationParser.java
│ │ │ ├── context
│ │ │ │ ├── AdapterNotFoundException.java
│ │ │ │ ├── AdapterConstructionException.java
│ │ │ │ └── AdapterGetter.java
│ │ │ └── reflection
│ │ │ │ └── ReflectionException.java
│ │ │ ├── abdera
│ │ │ ├── response
│ │ │ │ ├── InternalServerException.java
│ │ │ │ ├── ResponseHandler.java
│ │ │ │ ├── EmptyBodyResponseHandler.java
│ │ │ │ ├── EntryResponseHandler.java
│ │ │ │ └── AbstractResponseHandler.java
│ │ │ ├── TargetResolverField.java
│ │ │ ├── filter
│ │ │ │ ├── AdapterResponseInterceptor.java
│ │ │ │ ├── FeedPagingProcessor.java
│ │ │ │ ├── FeedConfigurationResponseProcessor.java
│ │ │ │ ├── FeedEntityTagProcessor.java
│ │ │ │ └── SelectiveURIJSONFilter.java
│ │ │ ├── TargetAwareAbstractCollectionAdapter.java
│ │ │ └── WorkspaceManager.java
│ │ │ ├── config
│ │ │ ├── ConfigurationException.java
│ │ │ └── AtomHopperConfigurationPreprocessor.java
│ │ │ ├── response
│ │ │ ├── ResponseParameter.java
│ │ │ ├── EmptyBody.java
│ │ │ ├── AdapterResponse.java
│ │ │ └── FeedSourceAdapterResponse.java
│ │ │ ├── exceptions
│ │ │ ├── ServletInitException.java
│ │ │ └── ContextAdapterResolutionException.java
│ │ │ ├── servlet
│ │ │ ├── ApplicationContextAdapter.java
│ │ │ ├── ServletInitParameter.java
│ │ │ ├── DefaultEmptyContext.java
│ │ │ └── ServletSpringContext.java
│ │ │ ├── ExternalConfigLoaderContextListener.java
│ │ │ ├── dbal
│ │ │ └── PageDirection.java
│ │ │ ├── LogBackConfigLoader.java
│ │ │ └── AtomHopperVersionServlet.java
│ └── resources
│ │ ├── META-INF
│ │ └── schema
│ │ │ ├── config
│ │ │ └── bindings.xjb
│ │ │ └── examples
│ │ │ └── config
│ │ │ ├── broken-feed-server-config.xml
│ │ │ └── feed-server-config.xml
│ │ └── template-logback.xml
│ └── test
│ ├── resources
│ └── org
│ │ └── atomhopper
│ │ └── config
│ │ └── WorkspaceConfigProcessorTest
│ │ ├── noArchiveWithArchive.xml
│ │ ├── archiveWithNoCurrent.xml
│ │ ├── noArchiveWithCurrent.xml
│ │ ├── archiveWithCurrent.xml
│ │ └── archiveWithArchive.xml
│ └── java
│ └── org
│ └── atomhopper
│ ├── LogBackConfigLoaderTest.java
│ ├── util
│ ├── config
│ │ ├── resource
│ │ │ ├── file
│ │ │ │ └── FileConfigurationResourceTest.java
│ │ │ └── uri
│ │ │ │ └── URIConfigurationResourceTest.java
│ │ └── AbstractConfigurationParserTest.java
│ ├── uri
│ │ └── ClasspathSchemeMapperTest.java
│ ├── TargetRegexBuilderFeedTest.java
│ ├── TargetRegexBuilderTestParent.java
│ ├── TargetRegexBuilderWorkspaceTest.java
│ └── TargetRegexBuilderTest.java
│ ├── ExternalConfigLoaderContextListenerTest.java
│ ├── adapter
│ ├── impl
│ │ ├── DisabledFeedInformationTest.java
│ │ └── DisabledFeedSourceTest.java
│ └── request
│ │ └── impl
│ │ └── PostEntryRequestImplTest.java
│ └── config
│ └── SchemaTest.java
├── Jenkinsfile
├── .gitignore
├── tests
├── jetty-killer
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── org
│ │ │ └── atomhopper
│ │ │ └── jettykiller
│ │ │ ├── CommandLineArguments.java
│ │ │ ├── AtomHopperServerControl.java
│ │ │ └── JettyKiller.java
│ │ └── resources
│ │ └── log4j.properties
├── regression
│ └── src
│ │ └── test
│ │ └── jmeter
│ │ └── user.properties
└── customjdbc-regression
│ └── src
│ └── test
│ └── jmeter
│ ├── postgres-adaptor-override-on-application-context.xml
│ └── postgres-adaptor-override-off-application-context.xml
├── server
└── src
│ └── main
│ ├── resources
│ ├── META-INF
│ │ └── atom-server.cfg.xml
│ └── logback.xml
│ └── java
│ └── org
│ └── atomhopper
│ └── server
│ ├── CommandLineArguments.java
│ ├── MonitorThread.java
│ └── AtomHopperServer.java
└── test-suite
└── src
├── main
├── java
│ └── org
│ │ └── atomhopper
│ │ ├── adapter
│ │ └── impl
│ │ │ └── AtomEntry.java
│ │ └── jetty
│ │ └── AtomHopperJettyServerBuilder.java
└── webapp
│ └── WEB-INF
│ └── web.xml
└── test
└── java
└── org
└── atomhopper
├── JettyIntegrationTestHarness.java
├── GetVersionPathTest.java
└── abdera
└── filter
└── SelectiveURIJSONFilterTest.java
/docker/.dockerignore:
--------------------------------------------------------------------------------
1 | README.md
--------------------------------------------------------------------------------
/atomhopper/src/main/resources/META-INF/placeholder-for-h2-db:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/atomhopper/src/main/webapp/META-INF/PlaceholderForAtomHopperH2Files:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/atomhopper/src/main/webapp/META-INF/PlaceholderForAtomHopperLogFiles:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/documentation/src/resources/figures/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 |
3 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 |
3 |
--------------------------------------------------------------------------------
/test-util/src/test/java/org/atomhopper/util/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 |
--------------------------------------------------------------------------------
/documentation/.gitignore:
--------------------------------------------------------------------------------
1 | !.gitignore
2 | target
3 | */target
4 | */*/target
5 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/add-unique-constraint.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE entries ADD CONSTRAINT entryid_unique UNIQUE(entryid);
--------------------------------------------------------------------------------
/atomhopper/src/main/webapp/META-INF/context.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/documentation/src/resources/figures/ah.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rackerlabs/atom-hopper/HEAD/documentation/src/resources/figures/ah.odg
--------------------------------------------------------------------------------
/documentation/.~lock.README.md#:
--------------------------------------------------------------------------------
1 | Rose Coste,rose.coste,M17UAGY,02.04.2012 15:31,file:///Users/rose.coste/Library/Application%20Support/OpenOffice.org/3;
--------------------------------------------------------------------------------
/documentation/src/resources/figures/ah-intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rackerlabs/atom-hopper/HEAD/documentation/src/resources/figures/ah-intro.png
--------------------------------------------------------------------------------
/documentation/src/resources/img/atomhopper-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rackerlabs/atom-hopper/HEAD/documentation/src/resources/img/atomhopper-logo.png
--------------------------------------------------------------------------------
/documentation/src/resources/figures/.~lock.ah.odg#:
--------------------------------------------------------------------------------
1 | Rose Coste,rose.coste,M17UAGY,22.03.2012 00:31,file:///Users/rose.coste/Library/Application%20Support/OpenOffice.org/3;
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/TemplateTarget.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | public enum TemplateTarget {
4 | WORKSPACE,
5 | FEED,
6 | ENTRY
7 | }
8 |
--------------------------------------------------------------------------------
/documentation/src/resources/img/atomhopper-sponsored-by-rackspace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rackerlabs/atom-hopper/HEAD/documentation/src/resources/img/atomhopper-sponsored-by-rackspace.png
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/template/TemplateTargetKey.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri.template;
2 |
3 | public enum TemplateTargetKey {
4 | WORKSPACE,
5 | FEED
6 | }
7 |
--------------------------------------------------------------------------------
/adapters/migration/src/main/java/org/atomhopper/migration/domain/MigrationReadFrom.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.migration.domain;
2 |
3 | public enum MigrationReadFrom {
4 | NEW,
5 | OLD
6 | }
7 |
--------------------------------------------------------------------------------
/adapters/migration/src/main/java/org/atomhopper/migration/domain/MigrationWriteTo.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.migration.domain;
2 |
3 | public enum MigrationWriteTo {
4 | NEW,
5 | OLD,
6 | BOTH
7 | }
8 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/response/InternalServerException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.response;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public class InternalServerException extends Exception {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/AtomHopperAdapter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | import java.util.Map;
4 |
5 | public interface AtomHopperAdapter {
6 |
7 | void setParameters(Map params);
8 | }
9 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/serial-modification.sql:
--------------------------------------------------------------------------------
1 | BEGIN;
2 |
3 | ALTER TABLE entries ADD id bigserial;
4 | ALTER TABLE entries DROP CONSTRAINT entries_pkey;
5 | ALTER TABLE entries ADD PRIMARY KEY (datelastupdated, id);
6 |
7 | COMMIT;
8 |
--------------------------------------------------------------------------------
/atomhopper/src/deb/control/control:
--------------------------------------------------------------------------------
1 | Package: [[name]]
2 | Version: [[version]]
3 | Section: misc
4 | Priority: optional
5 | Architecture: all
6 | Depends: sun-java6-jre, tomcat6
7 | Maintainer: Atom Hopper Team
8 | Description: Atom Hopper
9 | Distribution: development
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/PutEntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.atomhopper.adapter.request.entry.EntryRequest;
4 |
5 | public interface PutEntryRequest extends EntryRequest {
6 | }
7 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/actions/SimpleSessionAction.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.actions;
2 |
3 | import org.hibernate.Session;
4 |
5 | public interface SimpleSessionAction {
6 |
7 | void perform(Session liveSession);
8 | }
9 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/DeleteEntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.atomhopper.adapter.request.entry.EntryRequest;
4 |
5 | public interface DeleteEntryRequest extends EntryRequest {
6 | }
7 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/actions/ComplexSessionAction.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.actions;
2 |
3 | import org.hibernate.Session;
4 |
5 | public interface ComplexSessionAction {
6 |
7 | T perform(Session liveSession);
8 | }
9 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/atomhopper-entries-default-timestamp.sql:
--------------------------------------------------------------------------------
1 | BEGIN;
2 |
3 | ALTER TABLE entries ALTER COLUMN creationdate SET DEFAULT current_timestamp;
4 | ALTER TABLE entries ALTER COLUMN datelastupdated SET DEFAULT current_timestamp;
5 |
6 | COMMIT;
7 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/feed/FeedRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.feed;
2 |
3 | import org.atomhopper.adapter.request.ClientRequest;
4 |
5 | public interface FeedRequest extends ClientRequest {
6 | String getFeedName();
7 | }
8 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/entry/EntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.entry;
2 |
3 | import org.atomhopper.adapter.request.feed.FeedRequest;
4 |
5 | public interface EntryRequest extends FeedRequest {
6 |
7 | String getEntryId();
8 | }
9 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/query/CategoryCriteriaGenerator.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.query;
2 |
3 | import org.hibernate.Criteria;
4 |
5 | public interface CategoryCriteriaGenerator {
6 |
7 | void enhanceCriteria(Criteria ongoingCriteria);
8 | }
9 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/TargetResolverField.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera;
2 |
3 | public enum TargetResolverField {
4 | ENTRY,
5 | PARAMETERS,
6 | FEED,
7 | USER,
8 | WORKSPACE,
9 | CONTEXT_PATH,
10 | FEED_TYPE,
11 | MARKER
12 | }
13 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/dbal/AtomDatabaseException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.dbal;
2 |
3 | public class AtomDatabaseException extends RuntimeException {
4 |
5 | public AtomDatabaseException(String message, Throwable cause) {
6 | super(message, cause);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/add-eventtype-tenantid.sql:
--------------------------------------------------------------------------------
1 | BEGIN;
2 |
3 | ALTER TABLE entries ADD COLUMN eventtype text;
4 | ALTER TABLE entries ADD COLUMN tenantid text;
5 |
6 | CREATE INDEX eventtype_idx on entries( eventtype );
7 | CREATE INDEX tenantid_idx on entries( tenantid );
8 |
9 | COMMIT;
--------------------------------------------------------------------------------
/adapters/mongodb/src/main/java/org/atomhopper/mongodb/query/CategoryCriteriaGenerator.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.mongodb.query;
2 |
3 | import org.springframework.data.mongodb.core.query.Query;
4 |
5 | public interface CategoryCriteriaGenerator {
6 |
7 | void enhanceCriteria(Query ongoingQuery);
8 | }
9 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/java/org/atomhopper/jdbc/query/SearchType.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jdbc.query;
2 |
3 | public enum SearchType {
4 | FEED_FORWARD,
5 | FEED_BACKWARD,
6 | FEED_HEAD,
7 | LAST_PAGE,
8 | NEXT_LINK,
9 | BY_TIMESTAMP_FORWARD,
10 | BY_TIMESTAMP_BACKWARD
11 | }
12 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/resource/ConfigurationResource.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | public interface ConfigurationResource {
7 |
8 | InputStream getInputStream() throws IOException;
9 | }
10 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/UriToUrlResolver.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri;
2 |
3 | import java.net.MalformedURLException;
4 | import java.net.URI;
5 | import java.net.URL;
6 |
7 | public interface UriToUrlResolver {
8 |
9 | URL toURL(URI uri) throws MalformedURLException;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent any
3 |
4 | triggers {
5 | githubPush()
6 | }
7 | tools {
8 | maven 'MavenTest'
9 | }
10 | stages {
11 | stage ('Test') {
12 | steps {
13 | sh 'mvn initialize test'
14 | }
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/GetEntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.atomhopper.adapter.request.entry.EntryRequest;
5 |
6 | public interface GetEntryRequest extends EntryRequest {
7 | Entry newEntry();
8 | }
9 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/context/AdapterNotFoundException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.context;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public class AdapterNotFoundException extends RuntimeException {
8 |
9 | public AdapterNotFoundException(String string) {
10 | super(string);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/PostEntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 |
6 | public interface PostEntryRequest extends FeedRequest {
7 |
8 | Entry getEntry();
9 | }
10 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/config/ConfigurationException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.config;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public class ConfigurationException extends RuntimeException {
8 |
9 | public ConfigurationException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/response/ResponseParameter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.response;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public enum ResponseParameter {
8 | PREVIOUS_MARKER,
9 | NEXT_MARKER;
10 |
11 | @Override
12 | public String toString() {
13 | return super.toString().toLowerCase();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/reflection/ReflectionException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.reflection;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public class ReflectionException extends RuntimeException {
8 |
9 | public ReflectionException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/GetCategoriesRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.request.ClientRequest;
5 |
6 | public interface GetCategoriesRequest extends ClientRequest {
7 |
8 | Categories newCategories();
9 | }
10 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/context/AdapterConstructionException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.context;
2 |
3 | /**
4 | *
5 | *
6 | */
7 | public class AdapterConstructionException extends RuntimeException {
8 |
9 | public AdapterConstructionException(String string, Throwable thrwbl) {
10 | super(string, thrwbl);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/URISchemeMapper.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri;
2 |
3 | import java.net.MalformedURLException;
4 | import java.net.URI;
5 | import java.net.URL;
6 |
7 | public interface URISchemeMapper {
8 |
9 | boolean canMap(URI uriToMatch);
10 |
11 | URL toURL(URI uriToMap) throws MalformedURLException;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/template/TemplateParameters.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri.template;
2 |
3 | import java.util.Map;
4 |
5 | public interface TemplateParameters {
6 |
7 | void set(URITemplateParameter parameter, Object value);
8 |
9 | Map toMap();
10 |
11 | T getTargetTemplateKey();
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/resource/ConfigurationResourceException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource;
2 |
3 | /**
4 | *
5 |
6 | */
7 | public class ConfigurationResourceException extends RuntimeException {
8 |
9 | public ConfigurationResourceException(String string, Throwable thrwbl) {
10 | super(string, thrwbl);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/PublicationException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | public class PublicationException extends RuntimeException {
4 |
5 | public PublicationException(String message) {
6 | super(message);
7 | }
8 |
9 | public PublicationException(String message, Throwable cause) {
10 | super(message, cause);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/impl/AbstractDisabledAdapter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import org.atomhopper.adapter.AtomHopperAdapter;
4 |
5 | import java.util.Map;
6 |
7 | public abstract class AbstractDisabledAdapter implements AtomHopperAdapter {
8 |
9 | @Override
10 | public void setParameters(Map params) {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-feedhead.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/filter/AdapterResponseInterceptor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.response.AdapterResponse;
5 |
6 | /**
7 | *
8 | *
9 | */
10 | public interface AdapterResponseInterceptor {
11 |
12 | void process(RequestContext rc, AdapterResponse adapterResponse);
13 | }
14 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/resources/dbscript/DBMaintenanceSQL.txt:
--------------------------------------------------------------------------------
1 | # With the ON DELETE CASCADE constriant on the referenced columns this query is no longer needed.
2 | #
3 | #DELETE FROM categoryentryreferences
4 | #WHERE categoryentryreferences.entryid
5 | #IN (SELECT entries.entryid FROM entries WHERE datelastupdated < (now() - '8 day'::interval));
6 |
7 | DELETE FROM entries WHERE datelastupdated < (now() - '8 day'::interval);
8 |
--------------------------------------------------------------------------------
/documentation/README.md:
--------------------------------------------------------------------------------
1 | # This README relates only to documentation for Atom Hopper #
2 |
3 | Within /documentation/, the source XML for books published at http://atomhopper.org/ is in /src/resources/.
4 |
5 | Within /documentation/src/resources/, each file is the source for one book. Elements included within books, such as figures, code samples, and sections used in multiple books, are in subdirectories such as /figures/, /samples/ and /chapters/.
6 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/RequestParsingException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | public class RequestParsingException extends RuntimeException {
4 |
5 | public RequestParsingException(String string, Throwable thrwbl) {
6 | super(string, thrwbl);
7 | }
8 |
9 | public RequestParsingException(String string) {
10 | super(string);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/exceptions/ServletInitException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.exceptions;
2 |
3 | import javax.servlet.ServletException;
4 |
5 | public class ServletInitException extends ServletException {
6 |
7 | public ServletInitException(String message) {
8 | super(message);
9 | }
10 |
11 | public ServletInitException(String message, Throwable cause) {
12 | super(message, cause);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/ConfigurationParser.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config;
2 |
3 | import org.atomhopper.util.config.resource.ConfigurationResource;
4 |
5 | public interface ConfigurationParser {
6 |
7 | T read();
8 |
9 | Class getConfigurationClass();
10 |
11 | void setConfigurationResource(ConfigurationResource resource);
12 |
13 | ConfigurationResource getConfigurationResource();
14 | }
15 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/exceptions/ContextAdapterResolutionException.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.exceptions;
2 |
3 | public class ContextAdapterResolutionException extends RuntimeException {
4 |
5 | public ContextAdapterResolutionException(String message, Throwable cause) {
6 | super(message, cause);
7 | }
8 |
9 | public ContextAdapterResolutionException(String message) {
10 | super(message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/servlet/ApplicationContextAdapter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.servlet;
2 |
3 | import javax.servlet.ServletContext;
4 |
5 |
6 | /**
7 | *
8 | * @author jhopper
9 | */
10 | public interface ApplicationContextAdapter {
11 |
12 | void usingServletContext(ServletContext context);
13 |
14 | T fromContext(Class classToCastTo);
15 |
16 | T fromContext(String refName, Class classToCastTo);
17 | }
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-atom-entry-simple.xml:
--------------------------------------------------------------------------------
1 |
2 | This is a greeting from John Doe
3 | 2011-09-22T21:39:49.904Z
4 |
5 | John Doe
6 |
7 | Hello World
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/adapters/mongodb/src/main/java/org/atomhopper/mongodb/domain/PersistedCategory.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.mongodb.domain;
2 |
3 |
4 | public class PersistedCategory {
5 |
6 | private String term;
7 |
8 | public PersistedCategory(String term) {
9 | this.term = term;
10 | }
11 |
12 | public String getValue() {
13 | return this.term;
14 | }
15 |
16 | public void setValue(String term) {
17 | this.term = term;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/NotImplemented.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
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 | /**
9 | * This annotation may or may not be used now that interfaces are split along
10 | * domain lines
11 | */
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Target(ElementType.METHOD)
14 | public @interface NotImplemented {
15 | }
16 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/actions/PersistAction.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.actions;
2 |
3 | import org.hibernate.Session;
4 |
5 | public class PersistAction implements SimpleSessionAction {
6 |
7 | private final Object persistMe;
8 |
9 | public PersistAction(Object persistMe) {
10 | this.persistMe = persistMe;
11 | }
12 |
13 | @Override
14 | public void perform(Session liveSession) {
15 | liveSession.persist(persistMe);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/hopper/src/main/resources/META-INF/schema/config/bindings.xjb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/main/java/org/atomhopper/postgres/query/EntryRowMapper.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.query;
2 |
3 | import java.sql.ResultSet;
4 | import java.sql.SQLException;
5 |
6 | import org.springframework.jdbc.core.RowMapper;
7 |
8 | public class EntryRowMapper implements RowMapper {
9 | @Override
10 | public Object mapRow(ResultSet rs, int line) throws SQLException {
11 | EntryResultSetExtractor extractor = new EntryResultSetExtractor();
12 | return extractor.extractData(rs);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/TargetAwareAbstractCollectionAdapter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera;
2 |
3 | import org.apache.abdera.protocol.server.impl.AbstractCollectionAdapter;
4 |
5 | public abstract class TargetAwareAbstractCollectionAdapter extends AbstractCollectionAdapter {
6 |
7 | private final String target;
8 |
9 | public TargetAwareAbstractCollectionAdapter(String collectionSpec) {
10 | this.target = collectionSpec;
11 | }
12 |
13 | public String getTarget() {
14 | return target;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/PutEntryRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.adapter.request.adapter.PutEntryRequest;
5 | import org.atomhopper.adapter.request.entry.AbstractEntryRequest;
6 |
7 | public class PutEntryRequestImpl extends AbstractEntryRequest implements PutEntryRequest {
8 |
9 | public PutEntryRequestImpl(RequestContext abderaRequestContext) {
10 | super(abderaRequestContext);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## intellij stuff
2 | .idea/
3 |
4 | ## java specific
5 | !.gitignore
6 | *.iml
7 | *.iws
8 | *.ipr
9 | target
10 | */target
11 | */*/target
12 |
13 | ## generic files to ignore
14 | *~
15 | *.lock
16 | *.DS_Store
17 | *.swp
18 | *.out
19 | /test-suite/nb-configuration.xml
20 | /hopper/nb-configuration.xml
21 | /server/nb-configuration.xml
22 | /server/nbactions.xml
23 | /test-suite/nbactions.xml
24 | /hopper/nbactions.xml
25 | /server/nbactions-pack-server-jar.xml
26 | /ah-war/catalog.xml
27 | /server/catalog.xml
28 | /test-suite/catalog.xml
29 | /ah-war/nbactions.xml
30 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/servlet/ServletInitParameter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.servlet;
2 |
3 | /**
4 | * Enumeration for any initialization parameters that the servlet may expect.
5 | */
6 | public enum ServletInitParameter {
7 |
8 | CONTEXT_ADAPTER_CLASS("context-adapter-class"),
9 | CONFIGURATION_LOCATION("config-location");
10 |
11 | private final String value;
12 |
13 | private ServletInitParameter(String value) {
14 | this.value = value;
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return value;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/DeleteEntryRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.adapter.request.adapter.DeleteEntryRequest;
5 | import org.atomhopper.adapter.request.entry.AbstractEntryRequest;
6 |
7 | /**
8 | *
9 | *
10 | */
11 | public class DeleteEntryRequestImpl extends AbstractEntryRequest implements DeleteEntryRequest {
12 |
13 | public DeleteEntryRequestImpl(RequestContext abderaRequestContext) {
14 | super(abderaRequestContext);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/jetty-killer/src/main/java/org/atomhopper/jettykiller/CommandLineArguments.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jettykiller;
2 |
3 |
4 |
5 | import org.kohsuke.args4j.Option;
6 |
7 | public class CommandLineArguments {
8 |
9 | private static final String DEFAULT_PORT_INFO = "(Default is port 8818, range is 1024 to 49150)";
10 | private static final int STOPPORT = 8818;
11 |
12 | @Option(name = "-s", aliases = {"--shutdown-port", "-p", "--port"},
13 | usage = "The port used to communicate a shutdown to Atom Hopper " + DEFAULT_PORT_INFO)
14 | public final Integer stopport = STOPPORT;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/GetFeedRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter;
2 |
3 | import org.apache.abdera.model.Feed;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | *
10 | *
11 | */
12 | public interface GetFeedRequest extends FeedRequest {
13 |
14 | Feed newFeed();
15 |
16 | List getCategories();
17 |
18 | String getSearchQuery();
19 |
20 | String getPageMarker();
21 |
22 | String getPageSize();
23 |
24 | String getDirection();
25 |
26 | String getStartingAt();
27 | }
28 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/response/ResponseHandler.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.response;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.apache.abdera.protocol.server.ResponseContext;
5 | import org.atomhopper.abdera.filter.AdapterResponseInterceptor;
6 | import org.atomhopper.response.AdapterResponse;
7 |
8 | public interface ResponseHandler {
9 |
10 | void addResponseInterceptor(AdapterResponseInterceptor adapterResponseInterceptor);
11 |
12 | void clearResponseInterceptors();
13 |
14 | ResponseContext handleResponse(RequestContext rc, AdapterResponse adapterResponse);
15 | }
16 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/RequestQueryParameter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request;
2 |
3 | public enum RequestQueryParameter {
4 |
5 | CATEGORIES("categories"),
6 | SEARCH("search"),
7 | PAGE_DIRECTION("direction"),
8 | MARKER("marker"),
9 | PAGE_LIMIT("limit"),
10 | STARTING_AT("startingAt");
11 |
12 | //Class contents
13 | private final String stringValue;
14 |
15 | private RequestQueryParameter(String stringValue) {
16 | this.stringValue = stringValue;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return stringValue;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/ClasspathSchemeMapper.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 |
5 | import java.net.URI;
6 | import java.net.URL;
7 |
8 | public class ClasspathSchemeMapper implements URISchemeMapper {
9 |
10 | @Override
11 | public boolean canMap(URI uriToMatch) {
12 | final String uriScheme = uriToMatch.getScheme();
13 |
14 | return !StringUtils.isBlank(uriScheme) && uriScheme.startsWith("classpath");
15 | }
16 |
17 | @Override
18 | public URL toURL(URI uri) {
19 | return getClass().getResource(uri.getPath());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/template/URITemplate.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri.template;
2 |
3 | public enum URITemplate {
4 |
5 | WORKSPACE("{scheme=}://{host=}{-prefix|:|port}{target_base}/{workspace}"),
6 | FEED(WORKSPACE.toString() + "/{feed}{-prefix|/entries/|entry}/{-opt|?|lochint,limit}{-join|&|lochint,limit}");
7 |
8 | //Class Contents
9 | private final String templateString;
10 |
11 | private URITemplate(String templateString) {
12 | this.templateString = templateString;
13 | }
14 |
15 | @Override
16 | public String toString() {
17 | return templateString;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tests/regression/src/test/jmeter/user.properties:
--------------------------------------------------------------------------------
1 | #---------------------------------------------------------------------------
2 | # AtomHopper Tests Configuration
3 | #---------------------------------------------------------------------------
4 |
5 | host=10.14.209.232
6 | port=8080
7 | protocol=http
8 |
9 | feed=namespace/feed
10 | paging.feed.archive=namespace-p/feed/archive
11 | paging.feed=namespace-p/feed
12 |
13 | buildinfo.version=1.1.8
14 | buildinfo.groupid=org.atomhopper
15 | buildinfo.artifactid=atomhopper
16 |
17 | crossfeed.feed1=namespace1/feedA
18 | crossfeed.feed2=namespace1/feedB
19 | crossfeed.feed3=namespace2/feedA
20 | crossfeed.feed4=namespace2/feedB
21 |
22 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/response/EmptyBody.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.response;
2 |
3 | public final class EmptyBody {
4 |
5 | private static final EmptyBody INSTANCE = new EmptyBody();
6 |
7 | public static EmptyBody getInstance() {
8 | return INSTANCE;
9 | }
10 |
11 | private EmptyBody() {
12 | }
13 |
14 | @Override
15 | public int hashCode() {
16 | return INSTANCE.hashCode();
17 | }
18 |
19 | @Override
20 | public boolean equals(Object obj) {
21 | if (obj != null) {
22 | return obj.hashCode() == hashCode();
23 | } else {
24 | return false;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/GetEntryRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.adapter.request.adapter.GetEntryRequest;
6 | import org.atomhopper.adapter.request.entry.AbstractEntryRequest;
7 |
8 | public class GetEntryRequestImpl extends AbstractEntryRequest implements GetEntryRequest {
9 |
10 | public GetEntryRequestImpl(RequestContext abderaRequestContext) {
11 | super(abderaRequestContext);
12 | }
13 |
14 | @Override
15 | public Entry newEntry() {
16 | return getAbdera().newEntry();
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/ClientRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request;
2 |
3 | import org.apache.abdera.Abdera;
4 | import org.atomhopper.util.uri.template.TemplateParameters;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * A client request contains only the bare minimum needed to express the request
10 | * contents; in this case by wrapping an Abdera RequestContext.
11 | */
12 | public interface ClientRequest {
13 |
14 | String getTargetParameter(String parameter);
15 |
16 | String getRequestParameter(String parameter);
17 |
18 | List getRequestParameters(String parameter);
19 |
20 | String urlFor(TemplateParameters param);
21 |
22 | Abdera getAbdera();
23 | }
24 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/template/URITemplateParameter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri.template;
2 |
3 | public enum URITemplateParameter {
4 |
5 | HOST_SCHEME("scheme"),
6 | HOST_DOMAIN("host"),
7 | HOST_PORT("port"),
8 | WORKSPACE_RESOURCE("workspace"),
9 | FEED_RESOURCE("feed"),
10 | ENTRY_RESOURCE("entry"),
11 | MARKER("lochint"),
12 | PAGE_LIMIT("limit");
13 |
14 | //Class contents
15 | private final String stringRepresentation;
16 |
17 | private URITemplateParameter(String stringRepresentation) {
18 | this.stringRepresentation = stringRepresentation;
19 | }
20 |
21 | @Override
22 | public String toString() {
23 | return stringRepresentation;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/GetCategoriesRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.adapter.request.AbstractClientRequest;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 |
8 | public class GetCategoriesRequestImpl extends AbstractClientRequest implements GetCategoriesRequest {
9 |
10 | public GetCategoriesRequestImpl(RequestContext abderaRequestContext) {
11 | super(abderaRequestContext);
12 | }
13 |
14 | @Override
15 | public Categories newCategories() {
16 | return getAbdera().newCategories();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/feed/AbstractFeedRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.feed;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.abdera.TargetResolverField;
5 | import org.atomhopper.adapter.request.AbstractClientRequest;
6 |
7 | public abstract class AbstractFeedRequest extends AbstractClientRequest implements FeedRequest {
8 |
9 | protected AbstractFeedRequest(RequestContext abderaRequestContext) {
10 | super(abderaRequestContext);
11 | }
12 |
13 | @Override
14 | public String getFeedName() {
15 | return getTargetParameter(TargetResolverField.WORKSPACE.name()) + "/" +
16 | getTargetParameter(TargetResolverField.FEED.name());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/ConfigurationParserException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Rackspace.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | */
10 | package org.atomhopper.util.config;
11 |
12 | /**
13 | *
14 | *
15 | */
16 | public class ConfigurationParserException extends RuntimeException {
17 |
18 | public ConfigurationParserException(String message, Throwable cause) {
19 | super(message, cause);
20 | }
21 |
22 | public ConfigurationParserException(String message) {
23 | super(message);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/resource/file/FileConfigurationResource.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource.file;
2 |
3 | import org.atomhopper.util.config.resource.ConfigurationResource;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | public class FileConfigurationResource implements ConfigurationResource {
11 |
12 | private final File configurationFile;
13 |
14 | public FileConfigurationResource(String resourcePath) {
15 | configurationFile = new File(resourcePath);
16 | }
17 |
18 | @Override
19 | public InputStream getInputStream() throws IOException {
20 | return new FileInputStream(configurationFile);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/hopper/src/main/resources/META-INF/schema/examples/config/broken-feed-server-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-namespace-feed-products.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/entry/AbstractEntryRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.entry;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.abdera.TargetResolverField;
5 | import org.atomhopper.adapter.request.feed.AbstractFeedRequest;
6 |
7 | public class AbstractEntryRequest extends AbstractFeedRequest implements EntryRequest {
8 |
9 | private final String entryId;
10 |
11 | protected AbstractEntryRequest(RequestContext abderaRequestContext) {
12 | super(abderaRequestContext);
13 |
14 | entryId = abderaRequestContext.getTarget().getParameter(TargetResolverField.ENTRY.name());
15 | }
16 |
17 | @Override
18 | public String getEntryId() {
19 | return entryId;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/java/org/atomhopper/jdbc/adapter/JdbcFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jdbc.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.NotImplemented;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 | import org.atomhopper.adapter.request.feed.FeedRequest;
8 |
9 | public class JdbcFeedInformation implements FeedInformation {
10 |
11 | @Override
12 | public String getId(FeedRequest feedRequest) {
13 | throw new UnsupportedOperationException("Not supported yet.");
14 | }
15 |
16 | @Override
17 | @NotImplemented
18 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
19 | throw new UnsupportedOperationException("Not supported yet.");
20 | }
21 | }
--------------------------------------------------------------------------------
/tests/jetty-killer/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Root logger outputs to console for now
2 | log4j.rootLogger=WARN, consoleOut
3 |
4 | #log4j.logger.org.hibernate.SQL=DEBUG, consoleOut
5 | #log4j.additivity.org.hibernate.SQL=false
6 |
7 | # Console
8 | log4j.appender.consoleOut=org.apache.log4j.ConsoleAppender
9 | log4j.appender.consoleOut.layout=org.apache.log4j.PatternLayout
10 | log4j.appender.consoleOut.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
11 |
12 | # File
13 | #log4j.appender.defaultFile=org.apache.log4j.RollingFileAppender
14 | #log4j.appender.defaultFile.File=/tmp/senseLog.log
15 | #log4j.appender.defaultFile.MaxFileSize=2MB
16 | #log4j.appender.defaultFile.MaxBackupIndex=2
17 | #log4j.appender.defaultFile.layout = org.apache.log4j.PatternLayout
18 | #log4j.appender.defaultFile.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
--------------------------------------------------------------------------------
/adapters/mongodb/src/main/java/org/atomhopper/mongodb/adapter/MongodbFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.mongodb.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.NotImplemented;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 | import org.atomhopper.adapter.request.feed.FeedRequest;
8 |
9 | public class MongodbFeedInformation implements FeedInformation {
10 |
11 | @Override
12 | public String getId(FeedRequest feedRequest) {
13 | throw new UnsupportedOperationException("Not supported yet.");
14 | }
15 |
16 | @Override @NotImplemented
17 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
18 | throw new UnsupportedOperationException("Not supported yet.");
19 | }
20 | }
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-log4j-properties.txt:
--------------------------------------------------------------------------------
1 | # Root logger outputs to console for now
2 | log4j.rootLogger=WARN, consoleOut
3 |
4 | #log4j.logger.org.hibernate.SQL=DEBUG, consoleOut
5 | #log4j.additivity.org.hibernate.SQL=false
6 |
7 | # Console
8 | log4j.appender.consoleOut=org.apache.log4j.ConsoleAppender
9 | log4j.appender.consoleOut.layout=org.apache.log4j.PatternLayout
10 | log4j.appender.consoleOut.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
11 |
12 | # File
13 | #log4j.appender.defaultFile=org.apache.log4j.RollingFileAppender
14 | #log4j.appender.defaultFile.File=/tmp/senseLog.log
15 | #log4j.appender.defaultFile.MaxFileSize=2MB
16 | #log4j.appender.defaultFile.MaxBackupIndex=2
17 | #log4j.appender.defaultFile.layout = org.apache.log4j.PatternLayout
18 | #log4j.appender.defaultFile.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/main/java/org/atomhopper/postgres/adapter/PostgresFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.NotImplemented;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 | import org.atomhopper.adapter.request.feed.FeedRequest;
8 |
9 | public class PostgresFeedInformation implements FeedInformation {
10 |
11 | @Override
12 | public String getId(FeedRequest feedRequest) {
13 | throw new UnsupportedOperationException("Not supported yet.");
14 | }
15 |
16 | @Override
17 | @NotImplemented
18 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
19 | throw new UnsupportedOperationException("Not supported yet.");
20 | }
21 | }
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/FeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
5 | import org.atomhopper.adapter.request.feed.FeedRequest;
6 |
7 | public interface FeedInformation {
8 |
9 | /**
10 | * Requests the ID of the underlying feed as a string value.
11 | *
12 | * @return
13 | */
14 | String getId(FeedRequest getFeedRequest);
15 |
16 | /**
17 | * Retrieves a list of categories supported by this feed source.
18 | *
19 | * A workspace provider may poll all of its associated feeds for their
20 | * categories and then aggregate them into a service document.
21 | *
22 | * @return
23 | */
24 | Categories getCategories(GetCategoriesRequest getCategoriesRequest);
25 | }
26 |
--------------------------------------------------------------------------------
/server/src/main/resources/META-INF/atom-server.cfg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test-suite/src/main/java/org/atomhopper/adapter/impl/AtomEntry.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import org.apache.abdera.model.Entry;
4 |
5 | import java.util.Calendar;
6 |
7 | /**
8 | *
9 |
10 | */
11 | public class AtomEntry implements Comparable {
12 |
13 | private final Entry entry;
14 | private final Calendar updated;
15 |
16 | public AtomEntry(Entry entry) {
17 | this.entry = entry;
18 |
19 | updated = Calendar.getInstance();
20 | }
21 |
22 | public Entry getEntry() {
23 | return entry;
24 | }
25 |
26 | public Calendar getUpdated() {
27 | return updated;
28 | }
29 |
30 | public void updateTimestamp() {
31 | updated.setTimeInMillis(System.currentTimeMillis());
32 | }
33 |
34 | @Override
35 | public int compareTo(AtomEntry t) {
36 | return getUpdated().compareTo(t.getUpdated());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/test/java/org/atomhopper/postgres/query/CategoryStringGeneratorTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.query;
2 |
3 |
4 | import org.junit.Test;
5 |
6 | import static junit.framework.Assert.assertEquals;
7 |
8 | public class CategoryStringGeneratorTest {
9 |
10 | final String SINGLE_CAT = "+Cat1";
11 | final String SINGLE_CAT_RESULT = "{cat1}";
12 |
13 | final String MULTI_CAT = "+Cat1+Cat2";
14 | final String MULTI_CAT_RESULT = "{cat1,cat2}";
15 |
16 | @Test
17 | public void shouldGenerateStringForSingleCategory() {
18 | String result = CategoryStringGenerator.getPostgresCategoryString(SINGLE_CAT);
19 | assertEquals(result, SINGLE_CAT_RESULT);
20 | }
21 |
22 | @Test
23 | public void shouldGenerateStringForMulitpleCategories() {
24 | String result = CategoryStringGenerator.getPostgresCategoryString(MULTI_CAT);
25 | assertEquals(result, MULTI_CAT_RESULT);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hopper/src/test/resources/org/atomhopper/config/WorkspaceConfigProcessorTest/noArchiveWithArchive.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/PostEntryRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.adapter.request.adapter.PostEntryRequest;
6 | import org.atomhopper.adapter.request.feed.AbstractFeedRequest;
7 |
8 | /**
9 | *
10 | *
11 | */
12 | public class PostEntryRequestImpl extends AbstractFeedRequest implements PostEntryRequest {
13 |
14 | public PostEntryRequestImpl(RequestContext abderaRequestContext) {
15 | super(abderaRequestContext);
16 | }
17 |
18 | @Override
19 | public Entry getEntry() {
20 | try {
21 | return getRequestContext().getDocument().getRoot();
22 | } catch (Exception ex) {
23 | throw new RequestParsingException("Failed to read in ATOM Entry data. Reason: " + ex.getMessage(), ex);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-namespace-feed-news.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/hopper/src/test/resources/org/atomhopper/config/WorkspaceConfigProcessorTest/archiveWithNoCurrent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/impl/DisabledFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
6 | import org.atomhopper.adapter.request.feed.FeedRequest;
7 |
8 | public final class DisabledFeedInformation implements FeedInformation {
9 |
10 | private static final DisabledFeedInformation INSTANCE = new DisabledFeedInformation();
11 |
12 | public static DisabledFeedInformation getInstance() {
13 | return INSTANCE;
14 | }
15 |
16 | private DisabledFeedInformation() {
17 | }
18 |
19 | @Override
20 | public String getId(FeedRequest feedRequest) {
21 | return "atomhopper:no-id";
22 | }
23 |
24 | @Override
25 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
26 | return getCategoriesRequest.newCategories();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/filter/FeedPagingProcessor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import java.util.Calendar;
4 | import java.util.TimeZone;
5 | import org.apache.abdera.model.Feed;
6 | import org.apache.abdera.protocol.server.RequestContext;
7 | import org.atomhopper.response.AdapterResponse;
8 |
9 |
10 | public class FeedPagingProcessor implements AdapterResponseInterceptor {
11 | @Override
12 | public void process(RequestContext rc, AdapterResponse adapterResponse) {
13 | final Feed f = adapterResponse.getBody();
14 |
15 | // If there are no entries in the feed
16 | if (f == null || f.getEntries() == null || f.getEntries().isEmpty()) {
17 | return;
18 | }
19 | // Add an updated element to the feed
20 | final Calendar localNow = Calendar.getInstance(TimeZone.getDefault());
21 | localNow.setTimeInMillis(System.currentTimeMillis());
22 | f.setUpdated(localNow.getTime());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/test-util/src/main/java/org/atomhopper/util/TestHelper.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util;
2 |
3 | import org.junit.Assert;
4 |
5 | /**
6 | * User: sbrayman
7 | * Date: Sep 29, 2011
8 | *
9 | * Assert not equals extension to junit.
10 | */
11 |
12 | public final class TestHelper {
13 |
14 | private TestHelper() {
15 | }
16 |
17 | public static void assertNotEquals(Object shouldNotBe, Object actual) {
18 | assertNotEquals(null, shouldNotBe, actual);
19 | }
20 |
21 | public static void assertNotEquals(String message, Object shouldNotBe, Object actual) {
22 |
23 | String formatted = "";
24 |
25 | if (message != null) {
26 | formatted = message + " ";
27 | }
28 |
29 | try {
30 | Assert.assertEquals(shouldNotBe, actual);
31 | } catch (Throwable valuesNotEqual) {
32 | return;
33 | }
34 |
35 | Assert.fail(formatted + "expected:<" + shouldNotBe + "> equaled:<" + actual + ">");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/servlet/DefaultEmptyContext.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.servlet;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import javax.servlet.ServletContext;
7 |
8 | public class DefaultEmptyContext implements ApplicationContextAdapter {
9 |
10 | private static final Logger LOG = LoggerFactory.getLogger(DefaultEmptyContext.class);
11 |
12 | @Override
13 | public T fromContext(Class classToCastTo) {
14 | return null;
15 | }
16 |
17 | @Override
18 | public T fromContext(String refName, Class classToCastTo) {
19 | return null;
20 | }
21 |
22 | @Override
23 | public void usingServletContext(ServletContext context) {
24 | LOG.warn("Missing context adapter init-parameter for servlet: "
25 | + ServletInitParameter.CONTEXT_ADAPTER_CLASS.toString()
26 | + " - Please note that this will enforce a default, empty context adapter for this servlet.");
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/test-suite/src/test/java/org/atomhopper/JettyIntegrationTestHarness.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import org.atomhopper.jetty.AtomHopperJettyServerBuilder;
4 | import org.eclipse.jetty.server.Server;
5 | import org.junit.AfterClass;
6 | import org.junit.BeforeClass;
7 |
8 | /**
9 | * Note: This test harness expects to have the statically configured port
10 | * available.
11 | *
12 | * TODO: Make the port configurable?
13 | */
14 | public class JettyIntegrationTestHarness {
15 |
16 | private static Server serverInstance;
17 |
18 | @BeforeClass
19 | public static void startServer() throws Exception {
20 | serverInstance = new AtomHopperJettyServerBuilder(getPort()).newServer();
21 | serverInstance.start();
22 | }
23 |
24 | @AfterClass
25 | public static void stopServer() throws Exception {
26 | if (serverInstance != null) {
27 | serverInstance.stop();
28 | }
29 | }
30 |
31 | public static int getPort() {
32 | return 24156;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/hopper/src/test/resources/org/atomhopper/config/WorkspaceConfigProcessorTest/noArchiveWithCurrent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hopper/src/test/resources/org/atomhopper/config/WorkspaceConfigProcessorTest/archiveWithCurrent.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/response/AdapterResponse.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.response;
2 |
3 | import org.apache.abdera.util.EntityTag;
4 | import org.springframework.http.HttpStatus;
5 |
6 |
7 | public interface AdapterResponse {
8 |
9 | /**
10 | *
11 | * @return
12 | */
13 | T getBody();
14 |
15 | /**
16 | *
17 | * @param name
18 | * @return
19 | */
20 | String getParameter(ResponseParameter name);
21 |
22 | /**
23 | * Setting a parameter will take the value's toString() value and use it to
24 | * represent the value.
25 | *
26 | * @param name
27 | * @param value
28 | * @return
29 | */
30 | AdapterResponse withParameter(ResponseParameter name, Object value);
31 |
32 | /**
33 | *
34 | * @return
35 | */
36 | String getMessage();
37 |
38 | /**
39 | *
40 | * @return
41 | */
42 | HttpStatus getResponseStatus();
43 |
44 | void setEntityTag(EntityTag entityTag);
45 | EntityTag getEntityTag();
46 | }
47 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/LogBackConfigLoaderTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import ch.qos.logback.core.joran.spi.JoranException;
4 | import org.junit.Before;
5 | import org.junit.Rule;
6 | import org.junit.Test;
7 | import org.junit.experimental.runners.Enclosed;
8 | import org.junit.rules.ExpectedException;
9 | import org.junit.runner.RunWith;
10 |
11 | import java.io.IOException;
12 |
13 | @RunWith(Enclosed.class)
14 | public class LogBackConfigLoaderTest {
15 |
16 | public static class WhenLoadingConfig {
17 |
18 | String someFakeFileLocation;
19 |
20 | @Before
21 | public void setUp() throws Exception {
22 | someFakeFileLocation = "/noSuchLocation";
23 | }
24 |
25 | @Rule
26 | public ExpectedException exception = ExpectedException.none();
27 |
28 | @Test
29 | public void shouldThrowIOException() throws IOException, JoranException {
30 | exception.expect(IOException.class);
31 | new LogBackConfigLoader(someFakeFileLocation);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/config/resource/file/FileConfigurationResourceTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource.file;
2 |
3 | import org.junit.Before;
4 | import org.junit.Rule;
5 | import org.junit.Test;
6 | import org.junit.experimental.runners.Enclosed;
7 | import org.junit.rules.ExpectedException;
8 | import org.junit.runner.RunWith;
9 |
10 | import java.io.IOException;
11 |
12 | @RunWith(Enclosed.class)
13 | public class FileConfigurationResourceTest {
14 |
15 | public static class WhenUsingConfigFiles {
16 |
17 | String someFakeFileLocation;
18 |
19 | @Before
20 | public void setUp() throws Exception {
21 | someFakeFileLocation = "/noSuchLocation";
22 | }
23 |
24 | @Rule
25 | public ExpectedException exception = ExpectedException.none();
26 |
27 | @Test
28 | public void shouldThrowIOException() throws Exception {
29 | exception.expect(IOException.class);
30 | new FileConfigurationResource(someFakeFileLocation).getInputStream();
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/main/java/org/atomhopper/postgres/query/EntryResultSetExtractor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.query;
2 |
3 | import java.sql.ResultSet;
4 | import java.sql.SQLException;
5 | import java.util.Arrays;
6 |
7 | import org.atomhopper.postgres.model.PersistedEntry;
8 |
9 | import org.springframework.jdbc.core.ResultSetExtractor;
10 |
11 | public class EntryResultSetExtractor implements ResultSetExtractor {
12 |
13 | @Override
14 | public Object extractData(ResultSet rs) throws SQLException {
15 |
16 | PersistedEntry entry = new PersistedEntry();
17 | entry.setFeed(rs.getString("feed"));
18 | entry.setCreationDate(rs.getTimestamp("creationdate"));
19 | entry.setDateLastUpdated(rs.getTimestamp("datelastupdated"));
20 | entry.setEntryBody(rs.getString("entrybody"));
21 | entry.setEntryId(rs.getString("entryid"));
22 |
23 | Object[] objArray = (Object[]) rs.getArray("categories").getArray();
24 | entry.setCategories(Arrays.copyOf(objArray, objArray.length, String[].class));
25 | return entry;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/config/AbstractConfigurationParserTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config;
2 |
3 | import org.junit.Ignore;
4 | import org.junit.Test;
5 | import org.junit.experimental.runners.Enclosed;
6 | import org.junit.runner.RunWith;
7 |
8 | @RunWith(Enclosed.class)
9 | public class AbstractConfigurationParserTest {
10 |
11 | private static final String EXPECTED_CONFIGURATION = "some config thing";
12 |
13 | public static class WhenReadingConfigurations {
14 |
15 | @Test(expected = IllegalStateException.class)
16 | public void shouldRejectReadingFromNullConfigurationResources() {
17 | new TestableConfigurationParser().read();
18 | }
19 | }
20 |
21 | @Ignore
22 | public static class TestableConfigurationParser extends AbstractConfigurationParser {
23 |
24 | public TestableConfigurationParser() {
25 | super(String.class);
26 | }
27 |
28 | @Override
29 | protected String readConfiguration() {
30 | return EXPECTED_CONFIGURATION;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/adapter/HibernateFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.NotImplemented;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 | import org.atomhopper.adapter.request.feed.FeedRequest;
8 | import org.atomhopper.dbal.FeedRepository;
9 |
10 | public class HibernateFeedInformation implements FeedInformation {
11 |
12 | private final FeedRepository feedRepository;
13 |
14 | public HibernateFeedInformation(FeedRepository feedRepository) {
15 | this.feedRepository = feedRepository;
16 | }
17 |
18 | @Override
19 | public String getId(FeedRequest feedRequest) {
20 | return feedRepository.getFeed(feedRequest.getFeedName()).getFeedId();
21 | }
22 |
23 | @Override @NotImplemented
24 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
25 | throw new UnsupportedOperationException("Not supported yet.");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hopper/src/test/resources/org/atomhopper/config/WorkspaceConfigProcessorTest/archiveWithArchive.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/ExternalConfigLoaderContextListener.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import javax.servlet.ServletContextEvent;
4 | import javax.servlet.ServletContextListener;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | /**
10 | * Simple utility listener to load certain properties before Spring Starts up.
11 | *
12 | * This code is modified from https://bowerstudios.com/node/896
13 | */
14 | public class ExternalConfigLoaderContextListener implements ServletContextListener {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(ExternalConfigLoaderContextListener.class);
17 |
18 | @Override
19 | public void contextInitialized(ServletContextEvent sce) {
20 | final String configLocation = "/etc/atomhopper/";
21 |
22 | try {
23 | new LogBackConfigLoader(configLocation + "logback.xml");
24 | } catch (Exception e) {
25 | LOGGER.error("Unable to read config file", e);
26 | }
27 | }
28 |
29 | @Override
30 | public void contextDestroyed(ServletContextEvent sce) {
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/ExternalConfigLoaderContextListenerTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import org.junit.Rule;
4 | import org.junit.Test;
5 | import org.junit.experimental.runners.Enclosed;
6 | import org.junit.rules.ExpectedException;
7 | import org.junit.runner.RunWith;
8 |
9 | import javax.servlet.ServletContextEvent;
10 |
11 | import static org.mockito.Mockito.mock;
12 |
13 | @RunWith(Enclosed.class)
14 | public class ExternalConfigLoaderContextListenerTest {
15 |
16 | public static class WhenInitializingContext {
17 |
18 | ExternalConfigLoaderContextListener externalConfigLoaderContextListener;
19 |
20 | @Rule
21 | public ExpectedException exception = ExpectedException.none();
22 |
23 | @Test
24 | public void shouldThrowErrorOnInitialization() throws Exception {
25 | exception.expect(ClassFormatError.class);
26 | externalConfigLoaderContextListener = new ExternalConfigLoaderContextListener();
27 | externalConfigLoaderContextListener.contextInitialized(mock(ServletContextEvent.class));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/dbal/PageDirection.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.dbal;
2 |
3 | /**
4 | * The PageDirection to request the page forward of the marker or backward
5 | * of the marker. The direction is based on the temporal direction of the feed
6 | * where forward is any time period after the creation date of the marker and
7 | * backward is any time period before the creation date of the marker.
8 | *
9 | * Forward pages should provides the next page, marker inclusive - AKA Previous.
10 | * Backward pages should provides the previous page, marker exclusive - AKA Next.
11 | *
12 | *
13 | * HEAD (First Entry in Live Feed) PAST (Older Entries)
14 | * =========================================================================
15 | * M
16 | * PREVIOUS a NEXT
17 | * BACKWARD r FORWARD
18 | * k
19 | * e
20 | * r
21 | * @author zinic
22 | */
23 | public enum PageDirection {
24 |
25 | FORWARD, BACKWARD
26 | }
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/filter/FeedConfigurationResponseProcessor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import org.apache.abdera.model.Feed;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.config.v1_0.Author;
6 | import org.atomhopper.config.v1_0.FeedConfiguration;
7 | import org.atomhopper.response.AdapterResponse;
8 |
9 | public class FeedConfigurationResponseProcessor implements AdapterResponseInterceptor {
10 | private final FeedConfiguration feedConfiguration;
11 |
12 | public FeedConfigurationResponseProcessor(FeedConfiguration feedConfiguration) {
13 | this.feedConfiguration = feedConfiguration;
14 | }
15 |
16 | @Override
17 | public void process(RequestContext rc, AdapterResponse adapterResponse) {
18 | final Feed feed = adapterResponse.getBody();
19 | Author author = feedConfiguration.getAuthor();
20 |
21 | if (author != null) {
22 | String name = author.getName();
23 | if ((name != null) && !(name.isEmpty()) && (feed.getAuthor() == null)) {
24 | feed.addAuthor(name);
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-multifeed-atom-server.cfg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/template/EnumKeyedTemplateParameters.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri.template;
2 |
3 | import java.util.Collections;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | //TODO: Consider making domain scoped child classes with helper methods
8 | // Something like setMarker(String markerId) or setPageLimit(int pageLimit)
9 | public class EnumKeyedTemplateParameters implements TemplateParameters {
10 |
11 | private final T temlpateTargetKey;
12 | private final Map parameterMap;
13 |
14 | public EnumKeyedTemplateParameters(T temlpateTargetKey) {
15 | this.temlpateTargetKey = temlpateTargetKey;
16 | this.parameterMap = new HashMap();
17 | }
18 |
19 | @Override
20 | public void set(URITemplateParameter parameter, Object value) {
21 | parameterMap.put(parameter.toString(), value);
22 | }
23 |
24 | @Override
25 | public Map toMap() {
26 | return Collections.unmodifiableMap(parameterMap);
27 | }
28 |
29 | @Override
30 | public T getTargetTemplateKey() {
31 | return temlpateTargetKey;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/test/java/org/atomhopper/hibernate/actions/PersistActionTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.actions;
2 |
3 | import org.hibernate.Session;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.experimental.runners.Enclosed;
7 | import org.junit.runner.RunWith;
8 |
9 | import static org.mockito.Mockito.mock;
10 | import static org.mockito.Mockito.only;
11 | import static org.mockito.Mockito.verify;
12 |
13 | /**
14 | * User: sbrayman
15 | * Date: Sep 23, 2011
16 | */
17 |
18 | @RunWith(Enclosed.class)
19 | public class PersistActionTest {
20 |
21 | public static class WhenPersistingAnAction {
22 | private Session session;
23 | private Object persistMe;
24 | private PersistAction persistAction;
25 |
26 | @Before
27 | public void setUp() throws Exception {
28 | session = mock(Session.class);
29 | persistMe = mock(Object.class);
30 | persistAction = new PersistAction(persistMe);
31 | }
32 |
33 | @Test
34 | public void shouldPersistSession() throws Exception {
35 | persistAction.perform(session);
36 | verify(session, only()).persist(persistMe);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/adapters/mongodb/src/main/java/org/atomhopper/mongodb/adapter/MongodbUtilities.java:
--------------------------------------------------------------------------------
1 |
2 | package org.atomhopper.mongodb.adapter;
3 |
4 | public final class MongodbUtilities {
5 |
6 | private MongodbUtilities() {
7 | throw new AssertionError();
8 | }
9 |
10 | protected static int safeLongToInt(long value) {
11 | if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
12 | throw new IllegalArgumentException
13 | (value + " cannot be cast to int without changing its value.");
14 | }
15 | return (int) value;
16 | }
17 |
18 | protected static String formatCollectionName(final String collection) {
19 | // Note: The maximum size of a collection name is 128 characters
20 | // (including the name of the db and indexes).
21 | // It is probably best to keep it under 80/90 chars.
22 | // http://www.mongodb.org/display/DOCS/Collections
23 | final int maxCollectionNameLength = 70;
24 |
25 | if(collection.length() > maxCollectionNameLength) {
26 | return collection.replace('/', '.').substring(0, maxCollectionNameLength);
27 | } else {
28 | return collection.replace('/', '.');
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test-util/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.atomhopper
7 | parent
8 | 1.2.35-SNAPSHOT
9 |
10 |
11 | org.atomhopper
12 | test-util
13 | jar
14 |
15 | ATOM Hopper - Test Utility
16 |
17 |
18 | UTF-8
19 |
20 |
21 |
22 |
23 | junit
24 | junit
25 | compile
26 |
27 |
28 |
29 |
30 |
31 |
32 | org.apache.maven.plugins
33 | maven-compiler-plugin
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/atomhopper-database-schema-ddl-postgres.sql:
--------------------------------------------------------------------------------
1 | SET statement_timeout = 0;
2 | SET client_encoding = 'UTF8';
3 | SET standard_conforming_strings = on;
4 | SET check_function_bodies = false;
5 | SET client_min_messages = warning;
6 |
7 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
8 |
9 | COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
10 |
11 | SET search_path = public, pg_catalog;
12 | SET default_tablespace = '';
13 | SET default_with_oids = false;
14 |
15 | CREATE TABLE entries (
16 | entryid text NOT NULL,
17 | creationdate timestamp without time zone NOT NULL,
18 | datelastupdated timestamp without time zone NOT NULL,
19 | entrybody text,
20 | feed text,
21 | categories character varying[],
22 | PRIMARY KEY(datelastupdated, entryid)
23 | );
24 | ALTER TABLE public.entries OWNER TO atomschema;
25 | CREATE INDEX entryid_idx on entries(entryid);
26 | CREATE INDEX categories_idx on entries(categories);
27 | CREATE INDEX feed_idx on entries(feed);
28 | CREATE INDEX feed_entryid_idx on entries(feed, entryid);
29 |
30 | REVOKE ALL ON SCHEMA public FROM PUBLIC;
31 | REVOKE ALL ON SCHEMA public FROM postgres;
32 | GRANT ALL ON SCHEMA public TO postgres;
33 | GRANT ALL ON SCHEMA public TO PUBLIC;
34 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/adapter/impl/DisabledFeedInformationTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import static junit.framework.Assert.assertEquals;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.junit.experimental.runners.Enclosed;
8 | import org.junit.runner.RunWith;
9 | import static org.mockito.Mockito.mock;
10 |
11 | /**
12 | * User: sbrayman
13 | * Date: Sep 26, 2011
14 | */
15 |
16 | @RunWith(Enclosed.class)
17 | public class DisabledFeedInformationTest {
18 |
19 | public static class WhenAccessingDisabledFeedInformation {
20 |
21 | private DisabledFeedInformation disabledFeedInformation;
22 | private FeedRequest feedRequest;
23 | private String noId;
24 |
25 | @Before
26 | public void setUp() throws Exception {
27 | disabledFeedInformation = DisabledFeedInformation.getInstance();
28 | feedRequest = mock(FeedRequest.class);
29 | noId = "atomhopper:no-id";
30 | }
31 |
32 | @Test
33 | public void shouldNotReturnId() throws Exception {
34 | assertEquals("Get Id should return " + noId, disabledFeedInformation.getId(feedRequest), noId);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/jetty-killer/src/main/java/org/atomhopper/jettykiller/AtomHopperServerControl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jettykiller;
2 |
3 |
4 |
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | //
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 | import java.net.InetAddress;
12 | import java.net.Socket;
13 |
14 |
15 | public class AtomHopperServerControl {
16 | private static final Logger LOG = LoggerFactory.getLogger(AtomHopperServerControl.class);
17 |
18 | private final CommandLineArguments commandLineArgs;
19 | private static final String LOCALHOST_IP = "127.0.0.1";
20 |
21 | public AtomHopperServerControl(CommandLineArguments commandLineArgs) {
22 | this.commandLineArgs = commandLineArgs;
23 | }
24 |
25 | public void stopAtomHopper() {
26 | try {
27 | Socket s = new Socket(InetAddress.getByName(LOCALHOST_IP), commandLineArgs.stopport);
28 | OutputStream out = s.getOutputStream();
29 | LOG.info("Sending Atom Hopper stop request");
30 | out.write(("\r\n").getBytes());
31 | out.flush();
32 | s.close();
33 | } catch (IOException ioex) {
34 | LOG.error("An error occured while attempting to stop Atom Hopper: " + ioex.getMessage());
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/WorkspaceManager.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera;
2 |
3 | import org.apache.abdera.protocol.server.CollectionAdapter;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.apache.abdera.protocol.server.WorkspaceInfo;
6 |
7 | import java.util.Collection;
8 | import java.util.LinkedList;
9 | import java.util.List;
10 |
11 | public class WorkspaceManager implements org.apache.abdera.protocol.server.WorkspaceManager {
12 |
13 | private final List handlers;
14 |
15 | public WorkspaceManager() {
16 | handlers = new LinkedList();
17 | }
18 |
19 | public void addWorkspaces(List workspaces) {
20 | handlers.addAll(workspaces);
21 | }
22 |
23 | @Override
24 | public Collection getWorkspaces(RequestContext request) {
25 | return (Collection) handlers;
26 | }
27 |
28 | @Override
29 | public CollectionAdapter getCollectionAdapter(RequestContext request) {
30 | for (WorkspaceHandler workspace : handlers) {
31 | final CollectionAdapter adapter = workspace.getAnsweringAdapter(request);
32 |
33 | if (adapter != null) {
34 | return adapter;
35 | }
36 | }
37 |
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/main/resources/ddl/postgres/atomhopper-database-schema-ddl-postgres.sql:
--------------------------------------------------------------------------------
1 | SET statement_timeout = 0;
2 | SET client_encoding = 'UTF8';
3 | SET standard_conforming_strings = on;
4 | SET check_function_bodies = false;
5 | SET client_min_messages = warning;
6 |
7 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
8 |
9 | COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
10 |
11 | SET search_path = public, pg_catalog;
12 | SET default_tablespace = '';
13 | SET default_with_oids = false;
14 |
15 | CREATE TABLE entries (
16 | entryid character varying(255) CONSTRAINT entries_pkey PRIMARY KEY,
17 | creationdate timestamp without time zone NOT NULL,
18 | datelastupdated timestamp without time zone NOT NULL,
19 | entrybody character varying,
20 | feed character varying(255),
21 | categories character varying[]
22 | );
23 | ALTER TABLE public.entries OWNER TO atomschema;
24 | CREATE INDEX datelastupdated_idx on entries(datelastupdated);
25 | CREATE INDEX categories_idx on entries(categories);
26 | CREATE INDEX feed_idx on entries(feed);
27 | CREATE INDEX feed_datelastupdated_idx on entries(feed, datelastupdated);
28 |
29 | REVOKE ALL ON SCHEMA public FROM PUBLIC;
30 | REVOKE ALL ON SCHEMA public FROM postgres;
31 | GRANT ALL ON SCHEMA public TO postgres;
32 | GRANT ALL ON SCHEMA public TO PUBLIC;
33 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/adapter/request/impl/PostEntryRequestImplTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.impl;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.atomhopper.adapter.request.adapter.impl.PostEntryRequestImpl;
5 | import org.atomhopper.adapter.request.adapter.impl.RequestParsingException;
6 | import org.junit.Before;
7 | import org.junit.Test;
8 | import org.junit.experimental.runners.Enclosed;
9 | import org.junit.runner.RunWith;
10 |
11 | import java.io.IOException;
12 |
13 | import static org.mockito.Mockito.mock;
14 | import static org.mockito.Mockito.when;
15 |
16 | @RunWith(Enclosed.class)
17 | public class PostEntryRequestImplTest {
18 |
19 | public static class WhenParsingAdberaRequestContexts {
20 |
21 | private RequestContext requestContextMock;
22 |
23 | @Before
24 | public void standUp() throws Exception {
25 | requestContextMock = mock(RequestContext.class);
26 |
27 | when(requestContextMock.getDocument()).thenThrow(new IOException("Unable to read stream"));
28 | }
29 |
30 | @Test (expected = RequestParsingException.class)
31 | public void shouldWrapExceptionCasesGracefully() {
32 | new PostEntryRequestImpl(requestContextMock).getEntry();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/AbstractConfigurationParser.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config;
2 |
3 | import org.atomhopper.util.config.resource.ConfigurationResource;
4 |
5 | public abstract class AbstractConfigurationParser implements ConfigurationParser {
6 |
7 | private final Class configurationClassDefinition;
8 | private ConfigurationResource configurationResource;
9 |
10 | public AbstractConfigurationParser(Class configurationClassDefinition) {
11 | this.configurationClassDefinition = configurationClassDefinition;
12 | }
13 |
14 | @Override
15 | public Class getConfigurationClass() {
16 | return configurationClassDefinition;
17 | }
18 |
19 | @Override
20 | public void setConfigurationResource(ConfigurationResource resource) {
21 | configurationResource = resource;
22 | }
23 |
24 | @Override
25 | public ConfigurationResource getConfigurationResource() {
26 | return configurationResource;
27 | }
28 |
29 | @Override
30 | public final T read() {
31 | if (configurationResource == null) {
32 | throw new IllegalStateException("A configuration resource must be set first before reading from it.");
33 | }
34 |
35 | return readConfiguration();
36 | }
37 |
38 | protected abstract T readConfiguration();
39 | }
40 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-web.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | Atom Hopper Server
6 | ATOM
7 |
8 |
9 |
10 |
24 |
25 | atomhopper-url-pattern
26 | /atom/
27 |
28 |
29 |
30 |
31 | Atom-Hopper
32 | /atom/*
33 |
34 |
35 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/servlet/ServletSpringContext.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.servlet;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.ApplicationContextAware;
5 | import org.springframework.web.context.support.WebApplicationContextUtils;
6 |
7 | import javax.servlet.ServletContext;
8 |
9 | /*
10 | * @author John Hopper
11 | */
12 | public class ServletSpringContext implements ApplicationContextAware, ApplicationContextAdapter {
13 |
14 | private ApplicationContext applicationContext;
15 |
16 | @Override
17 | public synchronized void setApplicationContext(ApplicationContext ac) {
18 | if (applicationContext == null) {
19 | applicationContext = ac;
20 | }
21 | }
22 |
23 | @Override
24 | public synchronized void usingServletContext(ServletContext context) {
25 | if (applicationContext == null) {
26 | applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
27 | }
28 | }
29 |
30 | @Override
31 | public T fromContext(Class classToCastTo) {
32 | return applicationContext.getBean(classToCastTo);
33 | }
34 |
35 | @Override
36 | public T fromContext(String refName, Class classToCastTo) {
37 | return applicationContext.getBean(refName, classToCastTo);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/server/src/main/java/org/atomhopper/server/CommandLineArguments.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.server;
2 |
3 | import org.kohsuke.args4j.Argument;
4 | import org.kohsuke.args4j.Option;
5 |
6 | class CommandLineArguments {
7 |
8 | private static final String DEFAULT_PORT_INFO = "(Default listen port is 8080, default listen for shutdown port is 8818 (acceptable range is 1024 to 49150)";
9 | static final String ACTION_START = "start";
10 | static final String ACTION_STOP = "stop";
11 | private static final int PORT = 8080;
12 | private static final int STOPPORT = 8818;
13 |
14 | @Option(name = "-p", aliases = {"--port"},
15 | usage = "Atom Hopper port number " + DEFAULT_PORT_INFO)
16 | public final Integer port = PORT;
17 |
18 | @Option(name = "-s", aliases = {"--shutdown-port"},
19 | usage = "The port used to communicate a shutdown to Atom Hopper " + DEFAULT_PORT_INFO)
20 | public final Integer stopport = STOPPORT;
21 |
22 | @Option(name = "-c", aliases = {"--config-file"},
23 | usage = "The location and name of the Atom Hopper configuration file")
24 | public String configFile;
25 |
26 | //Note: I recommend keeping this an argument to stay inline with what people expect from a daemon script
27 | @Argument(usage = "Action to take - start | stop", required = true)
28 | public String action = ACTION_START;
29 | }
30 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/uri/ClasspathSchemeMapperTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri;
2 |
3 | import org.junit.Before;
4 | import org.junit.Test;
5 | import org.junit.experimental.runners.Enclosed;
6 | import org.junit.runner.RunWith;
7 |
8 | import java.net.URI;
9 |
10 | import static org.junit.Assert.assertFalse;
11 | import static org.junit.Assert.assertTrue;
12 |
13 | @RunWith(Enclosed.class)
14 | public class ClasspathSchemeMapperTest {
15 |
16 | public static class WhenMappingClasspathURIs {
17 |
18 | private URISchemeMapper classpathSchemeMapper;
19 | private URI classpathURI, httpURI;
20 |
21 | @Before
22 | public void standUp() throws Exception {
23 | classpathSchemeMapper = new ClasspathSchemeMapper();
24 |
25 | classpathURI = new URI("classpath:/META-INF/schema/config/bindings.xjb");
26 | httpURI = new URI("http://localhost");
27 | }
28 |
29 | @Test
30 | public void shouldMatchClasspathURIs() {
31 | assertTrue("ClasspathSchemeMapper should match on valid classpath URI", classpathSchemeMapper.canMap(classpathURI));
32 | }
33 |
34 | @Test
35 | public void shouldNotMatchNonClasspathURIs() {
36 | assertFalse("ClasspathSchemeMapper should not match on invalid classpath URI", classpathSchemeMapper.canMap(httpURI));
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hopper/src/main/resources/META-INF/schema/examples/config/feed-server-config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/hibernate/HibernateSessionManager.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate;
2 |
3 | import java.util.Map;
4 | import org.atomhopper.adapter.jpa.PersistedCategory;
5 | import org.atomhopper.adapter.jpa.PersistedEntry;
6 | import org.atomhopper.adapter.jpa.PersistedFeed;
7 | import org.hibernate.Session;
8 | import org.hibernate.SessionFactory;
9 | import org.hibernate.cfg.Configuration;
10 |
11 | public class HibernateSessionManager {
12 |
13 | private final SessionFactory sessionFactory;
14 |
15 | public HibernateSessionManager(Map parameters) {
16 | sessionFactory = buildSessionFactory(parameters);
17 | }
18 |
19 | private static SessionFactory buildSessionFactory(Map parameters) {
20 | final Configuration hibernateConfiguration = new Configuration()
21 | .addAnnotatedClass(PersistedFeed.class)
22 | .addAnnotatedClass(PersistedEntry.class)
23 | .addAnnotatedClass(PersistedCategory.class);
24 |
25 | for (Map.Entry userParameter : parameters.entrySet()) {
26 | hibernateConfiguration.setProperty(userParameter.getKey(), userParameter.getValue());
27 | }
28 |
29 | return hibernateConfiguration.buildSessionFactory();
30 | }
31 |
32 | public Session getSession() {
33 | return sessionFactory.openSession();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-application-context-db-h2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
27 |
--------------------------------------------------------------------------------
/documentation/src/resources/samples/ah-application-context-db-mysql.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
27 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/java/org/atomhopper/dbal/FeedRepository.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.dbal;
2 |
3 | import org.atomhopper.adapter.jpa.PersistedCategory;
4 | import org.atomhopper.adapter.jpa.PersistedEntry;
5 | import org.atomhopper.adapter.jpa.PersistedFeed;
6 | import org.atomhopper.hibernate.query.CategoryCriteriaGenerator;
7 |
8 | import java.util.Collection;
9 | import java.util.List;
10 | import java.util.Set;
11 |
12 | public interface FeedRepository {
13 |
14 | Set getCategoriesForFeed(final String feedName);
15 |
16 | Collection getAllFeeds();
17 |
18 | PersistedFeed getFeed(String resourceName);
19 |
20 | void saveFeed(PersistedFeed feed);
21 |
22 | List getFeedHead(String feedName, CategoryCriteriaGenerator categoryCriteria, int pageSize);
23 |
24 | List getFeedPage(String feedName, PersistedEntry markerEntry, PageDirection direction,
25 | CategoryCriteriaGenerator categoryCriteria, int pageSize);
26 |
27 | PersistedEntry getEntry(String entryId, String feedName);
28 |
29 | List getLastPage(String feedName, int pageSize, CategoryCriteriaGenerator criteriaGenerator);
30 |
31 | void saveEntry(PersistedEntry entry);
32 |
33 | Set updateCategories(Set categories);
34 |
35 | PersistedEntry getNextMarker(PersistedEntry persistedEntry, String feedName, CategoryCriteriaGenerator criteriaGenerator);
36 | }
37 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/uri/CustomSchemeResolver.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.uri;
2 |
3 | import java.net.MalformedURLException;
4 | import java.net.URI;
5 | import java.net.URL;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | /**
10 | * Due to some strange restriction placed on the URLStreamHandlerFactory (see:
11 | * http://download.oracle.com/javase/6/docs/api/index.html?java/net/URL.html) this
12 | * little mapper was introduced to allow for custom scheme matching.
13 | */
14 | public class CustomSchemeResolver implements UriToUrlResolver {
15 |
16 | public static UriToUrlResolver newDefaultInstance() {
17 | final CustomSchemeResolver resolverInstance = new CustomSchemeResolver();
18 | resolverInstance.addMapper(new ClasspathSchemeMapper());
19 |
20 | return resolverInstance;
21 | }
22 |
23 |
24 | private final Set schemeMapperSet;
25 |
26 | public CustomSchemeResolver() {
27 | schemeMapperSet = new HashSet();
28 | }
29 |
30 | public void addMapper(URISchemeMapper mapper) {
31 | schemeMapperSet.add(mapper);
32 | }
33 |
34 | @Override
35 | public URL toURL(URI uri) throws MalformedURLException {
36 | for (URISchemeMapper mapper : schemeMapperSet) {
37 | if (mapper.canMap(uri)) {
38 | return mapper.toURL(uri);
39 | }
40 | }
41 |
42 | //Default fallback
43 | return uri.toURL();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test-suite/src/test/java/org/atomhopper/GetVersionPathTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import static junit.framework.Assert.assertEquals;
4 | import static junit.framework.Assert.assertTrue;
5 | import org.apache.commons.httpclient.HttpClient;
6 | import org.apache.commons.httpclient.HttpMethod;
7 | import org.apache.commons.httpclient.HttpStatus;
8 | import org.apache.commons.httpclient.methods.GetMethod;
9 | import org.junit.Test;
10 | import org.junit.experimental.runners.Enclosed;
11 | import org.junit.runner.RunWith;
12 |
13 | @RunWith(Enclosed.class)
14 | public class GetVersionPathTest extends JettyIntegrationTestHarness {
15 |
16 | private static final HttpClient httpClient = new HttpClient();
17 | private static final String urlAndPort = "http://localhost:" + getPort();
18 |
19 | public static GetMethod getVersionPathMethod() {
20 | return new GetMethod(urlAndPort + "/buildinfo");
21 | }
22 |
23 | public static class WhenGettingVersionInfo {
24 |
25 | private final HttpMethod getVersionMethod = getVersionPathMethod();
26 |
27 | @Test
28 | public void shouldReturnHTTP200AndEmptyJSON() throws Exception {
29 | assertEquals("Getting the version should return a 200", HttpStatus.SC_OK, httpClient.executeMethod(getVersionMethod));
30 | // Since the test doesn't have the Maven version info, empty JSON will come back
31 | assertTrue(new String(getVersionMethod.getResponseBody()).contains("{}"));
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/test/java/org/atomhopper/hibernate/HibernateFeedRepositoryTestMain.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate;
2 |
3 | import org.atomhopper.adapter.jpa.PersistedEntry;
4 | import org.atomhopper.adapter.jpa.PersistedFeed;
5 | import org.atomhopper.hibernate.actions.SimpleSessionAction;
6 | import org.hibernate.Session;
7 | import org.hibernate.criterion.Restrictions;
8 |
9 | import java.util.Collections;
10 |
11 | public class HibernateFeedRepositoryTestMain {
12 |
13 | public static void main(String[] args) {
14 | final HibernateFeedRepository feedRepository = new HibernateFeedRepository(Collections.EMPTY_MAP);
15 |
16 | feedRepository.saveFeed(new PersistedFeed("testing", "uuid:not-really"));
17 | PersistedFeed f = feedRepository.getFeed("testing");
18 |
19 | System.out.println(f != null ? f.getName() : "null");
20 |
21 | PersistedEntry entry = new PersistedEntry("some-random-uuid");
22 | entry.setFeed(new PersistedFeed("testing", "uuid:not-really"));
23 |
24 | feedRepository.saveEntry(entry);
25 |
26 | feedRepository.performSimpleAction(new SimpleSessionAction() {
27 |
28 | @Override
29 | public void perform(Session liveSession) {
30 | PersistedFeed f = (PersistedFeed) liveSession.createCriteria(PersistedFeed.class).add(Restrictions.idEq("testing")).list().get(0);
31 |
32 | System.out.println("Entries: " + (f != null ? f.getEntries().size() : 0));
33 | }
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/docker/README.md:
--------------------------------------------------------------------------------
1 | # docker build image and run the conatiner
2 | Your current direcotry should be pointing to ***atom-hopper/docker***.
3 | Run the following command to build an image.
4 | ```
5 | $docker build -t atomhopper:latest-alpine .
6 | ```
7 | You can use the following command to run a container by provinding the appropriate values to the variables.
8 | ```
9 | $docker run -d --name [Conatiner_Name] -p 8080:8080 -e DB_TYPE=[Database_Type (PostgreSQL, MySQL)] -e DB_USER=[Database_Username] -e DB_PASSWORD=[Database_Password] -e DB_HOST=[IP:PORT] atomhopper:latest-alpine
10 | ```
11 |
12 | To run atomhopper with default database configuration (H2) and port 8080
13 | ```
14 | $docker run -d --name atomhopper -p 8080:8080 atomhopper:latest-alpine
15 | ```
16 | Test the sample feed at http://localhost:8080/namespace/feed
17 |
18 | H2 is the default databse configured to be used. The databse file for this is present under */opt/atomhopper*
19 |
20 | Following environment variables are set by default
21 | ```
22 | JAVA_HOME "/opt/java/openjdk8/jre"
23 | CATALINA_HOME "/opt/tomcat"
24 | AH_HOME "/opt/atomhopper"
25 | AH_VERSION "1.2.33"
26 | ```
27 | For specific databse configuration of your choice (PostgreSQL,MySQL) provide values for the variables DB_TYPE, DB_USER, DB_PASSWORD and DB_HOST
28 |
29 | Example of running with a PostgreSQL databse hosted externally.
30 | ```
31 | $docker run -d --name atomhopper -p 8080:8080 -e DB_TYPE=PostgreSQL -e DB_USER=postgresql -e DB_PASSWORD=postgresql -e DB_HOST=10.0.0.1:5432 atomhopper:latest-alpine
32 | ```
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/server/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | /var/log/atomhopper/atomhopper-logback.log
14 |
15 | %d{yyyy-MM-dd HH:mm:s} %-4r [%t] %-5p %c %x - %m%n
16 |
17 |
18 | 100
19 | /var/log/atomhopper/atomhopper-logback.log.%i
20 |
21 |
22 | 100MB
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/hopper/src/main/resources/template-logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | /var/log/atomhopper/atomhopper-logback.log
14 |
15 | %d{yyyy-MM-dd HH:mm:s} %-4r [%t] %-5p %c %x - %m%n
16 |
17 |
18 | 100
19 | /var/log/atomhopper/atomhopper-logback.log.%i
20 |
21 |
22 | 100MB
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/atomhopper/src/main/webapp/META-INF/template-logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | /var/log/atomhopper/atomhopper-logback.log
14 |
15 | %d{yyyy-MM-dd HH:mm:s} %-4r [%t] %-5p %c %x - %m%n
16 |
17 |
18 | 100
19 | /var/log/atomhopper/atomhopper-logback.log.%i
20 |
21 |
22 | 100MB
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/filter/FeedEntityTagProcessor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import org.apache.abdera.model.Feed;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.apache.abdera.util.EntityTag;
6 | import org.atomhopper.response.AdapterResponse;
7 |
8 | /**
9 | * AdapterResponseProcessor for a Feed that adds a weak entity tag to the feed using
10 | * the entry id of the first entry in the feed.
11 | */
12 | public class FeedEntityTagProcessor implements AdapterResponseInterceptor {
13 |
14 | @Override
15 | public void process(RequestContext rc, AdapterResponse adapterResponse) {
16 | final Feed f = adapterResponse.getBody();
17 |
18 | if(f == null) {
19 | return;
20 | }
21 |
22 | final int totalEntries = f.getEntries().size();
23 |
24 | // If there are no entries in the feed
25 | if (totalEntries == 0) {
26 | return;
27 | }
28 |
29 | // Get the id of the first entry on this page
30 | String id = f.getEntries().get(0).getId().toString();
31 | // Get the id of the last entry on this page
32 | String lastId = f.getEntries().get(totalEntries-1).getId().toString();
33 |
34 | EntityTag feedEtag = createEntityTag(rc, id, lastId);
35 | adapterResponse.setEntityTag(feedEtag);
36 | }
37 |
38 | protected EntityTag createEntityTag(RequestContext rc, String firstId, String lastId) {
39 | return new EntityTag(firstId + ":" + lastId, true);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/impl/DisabledPublisher.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.atomhopper.adapter.FeedPublisher;
5 | import org.atomhopper.adapter.ResponseBuilder;
6 | import org.atomhopper.adapter.request.adapter.DeleteEntryRequest;
7 | import org.atomhopper.adapter.request.adapter.PostEntryRequest;
8 | import org.atomhopper.adapter.request.adapter.PutEntryRequest;
9 | import org.atomhopper.response.AdapterResponse;
10 | import org.atomhopper.response.EmptyBody;
11 |
12 | public final class DisabledPublisher extends AbstractDisabledAdapter implements FeedPublisher {
13 |
14 | private static final DisabledPublisher INSTANCE = new DisabledPublisher();
15 | private static final String OP_NOT_SUPPORTED_MESSAGE = "Operation not supported";
16 |
17 | public static DisabledPublisher getInstance() {
18 | return INSTANCE;
19 | }
20 |
21 | private DisabledPublisher() {
22 | }
23 |
24 | @Override
25 | public AdapterResponse deleteEntry(DeleteEntryRequest deleteEntryRequest) {
26 | return ResponseBuilder.notImplemented(OP_NOT_SUPPORTED_MESSAGE);
27 | }
28 |
29 | @Override
30 | public AdapterResponse postEntry(PostEntryRequest postEntryRequest) {
31 | return ResponseBuilder.notImplemented(OP_NOT_SUPPORTED_MESSAGE);
32 | }
33 |
34 | @Override
35 | public AdapterResponse putEntry(PutEntryRequest putEntryRequest) {
36 | return ResponseBuilder.notImplemented(OP_NOT_SUPPORTED_MESSAGE);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/adapters/migration/src/main/java/org/atomhopper/migration/adapter/MigrationFeedInformation.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.migration.adapter;
2 |
3 | import org.apache.abdera.model.Categories;
4 | import org.atomhopper.adapter.FeedInformation;
5 | import org.atomhopper.adapter.NotImplemented;
6 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
7 | import org.atomhopper.adapter.request.feed.FeedRequest;
8 | import org.atomhopper.migration.domain.MigrationReadFrom;
9 |
10 | public class MigrationFeedInformation implements FeedInformation {
11 |
12 | private FeedInformation oldFeedInformation;
13 | private FeedInformation newFeedInformation;
14 | private MigrationReadFrom readFrom;
15 |
16 | public void setOldFeedInformation(FeedInformation oldFeedInformation) {
17 | this.oldFeedInformation = oldFeedInformation;
18 | }
19 |
20 | public void setNewFeedInformation(FeedInformation newFeedInformation) {
21 | this.newFeedInformation = newFeedInformation;
22 | }
23 |
24 | public void setReadFrom(MigrationReadFrom readFrom) {
25 | this.readFrom = readFrom;
26 | }
27 |
28 | @Override
29 | public String getId(FeedRequest getFeedRequest) {
30 | return readFrom == MigrationReadFrom.NEW ? newFeedInformation.getId(getFeedRequest)
31 | : oldFeedInformation.getId(getFeedRequest);
32 | }
33 |
34 | @Override
35 | @NotImplemented
36 | public Categories getCategories(GetCategoriesRequest getCategoriesRequest) {
37 | throw new UnsupportedOperationException("Not supported yet.");
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | #base tomcat 9 with openjdk 8
2 | FROM tomcat:9.0.41-jdk8 as tomcat
3 |
4 | FROM adoptopenjdk/openjdk8:alpine-slim
5 |
6 | LABEL maintainer="AtomHopperTeam@rackspace.com" \
7 | #Atom Hopper version
8 | version="1.2.33" \
9 | description="Docker image for Atom Hopper"
10 |
11 | #The database type
12 | ENV DB_TYPE=H2 \
13 | #Database username
14 | DB_USER=sa \
15 | #Database password
16 | DB_PASSWORD= \
17 | #Database Host:Port
18 | DB_HOST=h2 \
19 | AH_VERSION=1.2.33 \
20 | CATALINA_HOME=/opt/tomcat \
21 | AH_HOME=/opt/atomhopper \
22 | PATH=${PATH}:${CATALINA_HOME}/bin:${AH_HOME}
23 |
24 | RUN mkdir -p "${CATALINA_HOME}" "${AH_HOME}" /etc/atomhopper/ /var/log/atomhopper/
25 |
26 | WORKDIR ${AH_HOME}
27 |
28 | COPY --from=tomcat /usr/local/tomcat ${CATALINA_HOME}
29 | COPY start.sh .
30 |
31 | RUN apk --no-cache add curl \
32 | && curl -o atomhopper.war https://maven.research.rackspacecloud.com/content/repositories/releases/org/atomhopper/atomhopper/${AH_VERSION}/atomhopper-${AH_VERSION}.war \
33 | && unzip atomhopper.war META-INF/application-context.xml META-INF/template-logback.xml WEB-INF/classes/META-INF/atom-server.cfg.xml -d . \
34 | && mv META-INF/application-context.xml WEB-INF/classes/META-INF/atom-server.cfg.xml /etc/atomhopper/ \
35 | && mv META-INF/template-logback.xml /etc/atomhopper/logback.xml \
36 | && mv atomhopper.war ${CATALINA_HOME}/webapps/ROOT.war \
37 | && rm -rf META-INF WEB-INF \
38 | && chmod +x ${AH_HOME}/start.sh
39 |
40 | EXPOSE 8080
41 |
42 | CMD ["start.sh"]
43 |
44 |
--------------------------------------------------------------------------------
/atomhopper/src/main/resources/META-INF/atom-server.cfg.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/response/EmptyBodyResponseHandler.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.response;
2 |
3 | import org.apache.abdera.protocol.server.ProviderHelper;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.apache.abdera.protocol.server.ResponseContext;
6 | import org.atomhopper.abdera.filter.AdapterResponseInterceptor;
7 | import org.atomhopper.response.AdapterResponse;
8 | import org.atomhopper.response.EmptyBody;
9 |
10 | public class EmptyBodyResponseHandler extends AbstractResponseHandler {
11 |
12 | public EmptyBodyResponseHandler(String[] allowedMethods, AdapterResponseInterceptor... interceptors) {
13 | super(allowedMethods, interceptors);
14 | }
15 |
16 | @Override
17 | protected ResponseContext handleAdapterResponse(RequestContext rc, AdapterResponse adapterResponse) {
18 | switch (adapterResponse.getResponseStatus()) {
19 | case NOT_FOUND:
20 | return ProviderHelper.notfound(rc, adapterResponse.getMessage());
21 |
22 | case INTERNAL_SERVER_ERROR:
23 | return ProviderHelper.servererror(rc, adapterResponse.getMessage(), new InternalServerException());
24 |
25 | case METHOD_NOT_ALLOWED:
26 | return ProviderHelper.notallowed(rc, adapterResponse.getMessage(), getAllowedHttpMethods());
27 |
28 | case BAD_REQUEST:
29 | return ProviderHelper.badrequest(rc, adapterResponse.getMessage());
30 |
31 | default:
32 | return ProviderHelper.nocontent();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/jpa/PersistedFeed.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.jpa;
2 |
3 | import javax.persistence.Column;
4 | import javax.persistence.Entity;
5 | import javax.persistence.FetchType;
6 | import javax.persistence.Id;
7 | import javax.persistence.OneToMany;
8 | import javax.persistence.Table;
9 | import java.io.Serializable;
10 | import java.util.Collections;
11 | import java.util.HashSet;
12 | import java.util.Set;
13 |
14 | @Entity
15 | @Table(name = "Feeds")
16 | public class PersistedFeed implements Serializable {
17 |
18 | @Id
19 | @Column(name = "Name")
20 | private String name;
21 |
22 | @Column(name = "FeedID")
23 | private String feedId;
24 |
25 | @OneToMany(mappedBy = "feed", fetch = FetchType.LAZY)
26 | private Set entries;
27 |
28 | public PersistedFeed() {
29 | entries = Collections.EMPTY_SET;
30 | }
31 |
32 | public PersistedFeed(String name, String feedId) {
33 | entries = new HashSet();
34 |
35 | this.feedId = feedId;
36 | this.name = name;
37 | }
38 |
39 | public Set getEntries() {
40 | return entries;
41 | }
42 |
43 | public void setEntries(Set entries) {
44 | this.entries = entries;
45 | }
46 |
47 | public String getFeedId() {
48 | return feedId;
49 | }
50 |
51 | public void setFeedId(String feedId) {
52 | this.feedId = feedId;
53 | }
54 |
55 | public String getName() {
56 | return name;
57 | }
58 |
59 | public void setName(String name) {
60 | this.name = name;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/config/resource/uri/URIConfigurationResource.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource.uri;
2 |
3 | import org.atomhopper.util.config.resource.ConfigurationResource;
4 | import org.atomhopper.util.config.resource.ConfigurationResourceException;
5 | import org.atomhopper.util.uri.CustomSchemeResolver;
6 | import org.atomhopper.util.uri.UriToUrlResolver;
7 |
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.net.MalformedURLException;
11 | import java.net.URI;
12 | import java.net.URL;
13 |
14 | public class URIConfigurationResource implements ConfigurationResource {
15 |
16 | private final URI resourceLocation;
17 | private final UriToUrlResolver uriSchemeResolver;
18 |
19 | public URIConfigurationResource(URI resourceLocation) {
20 | this(resourceLocation, CustomSchemeResolver.newDefaultInstance());
21 | }
22 |
23 | public URIConfigurationResource(URI resourceLocation, UriToUrlResolver customUriSchemeResolver) {
24 | this.resourceLocation = resourceLocation;
25 | this.uriSchemeResolver = customUriSchemeResolver;
26 | }
27 |
28 | @Override
29 | public InputStream getInputStream() throws IOException {
30 | try {
31 | final URL location = uriSchemeResolver.toURL(resourceLocation);
32 | return location.openStream();
33 | } catch (MalformedURLException murle) {
34 | throw new ConfigurationResourceException("URI produces a malformed URL. URI, \""
35 | + resourceLocation.toString()
36 | + "\" may be unsupported. Reason: " + murle.getMessage(), murle);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/AbstractClientRequest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request;
2 |
3 | import org.apache.abdera.Abdera;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.util.uri.template.TemplateParameters;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Base class that contains the wrapped RequestContext from Abdera. All domain
11 | * specific request classes should inherit from this class.
12 | */
13 | public abstract class AbstractClientRequest implements ClientRequest {
14 |
15 | private final RequestContext abderaRequestContext;
16 |
17 | protected AbstractClientRequest(RequestContext abderaRequestContext) {
18 | this.abderaRequestContext = abderaRequestContext;
19 | }
20 |
21 | protected RequestContext getRequestContext() {
22 | return abderaRequestContext;
23 | }
24 |
25 | @Override
26 | public String urlFor(TemplateParameters param) {
27 | return abderaRequestContext.urlFor(param.getTargetTemplateKey(), param);
28 | }
29 |
30 | @Override
31 | public Abdera getAbdera() {
32 | return abderaRequestContext.getAbdera();
33 | }
34 |
35 | @Override
36 | public String getTargetParameter(String parameter) {
37 | return abderaRequestContext.getTarget().getParameter(parameter);
38 | }
39 |
40 | @Override
41 | public String getRequestParameter(String parameter) {
42 | return abderaRequestContext.getParameter(parameter);
43 | }
44 |
45 | @Override
46 | public List getRequestParameters(String parameter) {
47 | return abderaRequestContext.getParameters(parameter);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/config/resource/uri/URIConfigurationResourceTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.config.resource.uri;
2 |
3 | import org.atomhopper.util.uri.CustomSchemeResolver;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.experimental.runners.Enclosed;
7 | import org.junit.runner.RunWith;
8 |
9 | import java.io.InputStream;
10 | import java.net.URI;
11 |
12 | import static org.junit.Assert.assertNotNull;
13 | import static org.junit.Assert.assertTrue;
14 |
15 | @RunWith(Enclosed.class)
16 | public class URIConfigurationResourceTest {
17 |
18 | private static final String VALID_CLASSPATH_URI = "classpath:/META-INF/schema/config/bindings.xjb";
19 |
20 | public static class WhenGettingInputStreamsFromURILocations {
21 |
22 | private URIConfigurationResource configurationResource;
23 |
24 | @Before
25 | public void standUp() throws Exception {
26 | configurationResource = new URIConfigurationResource(
27 | new URI(VALID_CLASSPATH_URI),
28 | CustomSchemeResolver.newDefaultInstance());
29 | }
30 |
31 | @Test
32 | public void shouldGenerateInputStreamWithValidLocatableURIs() throws Exception {
33 | final InputStream result = configurationResource.getInputStream();
34 |
35 | assertNotNull("InputStream returned by the static classpath URI, \""
36 | + VALID_CLASSPATH_URI
37 | + "\" must not be null", result);
38 |
39 | assertTrue("InputStream should have at least one byte readable", result.read() > 0);
40 |
41 | result.close();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/test-suite/src/test/java/org/atomhopper/abdera/filter/SelectiveURIJSONFilterTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import org.apache.commons.httpclient.HttpClient;
4 | import org.apache.commons.httpclient.HttpMethod;
5 | import org.apache.commons.httpclient.methods.GetMethod;
6 | import org.atomhopper.JettyIntegrationTestHarness;
7 | import org.junit.Test;
8 | import org.junit.experimental.runners.Enclosed;
9 | import org.junit.runner.RunWith;
10 |
11 | import static junit.framework.Assert.assertEquals;
12 |
13 | /**
14 | * User: shin4590
15 | * Date: 7/3/14
16 | */
17 | @RunWith(Enclosed.class)
18 | public class SelectiveURIJSONFilterTest extends JettyIntegrationTestHarness {
19 |
20 | private static final HttpClient httpClient = new HttpClient();
21 | private static final String urlAndPort = "http://localhost:" + getPort();
22 |
23 | public static class WhenGettingFeedsWithFormatJsonWhereJsonIsAllowed {
24 |
25 | @Test
26 | public void shouldReturnOK() throws Exception {
27 | final HttpMethod getFeedMethod = new GetMethod(urlAndPort + "/namespace2/feed2/?format=json");
28 | httpClient.executeMethod(getFeedMethod);
29 | assertEquals("Response code: ", 200, getFeedMethod.getStatusCode());
30 | }
31 | }
32 |
33 | public static class WhenGettingFeedsWithFormatJsonWhereJsonIsNotAllowed {
34 |
35 | @Test
36 | public void shouldReturnOK() throws Exception {
37 | final HttpMethod getFeedMethod = new GetMethod(urlAndPort + "/namespace6/feed6/?format=json");
38 | httpClient.executeMethod(getFeedMethod);
39 | assertEquals("Response code: ", 400, getFeedMethod.getStatusCode());
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/jetty-killer/src/main/java/org/atomhopper/jettykiller/JettyKiller.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jettykiller;
2 |
3 |
4 |
5 |
6 | import org.kohsuke.args4j.CmdLineException;
7 | import org.kohsuke.args4j.CmdLineParser;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 |
12 | public class JettyKiller {
13 | private static final Logger LOG = LoggerFactory.getLogger(JettyKiller.class);
14 | private static final int MAX_PORT_NUMBER = 49150;
15 | private static final int MIN_PORT_NUMBER = 1024;
16 |
17 | private JettyKiller(){}
18 |
19 | public static void main(String[] args) {
20 | CommandLineArguments commandLineArgs = new CommandLineArguments();
21 | CmdLineParser cmdLineParser = new CmdLineParser(commandLineArgs);
22 | AtomHopperServerControl serverControl = new AtomHopperServerControl(commandLineArgs);
23 |
24 | try {
25 | cmdLineParser.parseArgument(args);
26 | } catch (CmdLineException e) {
27 | displayUsage(cmdLineParser, e);
28 | return;
29 | }
30 |
31 | if (!(portIsInRange(commandLineArgs.stopport))) {
32 | LOG.info("Invalid Atom Hopper port setting, use a value between 1 and 65535");
33 | return;
34 | }
35 |
36 | serverControl.stopAtomHopper();
37 | }
38 |
39 | private static void displayUsage(CmdLineParser cmdLineParser, Exception e) {
40 | System.err.println(e.getMessage());
41 | System.err.println("java -jar AtomHopperServer.jar [options...] arguments...");
42 | cmdLineParser.printUsage(System.err);
43 | }
44 |
45 | private static boolean portIsInRange(int portNum) {
46 | return (portNum <= MAX_PORT_NUMBER) && (portNum >= MIN_PORT_NUMBER);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/docker/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | export APP_CTX_PATH=/etc/atomhopper
3 | echo "using APP_CTX_PATH="$APP_CTX_PATH
4 |
5 | if [[ -e $APP_CTX_PATH/application-context.xml.orig ]]
6 | then
7 | echo "Replacing application-context.xml with original config."
8 | mv $APP_CTX_PATH/application-context.xml.orig $APP_CTX_PATH/application-context.xml
9 | fi
10 | echo "Database type selected:"$DB_TYPE
11 |
12 | #DB configuration
13 | if [[ $DB_TYPE != 'H2' ]] ; then
14 | #Comment default H2 Database and backup the original file
15 | sed -i.orig -e '/Start H2 Config/a ' $APP_CTX_PATH/application-context.xml
16 |
17 | #Enable databse based on the DB_TYPE value
18 | sed -i "/Start $DB_TYPE Config/{n;;d}" $APP_CTX_PATH/application-context.xml && sed -i "/Start $DB_TYPE Config/{n;n;n;n;n;n;;d}" $APP_CTX_PATH/application-context.xml
19 |
20 | #Remove databse username and password lines
21 | sed -i "/Start $DB_TYPE Config/{n;n;n;n;N;;d}" $APP_CTX_PATH/application-context.xml
22 |
23 | #Replace username and passowrd lines with env variable value
24 | sed -i -e "/End $DB_TYPE Config/i " -e "/End ${DB_TYPE} Config/i " $APP_CTX_PATH/application-context.xml
25 |
26 | #DB_HOST configuration
27 | if [ "$DB_TYPE" = 'MySQL' ] ; then
28 | sed -i -e "s/:mysql:\/\/localhost:8889/:mysql:\/\/$DB_HOST/g" $APP_CTX_PATH/application-context.xml
29 | fi
30 | if [ "$DB_TYPE" = 'PostgreSQL' ] ; then
31 | sed -i -e "s/:postgresql:\/\/localhost:5432/:postgresql:\/\/$DB_HOST/g" $APP_CTX_PATH/application-context.xml
32 | fi
33 | fi
34 |
35 | #Start tomcat server
36 | sh /opt/tomcat/bin/catalina.sh run
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/resources/ddl/jdbc/atomhopper-fresh-schema-ddl-postgres.sql:
--------------------------------------------------------------------------------
1 | -- This file can be used to create fresh AH DB schema.
2 | -- It is useful when we create new feeds.
3 | --
4 | -- This file needs to be kept up-to-date, everytime we change
5 | -- AH schema.
6 | --
7 | -- You will have to run this SQL as the schema user.
8 | -- For example, if you are adding a new feed called 'new_feed'
9 | -- you will have to run psql like this:
10 | -- psql -h localhost -U new_feed -d new_feed -f
11 | --
12 |
13 | SET statement_timeout = 0;
14 | SET client_encoding = 'UTF8';
15 | SET standard_conforming_strings = on;
16 | SET check_function_bodies = false;
17 | SET client_min_messages = warning;
18 |
19 | CREATE TABLE entries (
20 | id bigserial,
21 | entryid text NOT NULL UNIQUE,
22 | creationdate timestamp without time zone NOT NULL DEFAULT current_timestamp,
23 | datelastupdated timestamp without time zone NOT NULL DEFAULT current_timestamp,
24 | entrybody text,
25 | feed text,
26 | -- categories which are mapped to specific columns
27 | -- remove if you aren't configuring your FeedSource & FeedPublisher accordingly
28 | eventtype text,
29 | tenantid text,
30 | -- ---------------------
31 | categories character varying[],
32 | PRIMARY KEY(datelastupdated, id)
33 | );
34 | CREATE INDEX entryid_idx on entries(entryid);
35 | CREATE INDEX categories_idx on entries(categories);
36 | CREATE INDEX feed_idx on entries(feed);
37 | CREATE INDEX feed_entryid_idx on entries(feed, entryid);
38 |
39 | -- categories which are mapped to specific columns
40 | -- remove if you aren't configuring your FeedSource & FeedPublisher accordingly
41 | CREATE INDEX eventtype_idx on entries( eventtype );
42 | CREATE INDEX tenantid_idx on entries( tenantid );
43 | -- ---------------------
44 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/impl/DisabledFeedSource.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.apache.abdera.model.Feed;
5 | import org.atomhopper.adapter.FeedInformation;
6 | import org.atomhopper.adapter.FeedSource;
7 | import org.atomhopper.adapter.ResponseBuilder;
8 | import org.atomhopper.adapter.request.adapter.GetEntryRequest;
9 | import org.atomhopper.adapter.request.adapter.GetFeedRequest;
10 | import org.atomhopper.response.AdapterResponse;
11 |
12 | import java.net.URL;
13 |
14 | public final class DisabledFeedSource extends AbstractDisabledAdapter implements FeedSource {
15 |
16 | private static final DisabledFeedSource INSTANCE = new DisabledFeedSource();
17 | private static final String OP_NOT_SUPPORTED_MESSAGE = "Operation not supported";
18 |
19 | public static DisabledFeedSource getInstance() {
20 | return INSTANCE;
21 | }
22 |
23 | private DisabledFeedSource() {
24 | }
25 |
26 | @Override
27 | public FeedInformation getFeedInformation() {
28 | return DisabledFeedInformation.getInstance();
29 | }
30 |
31 | @Override
32 | public AdapterResponse getEntry(GetEntryRequest getEntryRequest) {
33 | return ResponseBuilder.notImplemented(OP_NOT_SUPPORTED_MESSAGE);
34 | }
35 |
36 | @Override
37 | public void setCurrentUrl( URL urlCurrent ) {
38 | // do nothing since this feed is disabled
39 | }
40 |
41 | @Override
42 | public void setArchiveUrl( URL url ) {
43 | // do nothing since this feed is disabled
44 | }
45 |
46 | @Override
47 | public AdapterResponse getFeed(GetFeedRequest getFeedRequest) {
48 | return ResponseBuilder.notImplemented(OP_NOT_SUPPORTED_MESSAGE);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tests/customjdbc-regression/src/test/jmeter/postgres-adaptor-override-on-application-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 |
33 |
34 | true
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/customjdbc-regression/src/test/jmeter/postgres-adaptor-override-off-application-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | false
32 |
33 |
34 | false
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/TargetRegexBuilderFeedTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util;
2 |
3 | import org.junit.Test;
4 | import org.junit.experimental.runners.Enclosed;
5 | import org.junit.runner.RunWith;
6 |
7 | import java.util.regex.Pattern;
8 |
9 | import static org.junit.Assert.assertTrue;
10 |
11 | /**
12 | *
13 | */
14 | @RunWith(Enclosed.class)
15 | public class TargetRegexBuilderFeedTest {
16 |
17 | public static class WhenBuildingFeedRegexes extends TargetRegexBuilderTestParent {
18 |
19 | @Test
20 | public void shouldMatchAllFeedVariations() {
21 | final TargetRegexBuilder target = feedRegexBuilder();
22 | final Pattern targetRegex = Pattern.compile(target.toFeedPattern());
23 |
24 | assertTrue("Should match plain feed URI - regex is: " + targetRegex.pattern(),
25 | targetRegex.matcher(FEED).matches());
26 | assertTrue("Should match plain feed URI with a slash - regex is: " + targetRegex.pattern(),
27 | targetRegex.matcher(addTrailingSlash(FEED)).matches());
28 | }
29 |
30 | @Test
31 | public void shouldMatchWithNonRootContextPath() {
32 | final TargetRegexBuilder target = feedRegexBuilder();
33 | target.setContextPath(CONTEXT_PATH);
34 |
35 | final Pattern targetRegex = Pattern.compile(target.toFeedPattern());
36 |
37 | assertTrue("Should match feed URI with a context root - regex is: " + targetRegex.pattern(),
38 | targetRegex.matcher(addContextRoot(FEED)).matches());
39 | }
40 |
41 | @Test(expected = IllegalStateException.class)
42 | public void shouldFailToBuildRegexWhenFeedIsNotSet() {
43 | new TargetRegexBuilder().toFeedPattern();
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/TargetRegexBuilderTestParent.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util;
2 |
3 | public class TargetRegexBuilderTestParent {
4 |
5 | public TargetRegexBuilder workspaceRegexBuilder() {
6 | final TargetRegexBuilder target = new TargetRegexBuilder();
7 | target.setWorkspace("workspace");
8 |
9 | return target;
10 | }
11 |
12 | public TargetRegexBuilder feedRegexBuilder() {
13 | final TargetRegexBuilder target = workspaceRegexBuilder();
14 | target.setFeed("feed");
15 |
16 | return target;
17 | }
18 |
19 |
20 | public static final String[] DEFAULT_CATEGORIES_SHORT = new String[]{"category_1", "category_2"},
21 | DEFAULT_CATEGORIES_LONG = new String[]{"category_a", "category_b", "category_c", "category_d", "category_e"};
22 | public static final String CONTEXT_PATH = "/approot",
23 | WORKSPACE = "/workspace",
24 | CATEGORIES = "/workspace/feed/categories",
25 | FEED = "/workspace/feed",
26 | ENTRY = "/workspace/feed/entries/tag:domain.com,2011-01-01:entry-id";
27 |
28 | public static String withCategories(String base, String[] categories) {
29 | final StringBuilder uri = new StringBuilder(base);
30 | uri.append("?categories=");
31 |
32 | if (categories.length >= 1) {
33 | uri.append(categories[0]);
34 |
35 | for (int i = 1; i < categories.length; i++) {
36 | uri.append(";").append(categories[i]);
37 | }
38 | }
39 |
40 | return uri.toString();
41 | }
42 |
43 | public static String addContextRoot(String base) {
44 | return CONTEXT_PATH + base;
45 | }
46 |
47 | public static String addTrailingSlash(String base) {
48 | return base + "/";
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/LogBackConfigLoader.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import ch.qos.logback.classic.LoggerContext;
10 | import ch.qos.logback.classic.joran.JoranConfigurator;
11 | import ch.qos.logback.core.joran.spi.JoranException;
12 |
13 | /**
14 | * Simple Utility class for loading an external config file for logback
15 | *
16 | * This code is modified from https://bowerstudios.com/node/896
17 | */
18 | public class LogBackConfigLoader {
19 |
20 | private Logger logger = LoggerFactory.getLogger(LogBackConfigLoader.class);
21 |
22 | public LogBackConfigLoader(String externalConfigFileLocation) throws IOException, JoranException {
23 | LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
24 |
25 | File externalConfigFile = new File(externalConfigFileLocation);
26 | if (!externalConfigFile.exists()) {
27 | throw new IOException("Logback External Config File Parameter does not reference a file that exists");
28 | } else if (!externalConfigFile.isFile()) {
29 | throw new IOException("Logback External Config File Parameter exists, but does not reference a file");
30 | } else if (!externalConfigFile.canRead()) {
31 | throw new IOException("Logback External Config File exists and is a file, but cannot be read.");
32 | } else {
33 | JoranConfigurator configurator = new JoranConfigurator();
34 | configurator.setContext(lc);
35 | lc.reset();
36 | configurator.doConfigure(externalConfigFileLocation);
37 |
38 | logger.info("Configured Logback with config file from: " + externalConfigFileLocation);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/server/src/main/java/org/atomhopper/server/MonitorThread.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.server;
2 |
3 |
4 | import org.eclipse.jetty.server.Server;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.InputStreamReader;
10 | import java.net.InetAddress;
11 | import java.net.ServerSocket;
12 | import java.net.Socket;
13 |
14 |
15 | public class MonitorThread extends Thread {
16 | private static final Logger LOG = LoggerFactory.getLogger(AtomHopperServer.class);
17 |
18 | private ServerSocket socket;
19 | private final Server serverInstance;
20 | private static final String MONITOR_NAME = "StopMonitor";
21 |
22 | public MonitorThread(Server serverInstance, final int stopPort, final String ipAddress) {
23 | this.serverInstance = serverInstance;
24 |
25 | setDaemon(true);
26 | setName(MONITOR_NAME);
27 |
28 | try {
29 | socket = new ServerSocket(stopPort, 1, InetAddress.getByName(ipAddress));
30 | } catch (Exception e) {
31 | LOG.error("Fatal error while monitoring or trying to stop: " + e.getMessage(), e);
32 | }
33 | }
34 |
35 | @Override
36 | public void run() {
37 | Socket accept;
38 |
39 | try {
40 | accept = socket.accept();
41 | BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
42 | reader.readLine();
43 | LOG.info("Stopping Atom Hopper...");
44 | serverInstance.stop();
45 | LOG.info("Atom Hopper has been stopped");
46 | accept.close();
47 | socket.close();
48 | } catch (Exception e) {
49 | LOG.error("Fatal error while monitoring or trying to stop: " + e.getMessage(), e);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/test/java/org/atomhopper/jdbc/adapter/JdbcFeedInformationTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jdbc.adapter;
2 |
3 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 |
6 | import org.junit.Before;
7 | import org.junit.Test;
8 | import org.junit.experimental.runners.Enclosed;
9 | import org.junit.runner.RunWith;
10 | import org.springframework.jdbc.core.JdbcTemplate;
11 |
12 | import static org.junit.Assert.assertNotNull;
13 | import static org.mockito.Mockito.mock;
14 |
15 | @RunWith(Enclosed.class)
16 | public class JdbcFeedInformationTest {
17 |
18 | public static class WhenGettingPostgresFeedInformation {
19 |
20 | private JdbcTemplate jbdcTemplate;
21 | private FeedRequest feedRequest;
22 | private GetCategoriesRequest getCategoriesRequest;
23 | private JdbcFeedInformation postgresFeedInformation;
24 |
25 | @Before
26 | public void setUp() throws Exception {
27 | jbdcTemplate = mock(JdbcTemplate.class);
28 | feedRequest = mock(FeedRequest.class);
29 | getCategoriesRequest = mock(GetCategoriesRequest.class);
30 |
31 | postgresFeedInformation = new JdbcFeedInformation();
32 | }
33 |
34 | @Test
35 | public void shouldCreatePostgresFeedInformation() throws Exception {
36 | assertNotNull(postgresFeedInformation);
37 | }
38 |
39 | @Test(expected=UnsupportedOperationException.class)
40 | public void shouldReturnId() throws Exception {
41 | postgresFeedInformation.getId(feedRequest);
42 | }
43 |
44 | @Test(expected=UnsupportedOperationException.class)
45 | public void shouldReturnCategories() throws Exception {
46 | postgresFeedInformation.getCategories(getCategoriesRequest);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/TargetRegexBuilderWorkspaceTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util;
2 |
3 | import org.junit.Test;
4 | import org.junit.experimental.runners.Enclosed;
5 | import org.junit.runner.RunWith;
6 |
7 | import java.util.regex.Pattern;
8 |
9 | import static org.junit.Assert.assertTrue;
10 |
11 | /**
12 | *
13 | */
14 | @RunWith(Enclosed.class)
15 | public class TargetRegexBuilderWorkspaceTest {
16 |
17 | public static class WhenBuildingWorkspaceRegexes extends TargetRegexBuilderTestParent {
18 |
19 | @Test
20 | public void shouldMatchAllWorkspaceVariations() {
21 | final TargetRegexBuilder target = workspaceRegexBuilder();
22 | final Pattern targetRegex = Pattern.compile(target.toWorkspacePattern());
23 |
24 | assertTrue("Should match plain workspace URI - regex is: " + targetRegex.pattern(),
25 | targetRegex.matcher(WORKSPACE).matches());
26 | assertTrue("Should match plain workspace URI with a slash - regex is: " + targetRegex.pattern(),
27 | targetRegex.matcher(addTrailingSlash(WORKSPACE)).matches());
28 | }
29 |
30 | @Test
31 | public void shouldMatchWithNonRootContextPath() {
32 | final TargetRegexBuilder target = workspaceRegexBuilder();
33 | target.setContextPath(CONTEXT_PATH);
34 |
35 | final Pattern targetRegex = Pattern.compile(target.toWorkspacePattern());
36 |
37 | assertTrue("Should match workspace URI with a context root - regex is: " + targetRegex.pattern(),
38 | targetRegex.matcher(addContextRoot(WORKSPACE)).matches());
39 | }
40 |
41 | @Test(expected = IllegalStateException.class)
42 | public void shouldFailToBuildRegexWhenWorkspaceIsNotSet() {
43 | new TargetRegexBuilder().toWorkspacePattern();
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/adapters/migration/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.atomhopper
7 | parent
8 | 1.2.35-SNAPSHOT
9 | ./../../pom.xml
10 |
11 |
12 | org.atomhopper.adapter
13 | migration-adapter
14 | jar
15 |
16 | ATOM Hopper - Migration Adapter
17 |
18 |
19 |
20 | org.atomhopper
21 | core
22 |
23 |
24 |
25 | org.javassist
26 | javassist
27 |
28 |
29 |
30 | org.apache.abdera
31 | abdera-core
32 |
33 |
34 |
35 | org.slf4j
36 | slf4j-api
37 |
38 |
39 |
40 | org.springframework.data
41 | spring-data-mongodb
42 |
43 |
44 |
45 | org.mockito
46 | mockito-all
47 |
48 |
49 |
50 | junit
51 | junit
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/test/java/org/atomhopper/hibernate/adapter/HibernateFeedPublisherTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.hibernate.adapter;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import org.atomhopper.adapter.request.adapter.DeleteEntryRequest;
6 | import org.atomhopper.adapter.request.adapter.PutEntryRequest;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.experimental.runners.Enclosed;
10 | import org.junit.runner.RunWith;
11 | import static org.mockito.Mockito.mock;
12 |
13 |
14 | @RunWith(Enclosed.class)
15 | public class HibernateFeedPublisherTest {
16 |
17 | public static class WhenCallingNonImplementedFunctionality {
18 |
19 | private HibernateFeedPublisher hibernateFeedPublisher;
20 | private PutEntryRequest putEntryRequest;
21 | private DeleteEntryRequest deleteEntryRequest;
22 |
23 | @Before
24 | public void setUp() throws Exception {
25 | putEntryRequest = mock(PutEntryRequest.class);
26 | deleteEntryRequest = mock(DeleteEntryRequest.class);
27 |
28 | hibernateFeedPublisher = new HibernateFeedPublisher();
29 | }
30 |
31 | @Test(expected=UnsupportedOperationException.class)
32 | public void shouldPutEntry() throws Exception {
33 | hibernateFeedPublisher.putEntry(putEntryRequest);
34 | }
35 |
36 | @Test(expected=UnsupportedOperationException.class)
37 | public void shouldDeleteEntry() throws Exception {
38 | hibernateFeedPublisher.deleteEntry(deleteEntryRequest);
39 | }
40 |
41 | @Test(expected = UnsupportedOperationException.class)
42 | public void shouldSetParameters() throws Exception {
43 | Map map = new HashMap();
44 | map.put("test1", "test2");
45 | hibernateFeedPublisher.setParameters(map);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/adapters/mongodb/src/test/java/org/atomhopper/mongodb/adapter/MongodbFeedInformationTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.mongodb.adapter;
2 |
3 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 | import org.springframework.data.mongodb.core.MongoTemplate;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.experimental.runners.Enclosed;
10 | import org.junit.runner.RunWith;
11 |
12 | import static org.junit.Assert.assertNotNull;
13 | import static org.mockito.Mockito.mock;
14 |
15 |
16 | @RunWith(Enclosed.class)
17 | public class MongodbFeedInformationTest {
18 |
19 | public static class WhenGettingMongodbFeedInformation {
20 |
21 | private MongoTemplate mongoTemplate;
22 | private FeedRequest feedRequest;
23 | private GetCategoriesRequest getCategoriesRequest;
24 | private MongodbFeedInformation mongodbFeedInformation;
25 |
26 | @Before
27 | public void setUp() throws Exception {
28 | mongoTemplate = mock(MongoTemplate.class);
29 | feedRequest = mock(FeedRequest.class);
30 | getCategoriesRequest = mock(GetCategoriesRequest.class);
31 |
32 | mongodbFeedInformation = new MongodbFeedInformation();
33 | }
34 |
35 | @Test
36 | public void shouldCreateHibernateFeedInformation() throws Exception {
37 | assertNotNull(mongodbFeedInformation);
38 | }
39 |
40 | @Test(expected=UnsupportedOperationException.class)
41 | public void shouldReturnId() throws Exception {
42 | mongodbFeedInformation.getId(feedRequest);
43 | }
44 |
45 | @Test(expected=UnsupportedOperationException.class)
46 | public void shouldReturnCategories() throws Exception {
47 | mongodbFeedInformation.getCategories(getCategoriesRequest);
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/test/java/org/atomhopper/postgres/adapter/PostgresFeedInformationTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.adapter;
2 |
3 | import org.atomhopper.adapter.request.adapter.GetCategoriesRequest;
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 |
6 | import org.junit.Before;
7 | import org.junit.Test;
8 | import org.junit.experimental.runners.Enclosed;
9 | import org.junit.runner.RunWith;
10 | import org.springframework.jdbc.core.JdbcTemplate;
11 |
12 | import static org.junit.Assert.assertNotNull;
13 | import static org.mockito.Mockito.mock;
14 |
15 | @RunWith(Enclosed.class)
16 | public class PostgresFeedInformationTest {
17 |
18 | public static class WhenGettingPostgresFeedInformation {
19 |
20 | private JdbcTemplate jbdcTemplate;
21 | private FeedRequest feedRequest;
22 | private GetCategoriesRequest getCategoriesRequest;
23 | private PostgresFeedInformation postgresFeedInformation;
24 |
25 | @Before
26 | public void setUp() throws Exception {
27 | jbdcTemplate = mock(JdbcTemplate.class);
28 | feedRequest = mock(FeedRequest.class);
29 | getCategoriesRequest = mock(GetCategoriesRequest.class);
30 |
31 | postgresFeedInformation = new PostgresFeedInformation();
32 | }
33 |
34 | @Test
35 | public void shouldCreatePostgresFeedInformation() throws Exception {
36 | assertNotNull(postgresFeedInformation);
37 | }
38 |
39 | @Test(expected=UnsupportedOperationException.class)
40 | public void shouldReturnId() throws Exception {
41 | postgresFeedInformation.getId(feedRequest);
42 | }
43 |
44 | @Test(expected=UnsupportedOperationException.class)
45 | public void shouldReturnCategories() throws Exception {
46 | postgresFeedInformation.getCategories(getCategoriesRequest);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/FeedPublisher.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.atomhopper.adapter.request.adapter.DeleteEntryRequest;
5 | import org.atomhopper.adapter.request.adapter.PostEntryRequest;
6 | import org.atomhopper.adapter.request.adapter.PutEntryRequest;
7 | import org.atomhopper.response.AdapterResponse;
8 | import org.atomhopper.response.EmptyBody;
9 |
10 | /**
11 | * A feed publisher, as defined by this interface, is responsible for committing
12 | * client change requests to the feed it represents.
13 | *
14 | * Note: this interface is required for ATOMpub functionality
15 | */
16 | public interface FeedPublisher extends AtomHopperAdapter {
17 |
18 | /**
19 | * Requests a single entry be added to the feed.
20 | *
21 | * @param postEntryRequest
22 | * @see PostEntryRequest
23 | *
24 | * @return
25 | * The returned entry should contain all of the information a client would
26 | * need to then request the newly added entry. This should include linking
27 | * and identifying the new entry in the response
28 | */
29 | AdapterResponse postEntry(PostEntryRequest postEntryRequest);
30 |
31 | /**
32 | * Requests that an entry be updated. This request is scoped by the unique
33 | * string ID of the entry the update is being requested for.
34 | *
35 | * @param putEntryRequest
36 | * @see PutEntryRequest
37 | *
38 | * @return
39 | */
40 | AdapterResponse putEntry(PutEntryRequest putEntryRequest);
41 |
42 | /**
43 | * Requests that an entry be deleted. This request is scoped by the unique
44 | * string ID of the entry the delete is being requested for.
45 | *
46 | * @param deleteEntryRequest
47 | * @see DeleteEntryRequest
48 | *
49 | * @return
50 | */
51 | AdapterResponse deleteEntry(DeleteEntryRequest deleteEntryRequest);
52 | }
53 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/config/SchemaTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.config;
2 |
3 | import org.atomhopper.config.v1_0.Configuration;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.experimental.runners.Enclosed;
7 | import org.junit.runner.RunWith;
8 |
9 | import javax.xml.XMLConstants;
10 | import javax.xml.bind.JAXBContext;
11 | import javax.xml.bind.Unmarshaller;
12 | import javax.xml.transform.stream.StreamSource;
13 | import javax.xml.validation.SchemaFactory;
14 |
15 | import static org.junit.Assert.assertFalse;
16 |
17 | /**
18 | *
19 | */
20 | @RunWith(Enclosed.class)
21 | public class SchemaTest {
22 |
23 | private static final SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
24 |
25 | public static class WhenValidating {
26 |
27 | private JAXBContext jaxbContext;
28 | private Unmarshaller jaxbUnmarshaller;
29 |
30 | @Before
31 | public void standUp() throws Exception {
32 | jaxbContext = JAXBContext.newInstance(
33 | org.atomhopper.config.v1_0.ObjectFactory.class);
34 |
35 | jaxbUnmarshaller = jaxbContext.createUnmarshaller();
36 |
37 | jaxbUnmarshaller.setSchema(SCHEMA_FACTORY.newSchema(
38 | new StreamSource[]{
39 | new StreamSource(SchemaTest.class.getResourceAsStream("/META-INF/schema/config/atom-hopper-config.xsd"))
40 | }));
41 | }
42 |
43 | @Test
44 | public void staticExampleShouldMatchSchema() throws Exception {
45 | final Configuration cfg = jaxbUnmarshaller.unmarshal(
46 | new StreamSource(SchemaTest.class.getResourceAsStream("/META-INF/schema/examples/config/feed-server-config.xml")), Configuration.class).getValue();
47 |
48 | assertFalse("Configured workspace list should have at least one element", cfg.getWorkspace().isEmpty());
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/util/TargetRegexBuilderTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util;
2 |
3 | import static org.junit.Assert.assertTrue;
4 | import org.junit.Test;
5 | import org.junit.experimental.runners.Enclosed;
6 | import org.junit.runner.RunWith;
7 |
8 | import static org.junit.Assert.assertEquals;
9 |
10 | /**
11 | *
12 | */
13 | @RunWith(Enclosed.class)
14 | public class TargetRegexBuilderTest {
15 |
16 | public static class WhenCopyingTargetRegexBuilders extends TargetRegexBuilderTestParent {
17 |
18 | @Test
19 | public void shouldCopyBuilderElements() {
20 | final TargetRegexBuilder expected = feedRegexBuilder();
21 | final TargetRegexBuilder actual = new TargetRegexBuilder(expected);
22 |
23 | assertEquals("TargetRegexBuilder copy must populate the context path", expected.getContextPath(), actual.getContextPath());
24 | assertEquals("TargetRegexBuilder copy must populate the workspace path", expected.getWorkspaceResource(), actual.getWorkspaceResource());
25 | assertEquals("TargetRegexBuilder copy must populate the feed path", expected.getFeedResource(), actual.getFeedResource());
26 | }
27 | }
28 |
29 | public static class WhenResourceAttributeHasBackslashesInRegex {
30 |
31 | private TargetRegexBuilder targetRegexBuilder;
32 |
33 | @Test
34 | public void shouldRetainTheBackslashInRegex() {
35 | String workspaceResource = "usagetest\\d{1,2}";
36 | String feedResource = "events";
37 | String contextPath = "";
38 |
39 | targetRegexBuilder = new TargetRegexBuilder();
40 | targetRegexBuilder.setContextPath(contextPath);
41 | targetRegexBuilder.setWorkspace(workspaceResource);
42 | targetRegexBuilder.setFeed(feedResource);
43 |
44 | assertTrue("should retain the backslash in the workspace resource regex",targetRegexBuilder.toEntryPattern().contains(workspaceResource));
45 |
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/adapters/hibernate/src/main/resources/ddl/postgres/atomhopper-database-schema-ddl-postgres.sql:
--------------------------------------------------------------------------------
1 | SET statement_timeout = 0;
2 | SET client_encoding = 'UTF8';
3 | SET standard_conforming_strings = on;
4 | SET check_function_bodies = false;
5 | SET client_min_messages = warning;
6 |
7 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
8 |
9 | COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
10 |
11 | SET search_path = public, pg_catalog;
12 | SET default_tablespace = '';
13 | SET default_with_oids = false;
14 |
15 | CREATE TABLE feeds (
16 | name character varying(255) CONSTRAINT feeds_pkey PRIMARY KEY,
17 | feedid character varying(255)
18 | );
19 | ALTER TABLE public.feeds OWNER TO atomschema;
20 |
21 | CREATE TABLE entries (
22 | entryid character varying(255) CONSTRAINT entries_pkey PRIMARY KEY,
23 | creationdate timestamp without time zone NOT NULL,
24 | datelastupdated timestamp without time zone NOT NULL,
25 | entrybody text,
26 | feed character varying(255),
27 | CONSTRAINT fk_feed_feeds_name FOREIGN KEY (feed) REFERENCES feeds(name) ON DELETE CASCADE
28 | );
29 | ALTER TABLE public.entries OWNER TO atomschema;
30 | CREATE INDEX datelastupdated_idx on entries(datelastupdated);
31 |
32 | CREATE TABLE categories (
33 | term character varying(255) CONSTRAINT categories_pkey PRIMARY KEY
34 | );
35 | ALTER TABLE public.categories OWNER TO atomschema;
36 |
37 | CREATE TABLE categoryentryreferences (
38 | entryid character varying(255) CONSTRAINT fk_entryid_entries_entryid REFERENCES entries(entryid) ON DELETE CASCADE,
39 | category character varying(255) CONSTRAINT fk_category_categories_term REFERENCES categories(term) ON DELETE CASCADE,
40 | CONSTRAINT categoryentryreferences_pkey PRIMARY KEY (entryid, category)
41 | );
42 | ALTER TABLE public.categoryentryreferences OWNER TO atomschema;
43 |
44 | REVOKE ALL ON SCHEMA public FROM PUBLIC;
45 | REVOKE ALL ON SCHEMA public FROM postgres;
46 | GRANT ALL ON SCHEMA public TO postgres;
47 | GRANT ALL ON SCHEMA public TO PUBLIC;
48 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/jpa/PersistedCategory.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.jpa;
2 |
3 | import javax.persistence.Column;
4 | import javax.persistence.Entity;
5 | import javax.persistence.FetchType;
6 | import javax.persistence.Id;
7 | import javax.persistence.ManyToMany;
8 | import javax.persistence.Table;
9 | import java.io.Serializable;
10 | import java.util.Collections;
11 | import java.util.HashSet;
12 | import java.util.Set;
13 |
14 | @Entity
15 | @Table(name = "Categories")
16 | public class PersistedCategory implements Serializable {
17 |
18 | @Id
19 | @Column(name = "Term")
20 | private String term;
21 |
22 | @ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
23 | private Set feedEntries;
24 |
25 | public PersistedCategory() {
26 | feedEntries = Collections.EMPTY_SET;
27 | }
28 |
29 | public PersistedCategory(String term) {
30 | feedEntries = new HashSet();
31 |
32 | this.term = term;
33 | }
34 |
35 | public Set getFeedEntries() {
36 | return feedEntries;
37 | }
38 |
39 | public void setFeedEntries(Set feedEntries) {
40 | this.feedEntries = feedEntries;
41 | }
42 |
43 | public String getTerm() {
44 | return term;
45 | }
46 |
47 | public void setTerm(String term) {
48 | this.term = term;
49 | }
50 |
51 | @Override
52 | public boolean equals(Object obj) {
53 | if (obj == null) {
54 | return false;
55 | }
56 | if (getClass() != obj.getClass()) {
57 | return false;
58 | }
59 | final PersistedCategory other = (PersistedCategory) obj;
60 | return !((this.term == null) ? (other.term != null) : !this.term.equals(other.term));
61 | }
62 |
63 | @Override
64 | public int hashCode() {
65 | int hash = 3;
66 | hash = 53 * hash + (this.term != null ? this.term.hashCode() : 0);
67 | return hash;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/request/adapter/impl/GetFeedRequestImpl.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.request.adapter.impl;
2 |
3 | import org.apache.abdera.model.Feed;
4 | import org.apache.abdera.protocol.server.RequestContext;
5 | import org.atomhopper.adapter.request.RequestQueryParameter;
6 | import org.atomhopper.adapter.request.adapter.GetFeedRequest;
7 | import org.atomhopper.adapter.request.feed.AbstractFeedRequest;
8 | import org.h2.util.StringUtils;
9 |
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class GetFeedRequestImpl extends AbstractFeedRequest implements GetFeedRequest {
14 |
15 | public GetFeedRequestImpl(RequestContext abderaRequestContext) {
16 | super(abderaRequestContext);
17 | }
18 |
19 | @Override
20 | public List getCategories() {
21 | final List categoryList = getRequestParameters(RequestQueryParameter.CATEGORIES.toString());
22 |
23 | return Collections.unmodifiableList(categoryList != null ? categoryList : Collections.EMPTY_LIST);
24 | }
25 |
26 | @Override
27 | public String getSearchQuery() {
28 | return getRequestParameter(RequestQueryParameter.SEARCH.toString());
29 | }
30 |
31 | @Override
32 | public String getPageSize() {
33 | return getRequestParameter(RequestQueryParameter.PAGE_LIMIT.toString());
34 | }
35 |
36 | @Override
37 | public String getPageMarker() {
38 | return getRequestParameter(RequestQueryParameter.MARKER.toString());
39 | }
40 |
41 | @Override
42 | public Feed newFeed() {
43 | return getAbdera().newFeed();
44 | }
45 |
46 | public String getDirection() {
47 | final String direction = this.getRequestParameter(RequestQueryParameter.PAGE_DIRECTION.toString());
48 | return !StringUtils.isNullOrEmpty(direction) ? direction : "forward";
49 | }
50 |
51 | public String getStartingAt() {
52 | return this.getRequestParameter(RequestQueryParameter.STARTING_AT.toString());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/adapter/FeedSource.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.apache.abdera.model.Feed;
5 | import org.atomhopper.adapter.request.adapter.GetEntryRequest;
6 | import org.atomhopper.adapter.request.adapter.GetFeedRequest;
7 | import org.atomhopper.response.AdapterResponse;
8 |
9 | import java.net.URL;
10 |
11 | /**
12 | * A feed source, as defined by this interface, is responsible for retrieving the
13 | * feed and its associated entry data.
14 | *
15 | */
16 | public interface FeedSource extends AtomHopperAdapter {
17 |
18 | public static final String REL_ARCHIVE_NEXT = "next-archive";
19 | public static final String REL_ARCHIVE_PREV = "prev-archive";
20 |
21 | FeedInformation getFeedInformation();
22 |
23 | /**
24 | * Requests a single feed from the adapter. This request did not contain
25 | * paging information and the adapter may assume that the requester is
26 | * requesting the head of the feed.
27 | *
28 | * @param request
29 | * @see GetEntryRequest
30 | *
31 | * @return
32 | */
33 | AdapterResponse getFeed(GetFeedRequest getFeedRequest);
34 |
35 | /**
36 | * Requests a single entry from the adapter.
37 | *
38 | * @param request
39 | * @see GetEntryRequest
40 | *
41 | * @return
42 | */
43 | AdapterResponse getEntry(GetEntryRequest getEntryRequest);
44 |
45 | /**
46 | * Declares this feed as an archive feed as well as sets the current url for the archive feed.
47 | * An archive feed must have a link to the current feed which its the archive for.
48 | *
49 | * @param urlCurrent The URL to the current feed for this archive. This will be displayed
50 | * in the "current" link
51 | */
52 | public void setCurrentUrl( URL urlCurrent );
53 |
54 | /**
55 | * If an atom feed has a corresponding archive,
56 | *
57 | * @param url
58 | */
59 | public void setArchiveUrl( URL url );
60 | }
61 |
--------------------------------------------------------------------------------
/adapters/mongodb/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.atomhopper
7 | parent
8 | 1.2.35-SNAPSHOT
9 | ./../../pom.xml
10 |
11 |
12 | org.atomhopper.adapter
13 | mongodb-adapter
14 | jar
15 |
16 | ATOM Hopper - MongoDB Adapter
17 |
18 |
19 |
20 | org.atomhopper
21 | core
22 |
23 |
24 |
25 | org.javassist
26 | javassist
27 |
28 |
29 |
30 | org.apache.abdera
31 | abdera-core
32 |
33 |
34 |
35 | org.slf4j
36 | slf4j-api
37 |
38 |
39 |
40 | org.springframework.data
41 | spring-data-mongodb
42 |
43 |
44 |
45 | org.mockito
46 | mockito-all
47 |
48 |
49 |
50 | junit
51 | junit
52 |
53 |
54 |
55 | com.yammer.metrics
56 | metrics-core
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/server/src/main/java/org/atomhopper/server/AtomHopperServer.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.server;
2 |
3 |
4 | import org.kohsuke.args4j.CmdLineException;
5 | import org.kohsuke.args4j.CmdLineParser;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 |
10 | public class AtomHopperServer {
11 | private static final Logger LOG = LoggerFactory.getLogger(AtomHopperServer.class);
12 | private static final int MAX_PORT_NUMBER = 49150;
13 | private static final int MIN_PORT_NUMBER = 1024;
14 |
15 | private AtomHopperServer(){}
16 |
17 | public static void main(String[] args) {
18 | CommandLineArguments commandLineArgs = new CommandLineArguments();
19 | CmdLineParser cmdLineParser = new CmdLineParser(commandLineArgs);
20 | AtomHopperServerControl serverControl = new AtomHopperServerControl(commandLineArgs);
21 |
22 | try {
23 | cmdLineParser.parseArgument(args);
24 |
25 | } catch (CmdLineException e) {
26 | displayUsage(cmdLineParser, e);
27 | return;
28 | }
29 |
30 | if ((!(portIsInRange(commandLineArgs.port))) || (!(portIsInRange(commandLineArgs.stopport)))) {
31 | LOG.info("Invalid Atom Hopper port setting, use a value between 1024 and 49150");
32 | return;
33 | }
34 |
35 | if (commandLineArgs.action.equalsIgnoreCase(CommandLineArguments.ACTION_START)) {
36 | serverControl.startAtomHopper();
37 | }
38 |
39 | if (commandLineArgs.action.equalsIgnoreCase(CommandLineArguments.ACTION_STOP)) {
40 | serverControl.stopAtomHopper();
41 | }
42 | }
43 |
44 | private static void displayUsage(CmdLineParser cmdLineParser, Exception e) {
45 | System.err.println(e.getMessage());
46 | System.err.println("java -jar AtomHopperServer.jar [options...] arguments...");
47 | cmdLineParser.printUsage(System.err);
48 | }
49 |
50 | private static boolean portIsInRange(int portNum) {
51 | return (portNum <= MAX_PORT_NUMBER) && (portNum >= MIN_PORT_NUMBER);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/response/FeedSourceAdapterResponse.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.response;
2 |
3 | import org.apache.abdera.util.EntityTag;
4 | import org.springframework.http.HttpStatus;
5 |
6 | import java.util.EnumMap;
7 | import java.util.Map;
8 |
9 | public class FeedSourceAdapterResponse implements AdapterResponse {
10 |
11 | private static final HttpStatus DEFAULT_HTTP_STATUS_CODE = HttpStatus.OK;
12 |
13 | private final T responseBody;
14 | private final HttpStatus statusCode;
15 | private final String message;
16 | private final Map parameters;
17 |
18 | private EntityTag etag;
19 |
20 | public FeedSourceAdapterResponse(T responseBody) {
21 | this(responseBody, DEFAULT_HTTP_STATUS_CODE, "");
22 | }
23 |
24 | public FeedSourceAdapterResponse(T responseBody, HttpStatus statusCode, String message) {
25 | this.responseBody = responseBody;
26 | this.statusCode = statusCode;
27 | this.message = message;
28 |
29 | parameters = new EnumMap(ResponseParameter.class);
30 | }
31 |
32 | public Map getParameters() {
33 | return parameters;
34 | }
35 |
36 | @Override
37 | public String getParameter(ResponseParameter key) {
38 | return getParameters().get(key);
39 | }
40 |
41 | @Override
42 | public AdapterResponse withParameter(ResponseParameter key, Object value) {
43 | getParameters().put(key, value.toString());
44 |
45 | return this;
46 | }
47 |
48 | @Override
49 | public T getBody() {
50 | return responseBody;
51 | }
52 |
53 | @Override
54 | public String getMessage() {
55 | return message;
56 | }
57 |
58 | @Override
59 | public HttpStatus getResponseStatus() {
60 | return statusCode;
61 | }
62 |
63 | @Override
64 | public EntityTag getEntityTag() {
65 | return etag;
66 | }
67 |
68 | @Override
69 | public void setEntityTag(EntityTag etag) {
70 | this.etag = etag;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/adapters/postgres-adapter/src/main/java/org/atomhopper/postgres/model/PersistedEntry.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.postgres.model;
2 |
3 | import java.util.Arrays;
4 | import java.util.Calendar;
5 | import java.util.Date;
6 | import java.util.TimeZone;
7 |
8 |
9 | public class PersistedEntry {
10 |
11 | private String entryId;
12 | private String feed;
13 | private String entryBody;
14 | private Date creationDate;
15 | private Date dateLastUpdated;
16 | private String[] categories;
17 |
18 | public PersistedEntry() {
19 | final Calendar localNow = Calendar.getInstance(TimeZone.getDefault());
20 | localNow.setTimeInMillis(System.currentTimeMillis());
21 |
22 | creationDate = localNow.getTime();
23 | dateLastUpdated = localNow.getTime();
24 | }
25 |
26 | public String getEntryId() {
27 | return entryId;
28 | }
29 |
30 | public void setEntryId(String entryId) {
31 | this.entryId = entryId;
32 | }
33 |
34 | public String getFeed() {
35 | return feed;
36 | }
37 |
38 | public void setFeed(String feed) {
39 | this.feed = feed;
40 | }
41 |
42 | public String getEntryBody() {
43 | return entryBody;
44 | }
45 |
46 | public void setEntryBody(String entryBody) {
47 | this.entryBody = entryBody;
48 | }
49 |
50 | public Date getCreationDate() {
51 | return (Date) creationDate.clone();
52 | }
53 |
54 | public void setCreationDate(Date creationDate) {
55 | this.creationDate = (Date) creationDate.clone();
56 | }
57 |
58 | public Date getDateLastUpdated() {
59 | return (Date) dateLastUpdated.clone();
60 | }
61 |
62 | public void setDateLastUpdated(Date dateLastUpdated) {
63 | this.dateLastUpdated = (Date) dateLastUpdated.clone();
64 | }
65 |
66 | public String[] getCategories() {
67 | return categories.clone();
68 | }
69 |
70 | public void setCategories(String[] categories) {
71 | if (categories != null) {
72 | this.categories = Arrays.copyOf(categories, categories.length);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/documentation/devops.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Atom Hopper",
3 | "description": "An open source ATOMPub server",
4 | "tags": [
5 | "java",
6 | "ATOM",
7 | "open source",
8 | "hibernate",
9 | "MongoDB",
10 | "Abdera"
11 | ],
12 | "contacts": [
13 | {
14 | "team_name": "CLoud Integration",
15 | "members": [
16 | {
17 | "name": "Theresa Huth",
18 | "sso":"theresa.huth",
19 | "github": "https://github.com/theresaHuth",
20 | "mailto": "theresa.huth@rackspace.com"
21 | },
22 | {
23 | "name": "Chad Lung",
24 | "sso":"chad.lung",
25 | "github": "https://github.com/chadlung",
26 | "mailto": "chad.lung@rackspace.com"
27 | },
28 | {
29 | "name": "Seth Brayman",
30 | "sso":"seth.brayman",
31 | "github": "https://github.com/sethbrayman",
32 | "mailto": "seth.brayman@rackspace.com"
33 | },
34 | {
35 | "name": "Richard Sartor",
36 | "sso":"richard.sartor",
37 | "github": "https://github.com/rich4632",
38 | "mailto": "richard.sartor@rackspace.com"
39 | }
40 | ]
41 | }
42 | ],
43 | "links": {
44 | "Blog":"http://atomhopper.org",
45 | "Email List": "atomhopper@lists.rackspace.com",
46 | "Code": "https://github.com/rackspace/atom-hopper",
47 | "Wiki":"https://github.com/rackspace/atom-hopper/wiki",
48 | "Twitter": "https://twitter.com/#!/atomhopper",
49 | "Implementation Plan":"https://red.rackspace.com:8443/display/misc/Atom+Hopper+Implementation+Plan"
50 | },
51 | "dependent_services": [
52 | "Nova (Cloud Servers)",
53 | "Glance",
54 | "Quantum",
55 | "Melange",
56 | "MaaS",
57 | "DBaaS",
58 | "LBaaS",
59 | "Legacy Cloud Servers",
60 | "Cloud Files",
61 | "Cloud Block Storage",
62 | "Usage Service Layer",
63 | "Data Warehouse",
64 | "Runbook Automation (RBA) / Managed Cloud",
65 | "Rack Connect",
66 | "Identity/Auth"
67 | ]
68 | }
69 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/AtomHopperVersionServlet.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper;
2 |
3 | import com.google.gson.Gson;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import javax.servlet.ServletException;
8 | import javax.servlet.http.HttpServlet;
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.PrintWriter;
14 | import java.util.Properties;
15 |
16 |
17 | public class AtomHopperVersionServlet extends HttpServlet {
18 |
19 | private static final Logger LOG = LoggerFactory.getLogger(AtomHopperVersionServlet.class);
20 | private static final String POM_PROPERTIES_LOCATION = "META-INF/maven/org.atomhopper/atomhopper/pom.properties";
21 |
22 | private Properties loadProperties() {
23 | Properties properties = new Properties();
24 | try {
25 | InputStream inStream = getServletContext().getResourceAsStream(POM_PROPERTIES_LOCATION);
26 | properties.load(inStream);
27 | inStream.close();
28 | } catch (Exception e){
29 | LOG.error("Unable to load pom.properties", e);
30 | }
31 | return properties;
32 | }
33 |
34 | private Properties getProperties(){
35 | return loadProperties();
36 | }
37 |
38 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
39 | throws ServletException, IOException {
40 | response.setContentType("application/json");
41 | PrintWriter out = response.getWriter();
42 | try {
43 | out.println(new Gson().toJson(getProperties()));
44 | } finally {
45 | out.close();
46 | }
47 | }
48 |
49 | @Override
50 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
51 | throws ServletException, IOException {
52 | processRequest(request, response);
53 | }
54 |
55 | @Override
56 | public String getServletInfo() {
57 | return "Returns the current Atom Hopper pom.properties in JSON format";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/test-suite/src/main/java/org/atomhopper/jetty/AtomHopperJettyServerBuilder.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jetty;
2 |
3 | import org.atomhopper.AtomHopperServlet;
4 | import org.atomhopper.AtomHopperVersionServlet;
5 | import org.atomhopper.servlet.ServletInitParameter;
6 | import org.atomhopper.servlet.ServletSpringContext;
7 | import org.eclipse.jetty.server.Server;
8 | import org.eclipse.jetty.servlet.ServletContextHandler;
9 | import org.eclipse.jetty.servlet.ServletHolder;
10 | import org.springframework.web.context.ContextLoaderListener;
11 |
12 | /**
13 | *
14 | *
15 | */
16 | public class AtomHopperJettyServerBuilder {
17 |
18 | private final int portNumber;
19 |
20 | public AtomHopperJettyServerBuilder(int portNumber) {
21 | this.portNumber = portNumber;
22 | }
23 |
24 | private Server buildNewInstance() {
25 | final Server jettyServerReference = new Server(portNumber);
26 | final ServletContextHandler rootContext = buildRootContext(jettyServerReference);
27 |
28 | final ServletHolder atomHopServer = new ServletHolder(AtomHopperServlet.class);
29 | final ServletHolder versionServlet = new ServletHolder(AtomHopperVersionServlet.class);
30 | atomHopServer.setInitParameter(ServletInitParameter.CONTEXT_ADAPTER_CLASS.toString(), ServletSpringContext.class.getName());
31 | atomHopServer.setInitParameter(ServletInitParameter.CONFIGURATION_LOCATION.toString(), "classpath:/META-INF/atom-server.cfg.xml");
32 |
33 | rootContext.addServlet(versionServlet, "/buildinfo");
34 | rootContext.addServlet(atomHopServer, "/*");
35 |
36 | return jettyServerReference;
37 | }
38 |
39 | private ServletContextHandler buildRootContext(Server serverReference) {
40 | final ServletContextHandler servletContext = new ServletContextHandler(serverReference, "/");
41 | servletContext.getInitParams().put("contextConfigLocation", "classpath:/META-INF/application-context.xml");
42 | servletContext.addEventListener(new ContextLoaderListener());
43 |
44 | return servletContext;
45 | }
46 |
47 | public Server newServer() {
48 | return buildNewInstance();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/response/EntryResponseHandler.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.response;
2 |
3 | import org.apache.abdera.model.Entry;
4 | import org.apache.abdera.protocol.server.ProviderHelper;
5 | import org.apache.abdera.protocol.server.RequestContext;
6 | import org.apache.abdera.protocol.server.ResponseContext;
7 | import org.atomhopper.abdera.filter.AdapterResponseInterceptor;
8 | import org.atomhopper.response.AdapterResponse;
9 |
10 | import java.util.Date;
11 |
12 | public class EntryResponseHandler extends AbstractResponseHandler {
13 |
14 | private static final String XML = "application/xml";
15 |
16 | public EntryResponseHandler(String[] allowedMethods, AdapterResponseInterceptor... interceptors) {
17 | super(allowedMethods, interceptors);
18 | }
19 |
20 | @Override
21 | protected ResponseContext handleAdapterResponse(RequestContext rc, AdapterResponse adapterResponse) {
22 | final Date lastUpdated = adapterResponse.getBody() != null ? adapterResponse.getBody().getUpdated() : null;
23 |
24 | switch (adapterResponse.getResponseStatus()) {
25 | case OK:
26 | case CREATED:
27 | return ProviderHelper.returnBase(adapterResponse.getBody(), adapterResponse.getResponseStatus().value(), lastUpdated);
28 |
29 | case NOT_FOUND:
30 | return ProviderHelper.notfound(rc, adapterResponse.getMessage()).setContentType(XML);
31 |
32 | case INTERNAL_SERVER_ERROR:
33 | return ProviderHelper.servererror(rc, adapterResponse.getMessage(), new InternalServerException()).setContentType(XML);
34 |
35 | case METHOD_NOT_ALLOWED:
36 | return ProviderHelper.notallowed(rc, adapterResponse.getMessage(), getAllowedHttpMethods()).setContentType(XML);
37 |
38 | case BAD_REQUEST:
39 | return ProviderHelper.badrequest(rc, adapterResponse.getMessage()).setContentType(XML);
40 |
41 | case CONFLICT:
42 | return ProviderHelper.conflict(rc, adapterResponse.getMessage()).setContentType(XML);
43 |
44 | default:
45 | return ProviderHelper.notfound(rc).setContentType(XML);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/test-suite/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Atom Hopper Server
5 | ATOM
6 |
7 |
8 | contextConfigLocation
9 | /META-INF/application-context.xml
10 |
11 |
12 |
13 | Spring Context Loader
14 | org.springframework.web.context.ContextLoaderListener
15 |
16 |
17 |
18 | Atom-Hopper
19 | org.atomhopper.AtomHopperServlet
20 |
21 |
22 | config-directory
23 | /tmp/atom-server
24 |
25 |
26 |
27 | context-adapter-class
28 | org.atomhopper.servlet.context.impl.ServletSpringContext
29 |
30 |
44 |
45 | atomhopper-url-pattern
46 |
47 |
48 |
49 |
50 |
51 | Atom-Hopper
52 | /*
53 |
54 |
55 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/config/AtomHopperConfigurationPreprocessor.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.config;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 | import org.atomhopper.config.v1_0.Author;
5 | import org.atomhopper.config.v1_0.Configuration;
6 | import org.atomhopper.config.v1_0.ConfigurationDefaults;
7 | import org.atomhopper.config.v1_0.FeedConfiguration;
8 | import org.atomhopper.config.v1_0.WorkspaceConfiguration;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * @author zinic
14 | */
15 | public class AtomHopperConfigurationPreprocessor {
16 |
17 | private final Configuration configuration;
18 |
19 | public AtomHopperConfigurationPreprocessor(Configuration configuration) {
20 | this.configuration = configuration;
21 | }
22 |
23 | public AtomHopperConfigurationPreprocessor applyDefaults() {
24 | final ConfigurationDefaults configurationDefaults = configuration.getDefaults();
25 | setDefaultAuthor(configuration.getWorkspace(), configurationDefaults.getAuthor());
26 |
27 | return new AtomHopperConfigurationPreprocessor(configuration);
28 | }
29 |
30 | public Configuration getConfiguration() {
31 | return configuration;
32 | }
33 |
34 | private void setDefaultAuthor(List workspaces, Author globalAuthorDefault) {
35 | for (WorkspaceConfiguration workspaceConfiguration : workspaces) {
36 | final Author workspaceAuthorDefault = (workspaceConfiguration.getDefaults() == null)
37 | ? null : workspaceConfiguration.getDefaults().getAuthor();
38 |
39 | final Author authorToApply = isAuthorEmpty(workspaceAuthorDefault)
40 | ? globalAuthorDefault : workspaceAuthorDefault;
41 |
42 | if (!isAuthorEmpty(authorToApply)) {
43 | for (FeedConfiguration feed : workspaceConfiguration.getFeed()) {
44 | if (isAuthorEmpty(feed.getAuthor())) {
45 | feed.setAuthor(authorToApply);
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
52 | private boolean isAuthorEmpty(Author author) {
53 | return author == null || author.getName() == null || StringUtils.isBlank(author.getName());
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/util/context/AdapterGetter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.util.context;
2 |
3 | import org.apache.commons.lang.StringUtils;
4 | import org.atomhopper.servlet.ApplicationContextAdapter;
5 | import org.atomhopper.util.reflection.ReflectionTools;
6 |
7 | /**
8 | *
9 | *
10 | */
11 | public class AdapterGetter {
12 |
13 | private final ApplicationContextAdapter contextAdapter;
14 |
15 | public AdapterGetter(ApplicationContextAdapter contextAdapter) {
16 | this.contextAdapter = contextAdapter;
17 | }
18 |
19 | public T getByName(String referenceName, Class classToCastTo) {
20 | if (StringUtils.isBlank(referenceName)) {
21 | throw new IllegalArgumentException("Bean reference for an adapter must not be empty or null");
22 | }
23 |
24 | final Object reference = contextAdapter.fromContext(referenceName, classToCastTo);
25 |
26 | if (reference == null) {
27 | throw new AdapterNotFoundException("Unable to find adapter by name: " + referenceName);
28 | } else if (!classToCastTo.isInstance(reference)) {
29 | throw new IllegalArgumentException("Class: "
30 | + reference.getClass().getCanonicalName()
31 | + " does not implement " + classToCastTo.getCanonicalName());
32 | }
33 |
34 | return (T) reference;
35 | }
36 |
37 | public T getByClassDefinition(Class> configuredAdapterClass, Class classToCastTo) {
38 | if (!classToCastTo.isAssignableFrom(configuredAdapterClass)) {
39 | throw new IllegalArgumentException("Class: "
40 | + configuredAdapterClass.getCanonicalName()
41 | + " does not implement " + classToCastTo.getCanonicalName());
42 | }
43 |
44 | try {
45 | final T instance = (T) contextAdapter.fromContext(configuredAdapterClass);
46 |
47 | return instance != null
48 | ? instance
49 | : (T) ReflectionTools.construct(configuredAdapterClass);
50 | } catch (Exception ex) {
51 | throw new AdapterConstructionException("Failed to get and or construct class: "
52 | + configuredAdapterClass.getCanonicalName(), ex);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/adapters/jdbc/src/main/java/org/atomhopper/jdbc/model/PersistedEntry.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.jdbc.model;
2 |
3 | import java.sql.Timestamp;
4 | import java.util.Arrays;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 | import java.util.TimeZone;
8 |
9 |
10 | public class PersistedEntry {
11 |
12 | private long id;
13 | private String entryId;
14 | private String feed;
15 | private String entryBody;
16 | private Date creationDate;
17 | private Date dateLastUpdated;
18 | private String[] categories;
19 |
20 | public PersistedEntry() {
21 | final Calendar localNow = Calendar.getInstance(TimeZone.getDefault());
22 | localNow.setTimeInMillis(System.currentTimeMillis());
23 |
24 | creationDate = localNow.getTime();
25 | dateLastUpdated = creationDate;
26 | }
27 |
28 | public long getId() {
29 | return id;
30 | }
31 |
32 | public void setId(long id) {
33 | this.id = id;
34 | }
35 |
36 | public String getEntryId() {
37 | return entryId;
38 | }
39 |
40 | public void setEntryId(String entryId) {
41 | this.entryId = entryId;
42 | }
43 |
44 | public String getFeed() {
45 | return feed;
46 | }
47 |
48 | public void setFeed(String feed) {
49 | this.feed = feed;
50 | }
51 |
52 | public String getEntryBody() {
53 | return entryBody;
54 | }
55 |
56 | public void setEntryBody(String entryBody) {
57 | this.entryBody = entryBody;
58 | }
59 |
60 | public Date getCreationDate() {
61 | return (Date) creationDate.clone();
62 | }
63 |
64 | public void setCreationDate(Date creationDate) {
65 | this.creationDate = (Date) creationDate.clone();
66 | }
67 |
68 | public Date getDateLastUpdated() {
69 | return (Date) dateLastUpdated.clone();
70 | }
71 |
72 | public void setDateLastUpdated(Date dateLastUpdated) {
73 | this.dateLastUpdated = (Date) dateLastUpdated.clone();
74 | }
75 |
76 | public String[] getCategories() {
77 | return categories.clone();
78 | }
79 |
80 | public void setCategories(String[] categories) {
81 | if (categories != null) {
82 | this.categories = Arrays.copyOf(categories, categories.length);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/adapters/postgres-adapter/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.atomhopper
7 | parent
8 | 1.2.35-SNAPSHOT
9 | ./../../pom.xml
10 |
11 |
12 | org.atomhopper.adapter
13 | postgres-adapter
14 | jar
15 |
16 | ATOM Hopper - Postgres Adapter
17 |
18 |
19 |
20 | org.atomhopper
21 | core
22 |
23 |
24 |
25 | postgresql
26 | postgresql
27 |
28 |
29 |
30 | org.apache.tomcat
31 | tomcat-jdbc
32 |
33 |
34 |
35 | org.javassist
36 | javassist
37 |
38 |
39 |
40 | org.apache.abdera
41 | abdera-core
42 |
43 |
44 |
45 | org.springframework
46 | spring-jdbc
47 |
48 |
49 |
50 | org.slf4j
51 | slf4j-api
52 |
53 |
54 |
55 | org.mockito
56 | mockito-all
57 |
58 |
59 |
60 | junit
61 | junit
62 |
63 |
64 |
65 | com.yammer.metrics
66 | metrics-core
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/adapters/mongodb/src/test/java/org/atomhopper/mongodb/adapter/MongodbUtilitiesTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.mongodb.adapter;
2 |
3 | import static junit.framework.Assert.assertEquals;
4 | import static org.atomhopper.mongodb.adapter.MongodbUtilities.formatCollectionName;
5 | import static org.atomhopper.mongodb.adapter.MongodbUtilities.safeLongToInt;
6 | import org.junit.Test;
7 | import org.junit.experimental.runners.Enclosed;
8 | import org.junit.runner.RunWith;
9 |
10 |
11 | @RunWith(Enclosed.class)
12 | public class MongodbUtilitiesTest {
13 |
14 | public static class WhenCallingMongodbUtilities {
15 |
16 | private final String SHORT_FORMATTED_COLLECTION_NAME = "namespace.feed";
17 | private final String SHORT_COLLECTION_NAME = "namespace/feed";
18 |
19 | private final String LONG_FORMATTED_COLLECTION_NAME = "namespace.feed.1234567890.1234567890.1234567890.1234567890.1234567890.";
20 | private final String LONG_COLLECTION_NAME = "namespace/feed/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890/1234567890";
21 |
22 | @Test
23 | public void shouldformatShortCollectionName() throws Exception {
24 | assertEquals("Should return formatted collection name (short)", SHORT_FORMATTED_COLLECTION_NAME, formatCollectionName(SHORT_COLLECTION_NAME));
25 | }
26 |
27 | @Test
28 | public void shouldformatLongCollectionName() throws Exception {
29 | assertEquals("Should return formatted collection name (long)", LONG_FORMATTED_COLLECTION_NAME, formatCollectionName(LONG_COLLECTION_NAME));
30 | }
31 |
32 | @Test(expected=IllegalArgumentException.class)
33 | public void shouldThrowErrorWhenConvertingWithMaxValuePlusOne() throws Exception {
34 | long maxValueForTest = (long)Integer.MAX_VALUE + (long)1;
35 | safeLongToInt(maxValueForTest);
36 | }
37 |
38 | @Test(expected=IllegalArgumentException.class)
39 | public void shouldThrowErrorWhenConvertingWithMinValueMinusOne() throws Exception {
40 | long minValueForTest = (long)Integer.MIN_VALUE - (long)1;
41 | safeLongToInt(minValueForTest);
42 | }
43 |
44 | @Test
45 | public void shouldReturnConvertedValue() throws Exception {
46 | assertEquals("Should return value", 1, safeLongToInt(1));
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/response/AbstractResponseHandler.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.response;
2 |
3 | import org.apache.abdera.protocol.server.RequestContext;
4 | import org.apache.abdera.protocol.server.ResponseContext;
5 | import org.atomhopper.abdera.filter.AdapterResponseInterceptor;
6 | import org.atomhopper.response.AdapterResponse;
7 |
8 | import java.util.Arrays;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 |
12 | public abstract class AbstractResponseHandler implements ResponseHandler {
13 |
14 | private final List> responseInterceptors;
15 | private final String[] allowedMethods;
16 |
17 | public AbstractResponseHandler(String[] allowedMethods, AdapterResponseInterceptor... interceptors) {
18 | this.allowedMethods = Arrays.copyOf(allowedMethods, allowedMethods.length);
19 | responseInterceptors = new LinkedList>(Arrays.asList(interceptors));
20 | }
21 |
22 | public AbstractResponseHandler(String[] allowedMethods, List> adapterResponseInterceptorList) {
23 | this.allowedMethods = Arrays.copyOf(allowedMethods, allowedMethods.length);
24 | responseInterceptors = new LinkedList>(adapterResponseInterceptorList);
25 | }
26 |
27 | @Override
28 | public final ResponseContext handleResponse(RequestContext rc, AdapterResponse adapterResponse) {
29 | processResponse(rc, adapterResponse);
30 |
31 | return handleAdapterResponse(rc, adapterResponse);
32 | }
33 |
34 | @Override
35 | public void addResponseInterceptor(AdapterResponseInterceptor adapterResponseInterceptor) {
36 | responseInterceptors.add(adapterResponseInterceptor);
37 | }
38 |
39 | @Override
40 | public void clearResponseInterceptors() {
41 | responseInterceptors.clear();
42 | }
43 |
44 | protected abstract ResponseContext handleAdapterResponse(RequestContext rc, AdapterResponse adapterResponse);
45 |
46 | protected String[] getAllowedHttpMethods() {
47 | return allowedMethods;
48 | }
49 |
50 | private void processResponse(RequestContext rc, AdapterResponse adapterResponse) {
51 | for (AdapterResponseInterceptor processor : responseInterceptors) {
52 | processor.process(rc, adapterResponse);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hopper/src/test/java/org/atomhopper/adapter/impl/DisabledFeedSourceTest.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.adapter.impl;
2 |
3 |
4 | import org.atomhopper.adapter.request.feed.FeedRequest;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.junit.experimental.runners.Enclosed;
8 | import org.junit.runner.RunWith;
9 | import org.apache.abdera.model.Entry;
10 | import org.apache.abdera.model.Feed;
11 | import org.atomhopper.adapter.request.adapter.GetEntryRequest;
12 | import org.atomhopper.adapter.request.adapter.GetFeedRequest;
13 | import org.atomhopper.response.AdapterResponse;
14 | import org.springframework.http.HttpStatus;
15 |
16 | import static junit.framework.Assert.assertEquals;
17 | import static junit.framework.Assert.assertNotNull;
18 | import static org.mockito.Mockito.mock;
19 |
20 |
21 | @RunWith(Enclosed.class)
22 | public class DisabledFeedSourceTest {
23 |
24 | public static class WhenAccessingDisabledFeedSource {
25 |
26 | private DisabledFeedSource disabledFeedSource;
27 | private GetEntryRequest mockGetEntryRequest;
28 | private GetFeedRequest mockGetFeedRequest;
29 |
30 | @Before
31 | public void setUp() throws Exception {
32 | disabledFeedSource = DisabledFeedSource.getInstance();
33 | mockGetEntryRequest = mock(GetEntryRequest.class);
34 | mockGetFeedRequest = mock(GetFeedRequest.class);
35 | }
36 |
37 | @Test
38 | public void shouldGetDisabledFeedSource() {
39 | assertNotNull("Should not return null", DisabledFeedSource.getInstance());
40 | }
41 |
42 | @Test
43 | public void shouldGetFeedInformation() {
44 | assertNotNull("Should not return null", disabledFeedSource.getFeedInformation());
45 | }
46 |
47 | @Test
48 | public void shouldGetEntry() {
49 | AdapterResponse response = disabledFeedSource.getEntry(mockGetEntryRequest);
50 | assertEquals("Should get entry with METHOD_NOT_ALLOWED", HttpStatus.METHOD_NOT_ALLOWED, response.getResponseStatus());
51 | }
52 |
53 | @Test
54 | public void shouldGetFeed() {
55 | AdapterResponse response = disabledFeedSource.getFeed(mockGetFeedRequest);
56 | assertEquals("Should get feed with METHOD_NOT_ALLOWED", HttpStatus.METHOD_NOT_ALLOWED, response.getResponseStatus());
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/hopper/src/main/java/org/atomhopper/abdera/filter/SelectiveURIJSONFilter.java:
--------------------------------------------------------------------------------
1 | package org.atomhopper.abdera.filter;
2 |
3 | import java.util.List;
4 | import org.apache.abdera.ext.json.JSONFilter;
5 | import org.apache.abdera.i18n.iri.IRI;
6 | import org.apache.abdera.protocol.server.FilterChain;
7 | import org.apache.abdera.protocol.server.ProviderHelper;
8 | import org.apache.abdera.protocol.server.RequestContext;
9 | import org.apache.abdera.protocol.server.ResponseContext;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Component;
12 |
13 | /**
14 | * This class performs XML -> JSON transformation on Atom Hopper responses.
15 | * It can be configured to only perform this transformation on selective URIs.
16 | * If a particular request URI is in the 'allowedURIs' list (only substring
17 | * check is performed), then the transformation
18 | * of XML -> JSON will be performed.
19 | *
20 | * User: shin4590
21 | * Date: 7/1/14
22 | */
23 | @Component
24 | public class SelectiveURIJSONFilter extends JSONFilter {
25 |
26 | @Autowired
27 | private List allowedURIs;
28 |
29 | @Override
30 | public ResponseContext filter(RequestContext request, FilterChain chain) {
31 | if ( uriAllowed(request.getUri()) ) {
32 | return super.filter(request, chain);
33 | } else {
34 | String format = request.getParameter("format");
35 | if ( format != null && format.equalsIgnoreCase("json") ) {
36 | return ProviderHelper.badrequest(request, "format=json is not a valid query parameter for this feed");
37 | } else {
38 | return chain.next(request);
39 | }
40 | }
41 | }
42 |
43 | public List getAllowedURIs() {
44 | return allowedURIs;
45 | }
46 |
47 | public void setAllowedURIs(List allowedURIs) {
48 | this.allowedURIs = allowedURIs;
49 | }
50 |
51 | private boolean uriAllowed(IRI uri) {
52 | if ( allowedURIs == null ) {
53 | return false;
54 | }
55 | String path = uri.getPath();
56 | for (String allowedPath : allowedURIs) {
57 | // actual path maybe: /foo/bar/entries/urn:uuid:xxxx, but
58 | // allowedURIs can just be /foo/bar
59 | if ( path.startsWith(allowedPath) ) {
60 | return true;
61 | }
62 | }
63 | return false;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------