/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.streams.dropwizard;
import org.apache.streams.config.StreamsConfiguration;
import org.apache.streams.core.StreamBuilder;
import org.apache.streams.core.StreamsProvider;
import org.apache.streams.jackson.StreamsJacksonMapper;
import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
import com.hubspot.dropwizard.guice.GuiceBundle;
import io.dropwizard.Application;
import io.dropwizard.jackson.GuavaExtrasModule;
import io.dropwizard.metrics.MetricsFactory;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Entry point to a dropwizard streams application
*
* <p/>
* It will start up a stream in the local runtime, as well as bind any
* StreamsProvider on the classpath with a @Resource annotation.
*/
public class StreamsApplication extends Application<StreamsDropwizardConfiguration> {
private static final Logger LOGGER = LoggerFactory
.getLogger(StreamsApplication.class);
protected static ObjectMapper mapper = StreamsJacksonMapper.getInstance();
protected StreamBuilder builder;
private static StreamsConfiguration streamsConfiguration;
// ConcurrentHashSet is preferable, but it's only in guava 15+
// spark 1.5.0 uses guava 14 so for the moment this is the workaround
// Set<StreamsProvider> resourceProviders = Sets.newConcurrentHashSet();
private Set<StreamsProvider> resourceProviders = Collections.newSetFromMap(new ConcurrentHashMap<StreamsProvider, Boolean>());
private Executor executor = Executors.newSingleThreadExecutor();
static {
mapper.registerModule(new AfterburnerModule());
mapper.registerModule(new GuavaModule());
mapper.registerModule(new GuavaExtrasModule());
}
@Override
public void initialize(Bootstrap<StreamsDropwizardConfiguration> bootstrap) {
LOGGER.info(getClass().getPackage().getName());
GuiceBundle<StreamsDropwizardConfiguration> guiceBundle =
GuiceBundle.<StreamsDropwizardConfiguration>newBuilder()
.addModule(new StreamsDropwizardModule())
.setConfigClass(StreamsDropwizardConfiguration.class)
// override and add more packages to pick up custom Resources
.enableAutoConfig(getClass().getPackage().getName())
.build();
bootstrap.addBundle(guiceBundle);
}
@Override
public void run(StreamsDropwizardConfiguration streamsDropwizardConfiguration, Environment environment) throws Exception {
executor = Executors.newSingleThreadExecutor();
for ( Class<?> resourceProviderClass : environment.jersey().getResourceConfig().getRootResourceClasses() ) {
StreamsProvider provider = (StreamsProvider)resourceProviderClass.newInstance();
if ( StreamsProvider.class.isInstance(provider)) {
resourceProviders.add(provider);
}
}
MetricRegistry metrics = new MetricRegistry();
MetricsFactory mfac = streamsDropwizardConfiguration.getMetricsFactory();
mfac.configure(environment.lifecycle(), metrics);
streamsConfiguration = mapper.convertValue(streamsDropwizardConfiguration, StreamsConfiguration.class);
builder = setup(streamsConfiguration, resourceProviders);
executor.execute(new StreamsDropwizardRunner(builder, streamsConfiguration));
// wait for streams to start up
Thread.sleep(10000);
for (StreamsProvider resource : resourceProviders) {
environment.jersey().register(resource);
LOGGER.info("Added resource class: {}", resource);
}
}
/**
* setup StreamBuilder.
* @param streamsConfiguration StreamsConfiguration
* @param resourceProviders Set of StreamsProvider
* @return StreamBuilder
*/
public StreamBuilder setup(StreamsConfiguration streamsConfiguration, Set<StreamsProvider> resourceProviders) {
StreamBuilder builder = new StreamDropwizardBuilder(streamsConfiguration);
List<String> providers = new ArrayList<>();
for ( StreamsProvider provider: resourceProviders) {
String providerId = provider.getClass().getSimpleName();
builder.newPerpetualStream(providerId, provider);
providers.add(providerId);
}
return builder;
}
private class StreamsDropwizardRunner implements Runnable {
private StreamsConfiguration streamsConfiguration;
private StreamBuilder builder;
protected StreamsDropwizardRunner(StreamBuilder builder, StreamsConfiguration streamsConfiguration) {
this.streamsConfiguration = streamsConfiguration;
this.builder = builder;
}
@Override
public void run() {
builder.start();
}
}
/**
* Run from console:
*
* <p/>
* java -jar uber.jar server ./configuration.yml
*
* @param args ["server", configuration.yml]
* @throws Exception Exception
*/
public static void main(String[] args) throws Exception {
new StreamsApplication().run(args);
}
}