/* * Copyright 2015 Petr Bouda * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * 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.joyrest.examples.combiner.binder; import java.io.InputStream; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Function; import java.util.logging.Logger; import javax.inject.Singleton; import org.glassfish.hk2.api.InjectionResolver; import org.glassfish.hk2.api.TypeLiteral; import org.glassfish.hk2.utilities.binding.AbstractBinder; import org.joyrest.examples.combiner.ApplicationProperties; import org.joyrest.examples.combiner.generator.IdGenerator; import org.joyrest.examples.combiner.generator.SequenceIdGenerator; import org.joyrest.examples.combiner.manager.FeedDataStoreManager; import org.joyrest.examples.combiner.manager.FeedTaskFactory; import org.joyrest.examples.combiner.manager.FeedTaskFactoryImpl; import org.joyrest.examples.combiner.model.CombinedFeed; import org.joyrest.examples.combiner.routes.CombinedFeedController; import org.joyrest.examples.combiner.service.CombinedFeedService; import org.joyrest.examples.combiner.service.CrudService; import org.joyrest.examples.combiner.store.DataStoreObserver; import org.joyrest.examples.combiner.store.InMemoryDataStore; import org.joyrest.examples.combiner.store.ObservableDataStore; import org.joyrest.examples.combiner.store.ReadWriteLockDataStore; import org.joyrest.hk2.extension.property.Property; import org.joyrest.hk2.extension.property.PropertyResolver; import org.joyrest.hk2.extension.property.parser.IntegerPropertyParser; import org.joyrest.hk2.extension.property.parser.LongPropertyParser; import org.joyrest.routing.ControllerConfiguration; import static java.util.Objects.nonNull; import static java.util.stream.Collectors.toMap; public class ApplicationBinder extends AbstractBinder { private static Logger LOG = Logger.getLogger(PropertiesBinder.class.getName()); private final Properties properties; public ApplicationBinder() { this("application.properties"); } public ApplicationBinder(String propertiesFileName) { this.properties = getProperties(propertiesFileName); } private static Properties getProperties(String path) { try (InputStream inputStream = ApplicationBinder.class.getClassLoader().getResourceAsStream(path)) { Properties properties = new Properties(); properties.load(inputStream); return properties; } catch (Exception e) { LOG.warning("Property file '" + path + "' not found in the classpath"); } return null; } @Override protected void configure() { ReadWriteLockDataStore datastore = new ReadWriteLockDataStore(); install( new RouteBinder(), new PropertiesBinder(properties), new ResourcePartBinder(datastore), new SchedulerPartBinder(datastore, properties)); } private static class RouteBinder extends AbstractBinder { @Override protected void configure() { bind(CombinedFeedController.class) .to(ControllerConfiguration.class) .in(Singleton.class); } } private static class SchedulerPartBinder extends AbstractBinder { private final ObservableDataStore dataStore; private final Properties properties; SchedulerPartBinder(ObservableDataStore datastore, Properties properties) { this.dataStore = datastore; this.properties = properties; } @Override protected void configure() { FeedTaskFactory feedTaskFactory = new FeedTaskFactoryImpl(dataStore); FeedDataStoreManager dataStoreManager; if (properties.containsKey(ApplicationProperties.SCHEDULER_POOL_SIZE)) { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( Integer.parseInt((String) properties.get(ApplicationProperties.SCHEDULER_POOL_SIZE))); dataStoreManager = new FeedDataStoreManager(feedTaskFactory, scheduler); } else { dataStoreManager = new FeedDataStoreManager(feedTaskFactory); } dataStore.addObserver(dataStoreManager); bind(feedTaskFactory) .to(FeedTaskFactory.class); bind(dataStoreManager) .to(FeedDataStoreManager.class) .to(DataStoreObserver.class); } } private static class ResourcePartBinder extends AbstractBinder { private final InMemoryDataStore datastore; ResourcePartBinder(InMemoryDataStore datastore) { this.datastore = datastore; } @Override protected void configure() { bind(datastore) .to(InMemoryDataStore.class); bind(CombinedFeedService.class) .to(new TypeLiteral<CrudService<CombinedFeed>>() {}) .in(Singleton.class); bind(SequenceIdGenerator.class) .to(IdGenerator.class) .in(Singleton.class); } } private static class PropertiesBinder extends AbstractBinder { private final Properties properties; PropertiesBinder(Properties properties) { this.properties = properties; } @Override protected void configure() { if (nonNull(properties)) { Map<String, String> propertyMap = properties.stringPropertyNames().stream() .collect(toMap(Function.identity(), properties::getProperty)); Map<Type, Function<String, ?>> parsers = new HashMap<>(); parsers.put(Integer.class, new IntegerPropertyParser()); parsers.put(Long.class, new LongPropertyParser()); parsers.put(String.class, Function.identity()); bind(new PropertyResolver(propertyMap, parsers)) .to(new TypeLiteral<InjectionResolver<Property>>() {}); } } } }