Java tutorial
/* * Copyright 2012 Janrain, Inc. * * 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 com.janrain.backplane2.server.config; import com.janrain.backplane.server.config.BpServerConfig; import com.janrain.backplane2.server.BackplaneServerException; import com.janrain.backplane2.server.V2MessageProcessor; import com.janrain.backplane2.server.dao.DAOFactory; import com.janrain.cache.CachedL1; import com.janrain.commons.supersimpledb.SimpleDBException; import com.janrain.commons.util.AwsUtility; import com.janrain.commons.util.InitSystemProps; import com.janrain.crypto.HmacHashUtils; import com.janrain.redis.Redis; import com.janrain.utils.BackplaneSystemProps; import com.netflix.curator.framework.CuratorFramework; import com.netflix.curator.framework.CuratorFrameworkFactory; import com.netflix.curator.framework.recipes.leader.LeaderSelector; import com.netflix.curator.retry.ExponentialBackoffRetry; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.MetricName; import com.yammer.metrics.reporting.ConsoleReporter; import com.yammer.metrics.reporting.GraphiteReporter; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.context.annotation.Scope; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * Holds configuration settings for the Backplane server * * @author Jason Cowley, Johnny Bufu */ @Scope(value = "singleton") public class Backplane2Config { // - PUBLIC /** * @return the debugMode */ public boolean isDebugMode() { return Boolean.valueOf(cachedGet(BpServerConfig.Field.DEBUG_MODE)); } /** * @return the server default max message value per channel * @throws SimpleDBException */ public long getDefaultMaxMessageLimit() { Long max = Long.valueOf(cachedGet(BpServerConfig.Field.DEFAULT_MESSAGES_MAX)); return max == null ? Backplane2Config.BP_MAX_MESSAGES_DEFAULT : max; } public boolean isLeaderDisabled() { // skip DAO layer, not so crazy about editing serialized streams for debug, yay FED-76 return isDebugMode() && Redis.getInstance().get(EC2InstanceId) != null; } public Exception getDebugException(Exception e) { return isDebugMode() ? e : null; } public String getInstanceId() { return bpInstanceId; } public String getBuildVersion() { return buildProperties.getProperty(BUILD_VERSION_PROPERTY); } /** * Retrieve the server instance id Amazon assigned * @return */ public static String getEC2InstanceId() { return EC2InstanceId; } public static void addToBackgroundServices(ScheduledExecutorService messageWorkerTask) { backgroundServices.add(messageWorkerTask); } // - PACKAGE Backplane2Config(String instanceId) { this.bpInstanceId = instanceId; } /** * Load system property * @param propParamName * @return */ static String getAwsProp(String propParamName) { String result = System.getProperty(propParamName); if (StringUtils.isBlank(result)) { throw new RuntimeException("Required system property configuration missing: " + propParamName); } return result; } // - PRIVATE private static final Logger logger = Logger.getLogger(Backplane2Config.class); private static final String BUILD_PROPERTIES = "/build.properties"; private static final String BUILD_VERSION_PROPERTY = "build.version"; private static final Properties buildProperties = new Properties(); private static final long BP_MAX_MESSAGES_DEFAULT = 100; private static final List<ExecutorService> backgroundServices = new ArrayList<ExecutorService>(); private final String bpInstanceId; private ExecutorService pingRedis; // Amazon specific instance-id value private static String EC2InstanceId = AwsUtility.retrieveEC2InstanceId(); private final com.yammer.metrics.core.Timer v2CleanupTimer = com.yammer.metrics.Metrics.newTimer( new MetricName("v2", this.getClass().getName().replace(".", "_"), "cleanup_messages_time"), TimeUnit.MILLISECONDS, TimeUnit.MINUTES); @SuppressWarnings({ "UnusedDeclaration" }) private Backplane2Config() { this.bpInstanceId = getAwsProp(InitSystemProps.AWS_INSTANCE_ID); ConsoleReporter.enable(10, TimeUnit.MINUTES); // Dump metrics to graphite server String graphiteServer = System.getProperty(BackplaneSystemProps.GRAPHITE_SERVER); if (StringUtils.isNotBlank(graphiteServer)) { try { String args[] = graphiteServer.split(":"); String server = args[0]; int port = Integer.parseInt(args[1]); GraphiteReporter.enable(10, TimeUnit.SECONDS, server, port, BackplaneSystemProps.getMachineName().replace(".", "_") + "_" + bpInstanceId); logger.info("Graphite server enabled at " + graphiteServer); } catch (Exception e) { logger.warn( "could not enable Graphite from " + graphiteServer + " must be in the form SERVER:PORT"); } } try { buildProperties.load(Backplane2Config.class.getResourceAsStream(BUILD_PROPERTIES)); //assert(StringUtils.isNotBlank(getEncryptionKey())); } catch (Exception e) { String err = "Error loading build properties from " + BUILD_PROPERTIES; logger.error(err, e); throw new RuntimeException(err, e); } logger.info("Configured Backplane Server instance: " + bpInstanceId); } private ScheduledExecutorService createPingTask() { ScheduledExecutorService ping = Executors.newScheduledThreadPool(1); ping.scheduleWithFixedDelay(new Runnable() { @Override public void run() { com.janrain.redis.Redis.getInstance().ping(); } }, 30, 10, TimeUnit.SECONDS); return ping; } @PostConstruct private void init() { backgroundServices.add(createPingTask()); try { String zkServerConfig = System.getProperty(BackplaneSystemProps.ZOOKEEPER_SERVERS); if (StringUtils.isEmpty(zkServerConfig)) { logger.error("Cannot find configuration entry for ZooKeeper server"); System.exit(1); } CuratorFramework client = CuratorFrameworkFactory.newClient(zkServerConfig, new ExponentialBackoffRetry(50, 20)); client.start(); String leaderPath = "/v2_worker_" + getInstanceId(); LeaderSelector leaderSelector = new LeaderSelector(client, leaderPath, new V2MessageProcessor(this, daoFactory)); leaderSelector.autoRequeue(); leaderSelector.start(); com.janrain.redis.Redis.getInstance().setActiveRedisInstance(client); } catch (Exception e) { logger.error(e); } } @PreDestroy private void cleanup() { Metrics.shutdown(); for (ExecutorService executor : backgroundServices) { try { executor.shutdown(); if (executor.awaitTermination(10, TimeUnit.SECONDS)) { logger.info("Background thread shutdown properly"); } else { executor.shutdownNow(); if (!executor.awaitTermination(10, TimeUnit.SECONDS)) { logger.error("Background thread did not terminate"); } } } catch (InterruptedException e) { logger.error("error shutting down background service", e); executor.shutdownNow(); Thread.currentThread().interrupt(); } } } @Inject private DAOFactory daoFactory; private String cachedGet(BpServerConfig.Field property) { try { BpServerConfig bpServerConfigCache = (BpServerConfig) CachedL1.getInstance() .getObject(BackplaneSystemProps.BPSERVER_CONFIG_KEY); if (bpServerConfigCache == null) { // pull from db if not found in cache try { bpServerConfigCache = daoFactory.getConfigDAO().get(BackplaneSystemProps.BPSERVER_CONFIG_KEY); } catch (Exception e) { // if we get an error from the db, create a new object } if (bpServerConfigCache == null) { // no instance found in cache or the db, so let's use the default record bpServerConfigCache = new BpServerConfig(); } // add it to the L1 cache CachedL1.getInstance().setObject(BackplaneSystemProps.BPSERVER_CONFIG_KEY, -1, bpServerConfigCache); } return bpServerConfigCache.get(property); } catch (Exception e) { logger.error(e); return null; } } private Long getMaxCacheAge() { return Long.valueOf(cachedGet(BpServerConfig.Field.CONFIG_CACHE_AGE_SECONDS)); } public void checkAdminAuth(String user, String password) throws AuthException { try { User userEntry = daoFactory.getAdminDAO().get(user); String authKey = userEntry == null ? null : userEntry.get(User.Field.PWDHASH); if (!HmacHashUtils.checkHmacHash(password, authKey)) { logger.error("User " + user + " not authorized"); throw new AuthException("Access denied"); } } catch (BackplaneServerException e) { logger.error("Error authenticating user " + user + " : " + e.getMessage(), getDebugException(e)); throw new AuthException("User " + user + " not authorized, " + e.getMessage(), getDebugException(e)); } } }