http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java deleted file mode 100644 index b5af827..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import org.apache.brooklyn.management.Task; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.enricher.Enrichers; -import brooklyn.entity.Entity; -import brooklyn.entity.Group; -import brooklyn.entity.basic.Attributes; -import brooklyn.entity.basic.ConfigurableEntityFactory; -import brooklyn.entity.basic.DynamicGroupImpl; -import brooklyn.entity.basic.Entities; -import brooklyn.entity.basic.EntityPredicates; -import brooklyn.entity.basic.Lifecycle; -import brooklyn.entity.basic.ServiceStateLogic; -import brooklyn.entity.proxy.LoadBalancer; -import brooklyn.entity.proxy.nginx.NginxController; -import brooklyn.entity.proxying.EntitySpec; -import brooklyn.entity.trait.Startable; -import brooklyn.entity.trait.StartableMethods; -import brooklyn.entity.webapp.tomcat.TomcatServer; -import brooklyn.event.SensorEvent; -import brooklyn.event.SensorEventListener; -import brooklyn.event.feed.ConfigToAttributes; -import brooklyn.location.Location; -import brooklyn.util.collections.MutableList; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.collections.QuorumCheck.QuorumChecks; -import brooklyn.util.exceptions.Exceptions; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; - -public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster { - - public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterImpl.class); - - public ControlledDynamicWebAppClusterImpl() { - this(MutableMap.of(), null); - } - - public ControlledDynamicWebAppClusterImpl(Map<?,?> flags) { - this(flags, null); - } - - public ControlledDynamicWebAppClusterImpl(Entity parent) { - this(MutableMap.of(), parent); - } - - @Deprecated - public ControlledDynamicWebAppClusterImpl(Map<?,?> flags, Entity parent) { - super(flags, parent); - } - - @Override - public void init() { - super.init(); - - ConfigToAttributes.apply(this, FACTORY); - ConfigToAttributes.apply(this, MEMBER_SPEC); - ConfigToAttributes.apply(this, CONTROLLER); - ConfigToAttributes.apply(this, CONTROLLER_SPEC); - ConfigToAttributes.apply(this, WEB_CLUSTER_SPEC); - ConfigToAttributes.apply(this, CONTROLLED_GROUP); - - ConfigurableEntityFactory<? extends WebAppService> webServerFactory = getAttribute(FACTORY); - EntitySpec<? extends WebAppService> webServerSpec = getAttribute(MEMBER_SPEC); - if (webServerFactory == null && webServerSpec == null) { - log.debug("creating default web server spec for {}", this); - webServerSpec = EntitySpec.create(TomcatServer.class); - setAttribute(MEMBER_SPEC, webServerSpec); - } - - log.debug("creating cluster child for {}", this); - // Note relies on initial_size being inherited by DynamicWebAppCluster, because key id is identical - EntitySpec<? extends DynamicWebAppCluster> webClusterSpec = getAttribute(WEB_CLUSTER_SPEC); - Map<String,Object> webClusterFlags; - if (webServerSpec != null) { - webClusterFlags = MutableMap.<String,Object>of("memberSpec", webServerSpec); - } else { - webClusterFlags = MutableMap.<String,Object>of("factory", webServerFactory); - } - if (webClusterSpec == null) { - log.debug("creating default web cluster spec for {}", this); - webClusterSpec = EntitySpec.create(DynamicWebAppCluster.class); - } - boolean hasMemberSpec = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.MEMBER_SPEC) || webClusterSpec.getFlags().containsKey("memberSpec"); - @SuppressWarnings("deprecation") - boolean hasMemberFactory = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.FACTORY) || webClusterSpec.getFlags().containsKey("factory"); - if (!(hasMemberSpec || hasMemberFactory)) { - webClusterSpec.configure(webClusterFlags); - } else { - log.warn("In {}, not setting cluster's {} because already set on webClusterSpec", new Object[] {this, webClusterFlags.keySet()}); - } - setAttribute(WEB_CLUSTER_SPEC, webClusterSpec); - - DynamicWebAppCluster cluster = addChild(webClusterSpec); - if (Entities.isManaged(this)) Entities.manage(cluster); - setAttribute(CLUSTER, cluster); - setEntityFilter(EntityPredicates.isMemberOf(cluster)); - - LoadBalancer controller = getAttribute(CONTROLLER); - if (controller == null) { - EntitySpec<? extends LoadBalancer> controllerSpec = getAttribute(CONTROLLER_SPEC); - if (controllerSpec == null) { - log.debug("creating controller using default spec for {}", this); - controllerSpec = EntitySpec.create(NginxController.class); - setAttribute(CONTROLLER_SPEC, controllerSpec); - } else { - log.debug("creating controller using custom spec for {}", this); - } - controller = addChild(controllerSpec); - addEnricher(Enrichers.builder().propagating(LoadBalancer.PROXY_HTTP_PORT, LoadBalancer.PROXY_HTTPS_PORT).from(controller).build()); - if (Entities.isManaged(this)) Entities.manage(controller); - setAttribute(CONTROLLER, controller); - } - - Group controlledGroup = getAttribute(CONTROLLED_GROUP); - if (controlledGroup == null) { - log.debug("using cluster as controlledGroup for {}", this); - controlledGroup = cluster; - setAttribute(CONTROLLED_GROUP, cluster); - } else { - log.debug("using custom controlledGroup {} for {}", controlledGroup, this); - } - - doBind(); - } - - @Override - protected void initEnrichers() { - if (config().getLocalRaw(UP_QUORUM_CHECK).isAbsent()) { - config().set(UP_QUORUM_CHECK, QuorumChecks.newInstance(2, 1.0, false)); - } - super.initEnrichers(); - ServiceStateLogic.newEnricherFromChildrenUp().checkChildrenOnly().requireUpChildren(getConfig(UP_QUORUM_CHECK)).addTo(this); - } - - @Override - public void rebind() { - super.rebind(); - doBind(); - } - - protected void doBind() { - DynamicWebAppCluster cluster = getAttribute(CLUSTER); - if (cluster != null) { - subscribe(cluster, DynamicWebAppCluster.GROUP_MEMBERS, new SensorEventListener<Object>() { - @Override public void onEvent(SensorEvent<Object> event) { - // TODO inefficient impl; also worth extracting this into a mixin of some sort. - rescanEntities(); - }}); - } - } - - @Override - public LoadBalancer getController() { - return getAttribute(CONTROLLER); - } - - @SuppressWarnings("unchecked") - @Override - public synchronized ConfigurableEntityFactory<WebAppService> getFactory() { - return (ConfigurableEntityFactory<WebAppService>) getAttribute(FACTORY); - } - - // TODO convert to an entity reference which is serializable - @Override - public synchronized DynamicWebAppCluster getCluster() { - return getAttribute(CLUSTER); - } - - @Override - public Group getControlledGroup() { - return getAttribute(CONTROLLED_GROUP); - } - - @Override - public void start(Collection<? extends Location> locations) { - ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING); - - try { - if (isLegacyConstruction()) { - init(); - } - - if (locations.isEmpty()) locations = getLocations(); - addLocations(locations); - - LoadBalancer loadBalancer = getController(); - loadBalancer.bind(MutableMap.of("serverPool", getControlledGroup())); - - List<Entity> childrenToStart = MutableList.<Entity>of(getCluster()); - // Set controller as child of cluster, if it does not already have a parent - if (getController().getParent() == null) { - addChild(getController()); - } - - // And only start controller if we are parent. Favour locations defined on controller, if present - Task<List<Void>> startControllerTask = null; - if (this.equals(getController().getParent())) { - if (getController().getLocations().size() == 0) { - childrenToStart.add(getController()); - } else { - startControllerTask = Entities.invokeEffectorList(this, MutableList.<Entity>of(getController()), Startable.START, ImmutableMap.of("locations", getController().getLocations())); - } - } - - Entities.invokeEffectorList(this, childrenToStart, Startable.START, ImmutableMap.of("locations", locations)).get(); - if (startControllerTask != null) { - startControllerTask.get(); - } - - // wait for everything to start, then update controller, to ensure it is up to date - // (will happen asynchronously as members come online, but we want to force it to happen) - getController().update(); - - ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING); - } catch (Exception e) { - ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); - throw Exceptions.propagate(e); - } finally { - connectSensors(); - } - } - - @Override - public void stop() { - ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING); - - try { - List<Startable> tostop = Lists.newArrayList(); - if (this.equals(getController().getParent())) tostop.add(getController()); - tostop.add(getCluster()); - - StartableMethods.stopSequentially(tostop); - - clearLocations(); - - ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED); - } catch (Exception e) { - ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE); - throw Exceptions.propagate(e); - } - } - - @Override - public void restart() { - // TODO prod the entities themselves to restart, instead? - Collection<Location> locations = Lists.newArrayList(getLocations()); - - stop(); - start(locations); - } - - void connectSensors() { - // FIXME no longer needed - addEnricher(Enrichers.builder() - .propagatingAllButUsualAnd(Attributes.MAIN_URI, ROOT_URL, GROUP_MEMBERS, GROUP_SIZE) - .from(getCluster()) - .build()); - addEnricher(Enrichers.builder() - // include hostname and address of controller (need both in case hostname only resolves to internal/private ip) - .propagating(LoadBalancer.HOSTNAME, Attributes.ADDRESS, Attributes.MAIN_URI, ROOT_URL) - .from(getController()) - .build()); - } - - @Override - public Integer resize(Integer desiredSize) { - return getCluster().resize(desiredSize); - } - - @Override - public String replaceMember(String memberId) { - return getCluster().replaceMember(memberId); - } - - /** - * @return the current size of the group. - */ - @Override - public Integer getCurrentSize() { - return getCluster().getCurrentSize(); - } - - @Override - public void deploy(String url, String targetName) { - DynamicWebAppClusterImpl.addToWarsByContext(this, url, targetName); - getCluster().deploy(url, targetName); - } - - @Override - public void undeploy(String targetName) { - DynamicWebAppClusterImpl.removeFromWarsByContext(this, targetName); - getCluster().undeploy(targetName); - } - - @Override - public void redeployAll() { - getCluster().redeployAll(); - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java deleted file mode 100644 index c1b027b..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import org.apache.brooklyn.catalog.Catalog; -import brooklyn.config.render.RendererHints; -import brooklyn.entity.group.DynamicCluster; -import brooklyn.entity.proxying.ImplementedBy; -import brooklyn.event.AttributeSensor; -import brooklyn.event.basic.BasicAttributeSensor; -import brooklyn.util.time.Duration; - -/** - * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes. Currently totals and averages: - * <ul> - * <li>Entity request counts</li> - * <li>Entity error counts</li> - * <li>Requests per second</li> - * <li>Entity processing time</li> - * </ul> - */ -@Catalog(name="Dynamic Web-app Cluster", description="A cluster of web-apps, which can be dynamically re-sized; this does not include a load-balancer") -@ImplementedBy(DynamicWebAppClusterImpl.class) -public interface DynamicWebAppCluster extends DynamicCluster, WebAppService, JavaWebAppService, - JavaWebAppService.CanDeployAndUndeploy, JavaWebAppService.CanRedeployAll { - - public static final AttributeSensor<Double> REQUEST_COUNT_PER_NODE = new BasicAttributeSensor<Double>( - Double.class, "webapp.reqs.total.perNode", "Cluster entity request average"); - - public static final AttributeSensor<Integer> ERROR_COUNT_PER_NODE = new BasicAttributeSensor<Integer>( - Integer.class, "webapp.reqs.errors.perNode", "Cluster entity request error average"); - - public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST_PER_NODE = new BasicAttributeSensor<Double>( - Double.class, "webapp.reqs.perSec.last.perNode", "Reqs/sec (last datapoint) averaged over all nodes"); - - public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE = new BasicAttributeSensor<Double>( - Double.class, "webapp.reqs.perSec.windowed.perNode", "Reqs/sec (over time window) averaged over all nodes"); - - public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = ApplyDisplayHints.TOTAL_PROCESSING_TIME_PER_NODE; - - public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW_PER_NODE = new BasicAttributeSensor<Double>( - Double.class, "webapp.reqs.processingTime.fraction.windowed.perNode", "Fraction of time spent processing " + - "reported by webserver (percentage, over time window) averaged over all nodes"); - - class ApplyDisplayHints { - public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = new BasicAttributeSensor<Integer>( - Integer.class, "webapp.reqs.processingTime.perNode", "Total processing time per node (millis)"); - static { - RendererHints.register(TOTAL_PROCESSING_TIME_PER_NODE, RendererHints.displayValue(Duration.millisToStringRounded())); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java deleted file mode 100644 index e364618..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; - -import org.apache.brooklyn.management.Task; -import org.apache.brooklyn.management.TaskAdaptable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.enricher.Enrichers; -import brooklyn.entity.Entity; -import brooklyn.entity.basic.Attributes; -import brooklyn.entity.basic.Entities; -import brooklyn.entity.basic.EntityInternal; -import brooklyn.entity.effector.Effectors; -import brooklyn.entity.group.DynamicCluster; -import brooklyn.entity.group.DynamicClusterImpl; -import brooklyn.event.AttributeSensor; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.collections.MutableSet; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.task.DynamicTasks; -import brooklyn.util.task.TaskBuilder; -import brooklyn.util.task.TaskTags; -import brooklyn.util.task.Tasks; -import brooklyn.util.time.Duration; -import brooklyn.util.time.Time; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; - -/** - * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes. Currently totals and averages: - * <ul> - * <li>Entity request counts</li> - * <li>Entity error counts</li> - * <li>Requests per second</li> - * <li>Entity processing time</li> - * </ul> - */ -public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster { - - private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class); - private static final FilenameToWebContextMapper FILENAME_TO_WEB_CONTEXT_MAPPER = new FilenameToWebContextMapper(); - - /** - * Instantiate a new DynamicWebAppCluster. Parameters as per {@link DynamicCluster#DynamicCluster()} - */ - public DynamicWebAppClusterImpl() { - super(); - } - - @Override - public void init() { - super.init(); - // Enricher attribute setup. A way of automatically discovering these (but avoiding - // averaging things like HTTP port and response codes) would be neat. - List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup = ImmutableList.of( - ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT), - ImmutableList.of(ERROR_COUNT, ERROR_COUNT), - ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST), - ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW), - ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME), - ImmutableList.of(PROCESSING_TIME_FRACTION_IN_WINDOW, PROCESSING_TIME_FRACTION_IN_WINDOW) - ); - - List<? extends List<? extends AttributeSensor<? extends Number>>> averagingEnricherSetup = ImmutableList.of( - ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT_PER_NODE), - ImmutableList.of(ERROR_COUNT, ERROR_COUNT_PER_NODE), - ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST_PER_NODE), - ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE), - ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME_PER_NODE), - ImmutableList.of(PROCESSING_TIME_FRACTION_IN_WINDOW, PROCESSING_TIME_FRACTION_IN_WINDOW_PER_NODE) - ); - - for (List<? extends AttributeSensor<? extends Number>> es : summingEnricherSetup) { - AttributeSensor<? extends Number> t = es.get(0); - AttributeSensor<? extends Number> total = es.get(1); - addEnricher(Enrichers.builder() - .aggregating(t) - .publishing(total) - .fromMembers() - .computingSum() - .build()); - } - - for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) { - @SuppressWarnings("unchecked") - AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0); - @SuppressWarnings("unchecked") - AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1); - addEnricher(Enrichers.builder() - .aggregating(t) - .publishing(average) - .fromMembers() - .computingAverage() - .defaultValueForUnreportedSensors(0) - .build()); - } - } - - // TODO this will probably be useful elsewhere ... but where to put it? - // TODO add support for this in DependentConfiguration (see TODO there) - /** Waits for the given target to report service up, then runs the given task - * (often an invocation on that entity), with the given name. - * If the target goes away, this task marks itself inessential - * before failing so as not to cause a parent task to fail. */ - static <T> Task<T> whenServiceUp(final Entity target, final TaskAdaptable<T> task, String name) { - return Tasks.<T>builder().name(name).dynamic(true).body(new Callable<T>() { - @Override - public T call() { - try { - while (true) { - if (!Entities.isManaged(target)) { - Tasks.markInessential(); - throw new IllegalStateException("Target "+target+" is no longer managed"); - } - if (Boolean.TRUE.equals(target.getAttribute(Attributes.SERVICE_UP))) { - Tasks.resetBlockingDetails(); - TaskTags.markInessential(task); - DynamicTasks.queue(task); - try { - return task.asTask().getUnchecked(); - } catch (Exception e) { - if (Entities.isManaged(target)) { - throw Exceptions.propagate(e); - } else { - Tasks.markInessential(); - throw new IllegalStateException("Target "+target+" is no longer managed", e); - } - } - } else { - Tasks.setBlockingDetails("Waiting on "+target+" to be ready"); - } - // TODO replace with subscription? - Time.sleep(Duration.ONE_SECOND); - } - } finally { - Tasks.resetBlockingDetails(); - } - } - }).build(); - } - - @Override - public void deploy(String url, String targetName) { - checkNotNull(url, "url"); - checkNotNull(targetName, "targetName"); - targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName); - - // set it up so future nodes get the right wars - addToWarsByContext(this, url, targetName); - - log.debug("Deploying "+targetName+"->"+url+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT)); - - Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class); - TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Deploy "+targetName+" to cluster (size "+Iterables.size(targets)+")"); - for (Entity target: targets) { - tb.add(whenServiceUp(target, Effectors.invocation(target, DEPLOY, MutableMap.of("url", url, "targetName", targetName)), - "Deploy "+targetName+" to "+target+" when ready")); - } - DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked(); - - // Update attribute - // TODO support for atomic sensor update (should be part of standard tooling; NB there is some work towards this, according to @aledsage) - Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS)); - deployedWars.add(targetName); - setAttribute(DEPLOYED_WARS, deployedWars); - } - - @Override - public void undeploy(String targetName) { - checkNotNull(targetName, "targetName"); - targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName); - - // set it up so future nodes get the right wars - if (!removeFromWarsByContext(this, targetName)) { - DynamicTasks.submit(Tasks.warning("Context "+targetName+" not known at "+this+"; attempting to undeploy regardless", null), this); - } - - log.debug("Undeploying "+targetName+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT)); - - Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class); - TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Undeploy "+targetName+" across cluster (size "+Iterables.size(targets)+")"); - for (Entity target: targets) { - tb.add(whenServiceUp(target, Effectors.invocation(target, UNDEPLOY, MutableMap.of("targetName", targetName)), - "Undeploy "+targetName+" at "+target+" when ready")); - } - DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked(); - - // Update attribute - Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS)); - deployedWars.remove( FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName) ); - setAttribute(DEPLOYED_WARS, deployedWars); - } - - static void addToWarsByContext(Entity entity, String url, String targetName) { - targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName); - // TODO a better way to do atomic updates, see comment above - synchronized (entity) { - Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT)); - newWarsMap.put(targetName, url); - ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap); - } - } - - static boolean removeFromWarsByContext(Entity entity, String targetName) { - targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName); - // TODO a better way to do atomic updates, see comment above - synchronized (entity) { - Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT)); - String url = newWarsMap.remove(targetName); - if (url==null) { - return false; - } - ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap); - return true; - } - } - - @Override - public void redeployAll() { - Map<String, String> wars = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT)); - String redeployPrefix = "Redeploy all WARs (count "+wars.size()+")"; - - log.debug("Redeplying all WARs across cluster "+this+": "+getConfig(WARS_BY_CONTEXT)); - - Iterable<CanDeployAndUndeploy> targetEntities = Iterables.filter(getChildren(), CanDeployAndUndeploy.class); - TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name(redeployPrefix+" across cluster (size "+Iterables.size(targetEntities)+")"); - for (Entity targetEntity: targetEntities) { - TaskBuilder<Void> redeployAllToTarget = Tasks.<Void>builder().name(redeployPrefix+" at "+targetEntity+" (after ready check)"); - for (String warContextPath: wars.keySet()) { - redeployAllToTarget.add(Effectors.invocation(targetEntity, DEPLOY, MutableMap.of("url", wars.get(warContextPath), "targetName", warContextPath))); - } - tb.add(whenServiceUp(targetEntity, redeployAllToTarget.build(), redeployPrefix+" at "+targetEntity+" when ready")); - } - DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java deleted file mode 100644 index ac60f86..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import brooklyn.entity.group.DynamicFabric; -import brooklyn.entity.proxying.ImplementedBy; -import brooklyn.event.AttributeSensor; -import brooklyn.event.basic.BasicAttributeSensor; - -/** - * DynamicWebAppFabric provide a fabric of clusters, aggregating the entity attributes. Currently totals and averages: - * <ul> - * <li>Entity request counts</li> - * <li>Entity error counts</li> - * <li>Requests per second</li> - * <li>Entity processing time</li> - * </ul> - */ -@ImplementedBy(DynamicWebAppFabricImpl.class) -public interface DynamicWebAppFabric extends DynamicFabric, WebAppService { - - public static final AttributeSensor<Double> REQUEST_COUNT_PER_NODE = new BasicAttributeSensor<Double>( - Double.class, "webapp.reqs.total.perNode", "Fabric entity request average"); - - public static final AttributeSensor<Integer> ERROR_COUNT_PER_NODE = new BasicAttributeSensor<Integer>( - Integer.class, "webapp.reqs.errors.perNode", "Fabric entity request error average"); - - public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST_PER_NODE = DynamicWebAppCluster.REQUESTS_PER_SECOND_LAST_PER_NODE; - public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE = DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE; - public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = DynamicWebAppCluster.TOTAL_PROCESSING_TIME_PER_NODE; - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java deleted file mode 100644 index 3a8d0be..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.List; - -import javax.annotation.Nullable; - -import brooklyn.enricher.Enrichers; -import brooklyn.entity.group.DynamicFabricImpl; -import brooklyn.event.AttributeSensor; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; - -public class DynamicWebAppFabricImpl extends DynamicFabricImpl implements DynamicWebAppFabric { - - @Override - public void onManagementBecomingMaster() { - // Enricher attribute setup. A way of automatically discovering these (but avoiding - // averaging things like HTTP port and response codes) would be neat. - List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup = ImmutableList.of( - ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT), - ImmutableList.of(ERROR_COUNT, ERROR_COUNT), - ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST), - ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW), - ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME) - ); - - List<? extends List<? extends AttributeSensor<? extends Number>>> averagingEnricherSetup = ImmutableList.of( - ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT_PER_NODE), - ImmutableList.of(ERROR_COUNT, ERROR_COUNT_PER_NODE), - ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST_PER_NODE), - ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE), - ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME_PER_NODE) - ); - - for (List<? extends AttributeSensor<? extends Number>> es : summingEnricherSetup) { - AttributeSensor<? extends Number> t = es.get(0); - AttributeSensor<? extends Number> total = es.get(1); - addEnricher(Enrichers.builder() - .aggregating(t) - .publishing(total) - .fromMembers() - .computingSum() - .build()); - } - - for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) { - @SuppressWarnings("unchecked") - AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0); - @SuppressWarnings("unchecked") - AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1); - - // TODO This needs to respond to changes in FABRIC_SIZE as well, to recalculate - addEnricher(Enrichers.builder() - .transforming(t) - .publishing(average) - .computing(new Function<Number, Double>() { - @Override public Double apply(@Nullable Number input) { - Integer size = getAttribute(DynamicWebAppFabric.FABRIC_SIZE); - return (size != null && input != null) ? (input.doubleValue() / size) : null; - }}) - .build()); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java deleted file mode 100644 index 89a1311..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.Map; - -import brooklyn.entity.Entity; -import brooklyn.entity.basic.AbstractConfigurableEntityFactory; -import brooklyn.entity.basic.ConfigurableEntityFactory; -import brooklyn.entity.basic.EntityFactoryForLocation; -import brooklyn.entity.proxying.EntitySpec; -import brooklyn.entity.trait.Startable; -import brooklyn.location.Location; -import brooklyn.location.MachineProvisioningLocation; - -public interface ElasticJavaWebAppService extends JavaWebAppService, Startable { - - public interface ElasticJavaWebAppServiceAwareLocation { - ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory(); - } - - /** @deprecated since 0.7.0 use {@link EntitySpec} */ - @Deprecated - public static class Factory extends AbstractConfigurableEntityFactory<ElasticJavaWebAppService> - implements EntityFactoryForLocation<ElasticJavaWebAppService> { - - private static final long serialVersionUID = 6654647949712073832L; - - public ElasticJavaWebAppService newEntity2(@SuppressWarnings("rawtypes") Map flags, Entity parent) { - return new ControlledDynamicWebAppClusterImpl(flags, parent); - } - - public ConfigurableEntityFactory<ElasticJavaWebAppService> newFactoryForLocation(Location l) { - if (l instanceof ElasticJavaWebAppServiceAwareLocation) { - return ((ElasticJavaWebAppServiceAwareLocation)l).newWebClusterFactory().configure(config); - } - //optional, fail fast if location not supported - if (!(l instanceof MachineProvisioningLocation)) - throw new UnsupportedOperationException("cannot create this entity in location "+l); - return this; - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java b/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java deleted file mode 100644 index 9bc99b8..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** utilities for translating consistently between a filename (http://acme.org/foo.war) and a web context path (/foo) */ -public class FilenameToWebContextMapper { - - public static final Logger log = LoggerFactory.getLogger(FilenameToWebContextMapper.class); - - public String findArchiveNameFromUrl(String url, boolean verbose) { - String name = url.substring(url.lastIndexOf('/') + 1); - if (name.indexOf("?")>0) { - Pattern p = Pattern.compile("[A-Za-z0-9_\\-]+\\..(ar|AR)($|(?=[^A-Za-z0-9_\\-]))"); - Matcher wars = p.matcher(name); - if (wars.find()) { - // take first such string - name = wars.group(); - if (wars.find()) { - if (verbose) log.warn("Not clear which archive to deploy for "+url+": using "+name); - } else { - if (verbose) log.info("Inferred archive to deploy for "+url+": using "+name); - } - } else { - if (verbose) log.warn("Not clear which archive to deploy for "+url+": using "+name); - } - } - return name; - } - - public String convertDeploymentTargetNameToFilename(String targetName) { - String result = targetName; - if (result.isEmpty()) return ""; - if (targetName.startsWith("/")) { - // treat input as a context - result = result.substring(1); - if (result.length()==0) result="ROOT"; - result += ".war"; - } else { - // treat input as a file, unless it has no dots in it - if (result.indexOf('.')==-1) result += ".war"; - } - return result; - } - - public String convertDeploymentTargetNameToContext(String targetName) { - String result = targetName; - if (result.isEmpty()) return ""; - if (targetName.startsWith("/")) { - // treat input as a context - noop - } else { - // make it look like a context - result = "/"+result; - if (result.indexOf('.')==-1) { - // no dot means no more processing - } else { - // look at extension - String extension = result.substring(result.lastIndexOf('.')+1).toUpperCase(); - if (extension.matches(".AR")) { - // looks like it was a WAR/EAR/etc - result = result.substring(0, result.length()-4); - if (result.equalsIgnoreCase("/ROOT")) result = "/"; - } else { - // input didn't look like a war filename, no more processing - } - } - } - return result; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java b/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java deleted file mode 100644 index cca69d0..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.Map; - -import brooklyn.util.guava.Maybe; - -public class HttpsSslConfig { - - private String keystoreUrl; - private String keystorePassword; - private String keyAlias; - - public HttpsSslConfig() { - } - - public HttpsSslConfig keystoreUrl(String val) { - keystoreUrl = val; return this; - } - - public HttpsSslConfig keystorePassword(String val) { - keystorePassword = val; return this; - } - - public HttpsSslConfig keyAlias(String val) { - keyAlias = val; return this; - } - - public String getKeystoreUrl() { - return keystoreUrl; - } - - public String getKeystorePassword() { - return keystorePassword; - } - - public String getKeyAlias() { - return keyAlias; - } - - // method naming convention allows it to be used by TypeCoercions - public static HttpsSslConfig fromMap(Map<String,String> map) { - HttpsSslConfig result = new HttpsSslConfig(); - result.keystoreUrl = first(map, "keystoreUrl", "url").orNull(); - result.keystorePassword = first(map, "keystorePassword", "password").orNull(); - result.keyAlias = first(map, "keyAlias", "alias", "key").orNull(); - return result; - } - - private static Maybe<String> first(Map<String,String> map, String ...keys) { - for (String key: keys) { - if (map.containsKey(key)) - return Maybe.of(map.get(key)); - } - return Maybe.<String>absent(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java deleted file mode 100644 index f355555..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.io.File; -import java.util.Set; - -import brooklyn.entity.java.JavaSoftwareProcessDriver; - -public interface JavaWebAppDriver extends JavaSoftwareProcessDriver { - - Set<String> getEnabledProtocols(); - - Integer getHttpPort(); - - Integer getHttpsPort(); - - HttpsSslConfig getHttpsSslConfig(); - - void deploy(File file); - - void deploy(File f, String targetName); - - /** - * Deploys a URL as a webapp at the appserver. - * <p> - * See {@link JavaWebAppSoftwareProcess#deploy(String, String)} for details of how input filenames are handled. - * - * @return A token which can be used as an argument to undeploy. - * Typically the web context with leading slash where the app can be reached (just "/" for ROOT) - */ - String deploy(String url, String targetName); - - void undeploy(String targetName); - - FilenameToWebContextMapper getFilenameContextMapper(); - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java deleted file mode 100644 index 52b090d..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import brooklyn.config.ConfigKey; -import brooklyn.entity.Entity; -import brooklyn.entity.annotation.Effector; -import brooklyn.entity.annotation.EffectorParam; -import brooklyn.entity.basic.MethodEffector; -import brooklyn.entity.java.UsesJava; -import brooklyn.event.AttributeSensor; -import brooklyn.event.basic.BasicAttributeSensor; -import brooklyn.event.basic.BasicConfigKey; -import brooklyn.util.flags.SetFromFlag; - -public interface JavaWebAppService extends WebAppService, UsesJava { - - @SetFromFlag("war") - public static final ConfigKey<String> ROOT_WAR = new BasicConfigKey<String>( - String.class, "wars.root", "WAR file to deploy as the ROOT, as URL (supporting file: and classpath: prefixes)"); - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @SetFromFlag("wars") - public static final ConfigKey<List<String>> NAMED_WARS = new BasicConfigKey( - List.class, "wars.named", "Archive files to deploy, as URL strings (supporting file: and classpath: prefixes); context (path in user-facing URL) will be inferred by name"); - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @SetFromFlag("warsByContext") - public static final ConfigKey<Map<String,String>> WARS_BY_CONTEXT = new BasicConfigKey( - Map.class, "wars.by.context", "Map of context keys (path in user-facing URL, typically without slashes) to archives (e.g. WARs by URL) to deploy, supporting file: and classpath: prefixes)"); - - /** Optional marker interface for entities which support 'deploy' and 'undeploy' */ - public interface CanDeployAndUndeploy extends Entity { - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static final AttributeSensor<Set<String>> DEPLOYED_WARS = new BasicAttributeSensor( - Set.class, "webapp.deployedWars", "Names of archives/contexts that are currently deployed"); - - public static final MethodEffector<Void> DEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "deploy"); - public static final MethodEffector<Void> UNDEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "undeploy"); - - /** - * Deploys the given artifact, from a source URL, to a given deployment filename/context. - * There is some variance in expected filename/context at various servers, - * so the following conventions are followed: - * <p> - * either ROOT.WAR or / denotes root context - * <p> - * anything of form FOO.?AR (ending .?AR) is copied with that name (unless copying not necessary) - * and is expected to be served from /FOO - * <p> - * anything of form /FOO (with leading slash) is expected to be served from /FOO - * (and is copied as FOO.WAR) - * <p> - * anything of form FOO (without a dot) is expected to be served from /FOO - * (and is copied as FOO.WAR) - * <p> - * otherwise <i>please note</i> behaviour may vary on different appservers; - * e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually), - * but served as /FOO.FOO on systems that take a deployment context. - * <p> - * See {@link FileNameToContextMappingTest} for definitive examples! - * - * @param url where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)... - * @param targetName where to tell the server to serve the WAR, see above - */ - @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context") - public void deploy( - @EffectorParam(name="url", description="URL of WAR file") String url, - @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName); - - /** - * For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy, - * e.g. the transformed name using - */ - @Effector(description="Undeploys the given context/artifact") - public void undeploy( - @EffectorParam(name="targetName") String targetName); - } - - /** Optional marker interface for entities which support 'redeployAll' */ - public interface CanRedeployAll { - public static final MethodEffector<Void> REDEPLOY_ALL = new MethodEffector<Void>(CanRedeployAll.class, "redeployAll"); - - @Effector(description="Redeploys all web apps known here across the cluster (e.g. if it gets into an inconsistent state)") - public void redeployAll(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java deleted file mode 100644 index bbeead2..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import brooklyn.entity.basic.SoftwareProcess; - -public interface JavaWebAppSoftwareProcess extends SoftwareProcess, JavaWebAppService, JavaWebAppService.CanDeployAndUndeploy { - - // exist on the interface for freemarker to pick it up - - public boolean isHttpEnabled(); - public boolean isHttpsEnabled(); - public Integer getHttpPort(); - public Integer getHttpsPort(); - public String getHttpsSslKeyAlias(); - public String getHttpsSslKeystorePassword(); - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java deleted file mode 100644 index 209d3fe..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.entity.Entity; -import brooklyn.entity.annotation.Effector; -import brooklyn.entity.annotation.EffectorParam; -import brooklyn.entity.basic.SoftwareProcessImpl; -import brooklyn.entity.java.JavaAppUtils; - -import com.google.common.base.Throwables; -import com.google.common.collect.Sets; - -public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl implements JavaWebAppService, JavaWebAppSoftwareProcess { - - private static final Logger LOG = LoggerFactory.getLogger(JavaWebAppSoftwareProcessImpl.class); - - public JavaWebAppSoftwareProcessImpl(){ - super(); - } - - @SuppressWarnings("rawtypes") - public JavaWebAppSoftwareProcessImpl(Entity parent){ - this(new LinkedHashMap(),parent); - } - - @SuppressWarnings("rawtypes") - public JavaWebAppSoftwareProcessImpl(Map flags){ - this(flags, null); - } - - @SuppressWarnings("rawtypes") - public JavaWebAppSoftwareProcessImpl(Map flags, Entity parent) { - super(flags, parent); - } - - @Override - public void init() { - super.init(); - - WebAppServiceMethods.connectWebAppServerPolicies(this); - JavaAppUtils.connectJavaAppServerPolicies(this); - } - - //just provide better typing - public JavaWebAppDriver getDriver() { - return (JavaWebAppDriver) super.getDriver(); - } - - // TODO thread-safety issues: if multiple concurrent calls, may break (e.g. deployment_wars being reset) - public void deployInitialWars() { - if (getAttribute(DEPLOYED_WARS) == null) setAttribute(DEPLOYED_WARS, Sets.<String>newLinkedHashSet()); - - String rootWar = getConfig(ROOT_WAR); - if (rootWar!=null) deploy(rootWar, "ROOT.war"); - - List<String> namedWars = getConfig(NAMED_WARS, Collections.<String>emptyList()); - for(String war: namedWars){ - deploy(war, getDriver().getFilenameContextMapper().findArchiveNameFromUrl(war, true)); - } - - Map<String,String> warsByContext = getConfig(WARS_BY_CONTEXT); - if (warsByContext!=null) { - for (String context: warsByContext.keySet()) { - deploy(warsByContext.get(context), context); - } - } - } - - /** - * Deploys the given artifact, from a source URL, to a given deployment filename/context. - * There is some variance in expected filename/context at various servers, - * so the following conventions are followed: - * <p> - * either ROOT.WAR or / denotes root context - * <p> - * anything of form FOO.?AR (ending .?AR) is copied with that name (unless copying not necessary) - * and is expected to be served from /FOO - * <p> - * anything of form /FOO (with leading slash) is expected to be served from /FOO - * (and is copied as FOO.WAR) - * <p> - * anything of form FOO (without a dot) is expected to be served from /FOO - * (and is copied as FOO.WAR) - * <p> - * otherwise <i>please note</i> behaviour may vary on different appservers; - * e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually), - * but served as /FOO.FOO on systems that take a deployment context. - * <p> - * See {@link FileNameToContextMappingTest} for definitive examples! - * - * @param url where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)... - * @param targetName where to tell the server to serve the WAR, see above - */ - @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context") - public void deploy( - @EffectorParam(name="url", description="URL of WAR file") String url, - @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) { - try { - checkNotNull(url, "url"); - checkNotNull(targetName, "targetName"); - JavaWebAppDriver driver = getDriver(); - String deployedName = driver.deploy(url, targetName); - - // Update attribute - Set<String> deployedWars = getAttribute(DEPLOYED_WARS); - if (deployedWars == null) { - deployedWars = Sets.newLinkedHashSet(); - } - deployedWars.add(deployedName); - setAttribute(DEPLOYED_WARS, deployedWars); - } catch (RuntimeException e) { - // Log and propagate, so that log says which entity had problems... - LOG.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e); - throw Throwables.propagate(e); - } - } - - /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */ - @Override - @Effector(description="Undeploys the given context/artifact") - public void undeploy( - @EffectorParam(name="targetName") String targetName) { - try { - JavaWebAppDriver driver = getDriver(); - driver.undeploy(targetName); - - // Update attribute - Set<String> deployedWars = getAttribute(DEPLOYED_WARS); - if (deployedWars == null) { - deployedWars = Sets.newLinkedHashSet(); - } - deployedWars.remove( driver.getFilenameContextMapper().convertDeploymentTargetNameToContext(targetName) ); - setAttribute(DEPLOYED_WARS, deployedWars); - } catch (RuntimeException e) { - // Log and propagate, so that log says which entity had problems... - LOG.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e); - throw Throwables.propagate(e); - } - } - - @Override - protected void postStop() { - super.postStop(); - // zero our workrate derived workrates. - // TODO might not be enough, as policy may still be executing and have a record of historic vals; should remove policies - // (also not sure we want this; implies more generally a responsibility for sensors to announce things when disconnected, - // vs them just showing the last known value...) - setAttribute(REQUESTS_PER_SECOND_LAST, 0D); - setAttribute(REQUESTS_PER_SECOND_IN_WINDOW, 0D); - } - - public boolean isHttpEnabled() { - return WebAppServiceMethods.isProtocolEnabled(this, "HTTP"); - } - - public boolean isHttpsEnabled() { - return WebAppServiceMethods.isProtocolEnabled(this, "HTTPS"); - } - - public Integer getHttpPort() { - return getAttribute(HTTP_PORT); - } - - public Integer getHttpsPort() { - return getAttribute(HTTPS_PORT); - } - - public String getHttpsSslKeyAlias() { - HttpsSslConfig config = getAttribute(HTTPS_SSL_CONFIG); - return (config == null) ? null : config.getKeyAlias(); - } - - public String getHttpsSslKeystorePassword() { - HttpsSslConfig config = getAttribute(HTTPS_SSL_CONFIG); - return (config == null) ? "" : config.getKeystorePassword(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java deleted file mode 100644 index cd32b01..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.io.File; -import java.net.URI; -import java.util.Set; - -import brooklyn.entity.basic.Attributes; -import brooklyn.entity.java.JavaSoftwareProcessSshDriver; -import brooklyn.location.basic.SshMachineLocation; -import brooklyn.util.task.DynamicTasks; -import brooklyn.util.task.Tasks; -import brooklyn.util.task.ssh.SshTasks; -import brooklyn.util.text.Strings; - -import com.google.common.collect.ImmutableList; - -public abstract class JavaWebAppSshDriver extends JavaSoftwareProcessSshDriver implements JavaWebAppDriver { - - public JavaWebAppSshDriver(JavaWebAppSoftwareProcessImpl entity, SshMachineLocation machine) { - super(entity, machine); - } - - public JavaWebAppSoftwareProcessImpl getEntity() { - return (JavaWebAppSoftwareProcessImpl) super.getEntity(); - } - - protected boolean isProtocolEnabled(String protocol) { - Set<String> protocols = getEnabledProtocols(); - for (String contender : protocols) { - if (protocol.equalsIgnoreCase(contender)) { - return true; - } - } - return false; - } - - @Override - public Set<String> getEnabledProtocols() { - return entity.getAttribute(JavaWebAppSoftwareProcess.ENABLED_PROTOCOLS); - } - - @Override - public Integer getHttpPort() { - return entity.getAttribute(Attributes.HTTP_PORT); - } - - @Override - public Integer getHttpsPort() { - return entity.getAttribute(Attributes.HTTPS_PORT); - } - - @Override - public HttpsSslConfig getHttpsSslConfig() { - return entity.getAttribute(WebAppServiceConstants.HTTPS_SSL_CONFIG); - } - - protected String getSslKeystoreUrl() { - HttpsSslConfig ssl = getHttpsSslConfig(); - return (ssl == null) ? null : ssl.getKeystoreUrl(); - } - - protected String getSslKeystorePassword() { - HttpsSslConfig ssl = getHttpsSslConfig(); - return (ssl == null) ? null : ssl.getKeystorePassword(); - } - - protected String getSslKeyAlias() { - HttpsSslConfig ssl = getHttpsSslConfig(); - return (ssl == null) ? null : ssl.getKeyAlias(); - } - - protected String inferRootUrl() { - if (isProtocolEnabled("https")) { - Integer port = getHttpsPort(); - checkNotNull(port, "HTTPS_PORT sensors not set; is an acceptable port available?"); - return String.format("https://%s:%s/", getSubnetHostname(), port); - } else if (isProtocolEnabled("http")) { - Integer port = getHttpPort(); - checkNotNull(port, "HTTP_PORT sensors not set; is an acceptable port available?"); - return String.format("http://%s:%s/", getSubnetHostname(), port); - } else { - throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols()); - } - } - - @Override - public void postLaunch() { - String rootUrl = inferRootUrl(); - entity.setAttribute(Attributes.MAIN_URI, URI.create(rootUrl)); - entity.setAttribute(WebAppService.ROOT_URL, rootUrl); - } - - /** - * if files should be placed on the server for deployment, - * override this to be the sub-directory of the runDir where they should be stored - * (or override getDeployDir() if they should be copied somewhere else, - * and set this null); - * if files are not copied to the server, but injected (e.g. JMX or uploaded) - * then override {@link #deploy(String, String)} as appropriate, - * using getContextFromDeploymentTargetName(targetName) - * and override this to return null - */ - protected abstract String getDeploySubdir(); - - protected String getDeployDir() { - if (getDeploySubdir()==null) - throw new IllegalStateException("no deployment directory available for "+this); - return getRunDir() + "/" + getDeploySubdir(); - } - - @Override - public void deploy(File file) { - deploy(file, null); - } - - @Override - public void deploy(File f, String targetName) { - if (targetName == null) { - targetName = f.getName(); - } - deploy(f.toURI().toASCIIString(), targetName); - } - - /** - * Deploys a URL as a webapp at the appserver. - * - * Returns a token which can be used as an argument to undeploy, - * typically the web context with leading slash where the app can be reached (just "/" for ROOT) - * - * @see JavaWebAppSoftwareProcess#deploy(String, String) for details of how input filenames are handled - */ - @Override - public String deploy(final String url, final String targetName) { - final String canonicalTargetName = getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName); - final String dest = getDeployDir() + "/" + canonicalTargetName; - //write to a .tmp so autodeploy is not triggered during upload - final String tmpDest = dest + "." + Strings.makeRandomId(8) + ".tmp"; - final String msg = String.format("deploying %s to %s:%s", new Object[]{url, getHostname(), dest}); - log.info(entity + " " + msg); - Tasks.setBlockingDetails(msg); - try { - final String copyTaskMsg = String.format("copying %s to %s:%s", new Object[]{url, getHostname(), tmpDest}); - DynamicTasks.queue(copyTaskMsg, new Runnable() { - @Override - public void run() { - int result = copyResource(url, tmpDest); - if (result != 0) { - throw new IllegalStateException("Invalud result " + result + " while " + copyTaskMsg); - } - } - }); - - // create a backup - DynamicTasks.queue(SshTasks.newSshExecTaskFactory(getMachine(), String.format("mv -f %s %s.bak", dest, dest)) - .allowingNonZeroExitCode()); - - //rename temporary upload file to .war to be picked up for deployment - DynamicTasks.queue(SshTasks.newSshExecTaskFactory(getMachine(), String.format("mv -f %s %s", tmpDest, dest)) - .requiringExitCodeZero()); - log.debug("{} deployed {} to {}:{}", new Object[]{entity, url, getHostname(), dest}); - - DynamicTasks.waitForLast(); - } finally { - Tasks.resetBlockingDetails(); - } - return getFilenameContextMapper().convertDeploymentTargetNameToContext(canonicalTargetName); - } - - @Override - public void undeploy(String targetName) { - String dest = getDeployDir() + "/" + getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName); - log.info("{} undeploying {}:{}", new Object[]{entity, getHostname(), dest}); - int result = getMachine().execCommands("removing war on undeploy", ImmutableList.of(String.format("rm -f %s", dest))); - log.debug("{} undeployed {}:{}: result {}", new Object[]{entity, getHostname(), dest, result}); - } - - @Override - public FilenameToWebContextMapper getFilenameContextMapper() { - return new FilenameToWebContextMapper(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java deleted file mode 100644 index 8aeaec6..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import brooklyn.entity.Entity; - -public interface WebAppService extends WebAppServiceConstants, Entity { -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java deleted file mode 100644 index 68ba9ae..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import java.util.Set; - -import com.google.common.collect.ImmutableSet; - -import brooklyn.config.render.RendererHints; -import brooklyn.entity.basic.Attributes; -import brooklyn.event.AttributeSensor; -import brooklyn.event.basic.BasicAttributeSensorAndConfigKey; -import brooklyn.event.basic.PortAttributeSensorAndConfigKey; -import brooklyn.event.basic.Sensors; -import brooklyn.util.flags.SetFromFlag; - -public interface WebAppServiceConstants extends WebAppServiceMetrics { - - @SetFromFlag("httpPort") - public static final PortAttributeSensorAndConfigKey HTTP_PORT = Attributes.HTTP_PORT; - - @SetFromFlag("httpsPort") - public static final PortAttributeSensorAndConfigKey HTTPS_PORT = Attributes.HTTPS_PORT; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @SetFromFlag("enabledProtocols") - public static final BasicAttributeSensorAndConfigKey<Set<String>> ENABLED_PROTOCOLS = new BasicAttributeSensorAndConfigKey( - Set.class, "webapp.enabledProtocols", "List of enabled protocols (e.g. http, https)", ImmutableSet.of("http")); - - @SetFromFlag("httpsSsl") - public static final BasicAttributeSensorAndConfigKey<HttpsSslConfig> HTTPS_SSL_CONFIG = new BasicAttributeSensorAndConfigKey<HttpsSslConfig>( - HttpsSslConfig.class, "webapp.https.ssl", "SSL Configuration for HTTPS", null); - - public static final AttributeSensor<String> ROOT_URL = RootUrl.ROOT_URL; - -} - -// this class is added because the ROOT_URL relies on a static initialization which unfortunately can't be added to an interface. -class RootUrl { - public static final AttributeSensor<String> ROOT_URL = Sensors.newStringSensor("webapp.url", "URL"); - - static { - RendererHints.register(ROOT_URL, RendererHints.namedActionWithUrl()); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java ---------------------------------------------------------------------- diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java deleted file mode 100644 index c6fbe29..0000000 --- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 - * 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 brooklyn.entity.webapp; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import brooklyn.enricher.RollingTimeWindowMeanEnricher; -import brooklyn.enricher.TimeFractionDeltaEnricher; -import brooklyn.enricher.TimeWeightedDeltaEnricher; -import brooklyn.entity.Entity; -import brooklyn.entity.basic.EntityLocal; -import brooklyn.location.access.BrooklynAccessUtils; -import brooklyn.util.time.Duration; - -import com.google.common.net.HostAndPort; - -public class WebAppServiceMethods implements WebAppServiceConstants { - - public static final Duration DEFAULT_WINDOW_DURATION = Duration.TEN_SECONDS; - - public static void connectWebAppServerPolicies(EntityLocal entity) { - connectWebAppServerPolicies(entity, DEFAULT_WINDOW_DURATION); - } - - public static void connectWebAppServerPolicies(EntityLocal entity, Duration windowPeriod) { - entity.addEnricher(TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(entity, REQUEST_COUNT, REQUESTS_PER_SECOND_LAST)); - - if (windowPeriod!=null) { - entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, REQUESTS_PER_SECOND_LAST, - REQUESTS_PER_SECOND_IN_WINDOW, windowPeriod)); - } - - entity.addEnricher(new TimeFractionDeltaEnricher<Integer>(entity, TOTAL_PROCESSING_TIME, PROCESSING_TIME_FRACTION_LAST, TimeUnit.MILLISECONDS)); - - if (windowPeriod!=null) { - entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, PROCESSING_TIME_FRACTION_LAST, - PROCESSING_TIME_FRACTION_IN_WINDOW, windowPeriod)); - } - - } - - public static Set<String> getEnabledProtocols(Entity entity) { - return entity.getAttribute(WebAppService.ENABLED_PROTOCOLS); - } - - public static boolean isProtocolEnabled(Entity entity, String protocol) { - for (String contender : getEnabledProtocols(entity)) { - if (protocol.equalsIgnoreCase(contender)) { - return true; - } - } - return false; - } - - public static String inferBrooklynAccessibleRootUrl(Entity entity) { - if (isProtocolEnabled(entity, "https")) { - Integer rawPort = entity.getAttribute(HTTPS_PORT); - checkNotNull(rawPort, "HTTPS_PORT sensors not set for %s; is an acceptable port available?", entity); - HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort); - return String.format("https://%s:%s/", hp.getHostText(), hp.getPort()); - } else if (isProtocolEnabled(entity, "http")) { - Integer rawPort = entity.getAttribute(HTTP_PORT); - checkNotNull(rawPort, "HTTP_PORT sensors not set for %s; is an acceptable port available?", entity); - HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort); - return String.format("http://%s:%s/", hp.getHostText(), hp.getPort()); - } else { - throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols(entity)); - } - } -}
