/* * 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 org.apache.brooklyn.core.entity.lifecycle; import java.io.Serializable; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.core.config.render.RendererHints; import org.apache.brooklyn.core.entity.trait.Startable; import org.apache.brooklyn.util.core.flags.TypeCoercions; import org.apache.brooklyn.util.text.StringFunctions; import com.google.common.base.CaseFormat; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Preconditions; /** * An enumeration representing the status of an {@link org.apache.brooklyn.api.entity.Entity}. */ public enum Lifecycle { /** * The entity has just been created. * * This stage encompasses the contruction. Once this stage is * complete, the basic set of sensors will be available, apart from any that require the entity to be active or * deployed to a {@link Location}. */ CREATED, /** * The entity is starting. * <p> * This stage is typically entered when the {@link Startable#START} effector * is called, to undertake the startup operations from the management plane. * When this completes the entity will normally transition to * {@link Lifecycle#RUNNING}. */ STARTING, /** * The entity service is expected to be running. In healthy operation, {@link Attributes#SERVICE_UP} will be true, * or will shortly be true if all service start actions have been completed and we are merely waiting for it to be running. */ RUNNING, /** * The entity is stopping. * * This stage is activated when the * {@link Startable#STOP} effector is called. The entity service is stopped. * Sensors that provide data from the running entity may be cleared and subscriptions cancelled. */ STOPPING, /** * The entity is not expected to be active. * * This stage is entered when an entity is stopped, or may be entered when an entity is * fully created but not started. It may or may not be removed from the location(s) it was assigned, * and it will typically not be providing new sensor data apart. */ STOPPED, /** * The entity is destroyed. * * The entity will be unmanaged and removed from any groups and from its parent. */ DESTROYED, /** * Entity error state. * * This stage is reachable from any other stage if an error occurs or an exception is thrown. */ ON_FIRE; /** * The text representation of the {@link #name()}. * * This is formatted as lower case characters, with hyphens instead of spaces. */ public String value() { return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()); } /** @see #value() */ @Override public String toString() { return value(); } /** * Creates a {@link Lifecycle} from a text representation. * * This accepts the text representations output by the {@link #value()} method for each entry. * * @see #value() */ public static Lifecycle fromValue(String v) { try { return valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, v)); } catch (IllegalArgumentException iae) { return ON_FIRE; } } public static class Transition implements Serializable { private static final long serialVersionUID = 603419184398753502L; final Lifecycle state; final long timestampUtc; public Transition(Lifecycle state, Date timestamp) { this.state = Preconditions.checkNotNull(state, "state"); this.timestampUtc = Preconditions.checkNotNull(timestamp, "timestamp").getTime(); } public Lifecycle getState() { return state; } public Date getTimestamp() { return new Date(timestampUtc); } @Override public int hashCode() { return Objects.hashCode(state, timestampUtc); } @Override public boolean equals(Object obj) { if (!(obj instanceof Transition)) return false; if (!state.equals(((Transition)obj).getState())) return false; if (timestampUtc != ((Transition)obj).timestampUtc) return false; return true; } @Override public String toString() { return state+" @ "+timestampUtc+" / "+new Date(timestampUtc); } } protected static class TransitionCoalesceFunction implements Function<String, Transition> { private static final Pattern TRANSITION_PATTERN = Pattern.compile("^([\\w-]+)\\s+@\\s+(\\d+).*"); @Override public Transition apply(final String input) { if (input != null) { Matcher m = TRANSITION_PATTERN.matcher(input); if (m.matches()) { Lifecycle state = Lifecycle.valueOf(m.group(1).toUpperCase().replace('-', '_')); long time = Long.parseLong(m.group(2)); return new Transition(state, new Date(time)); } else { throw new IllegalStateException("Serialized Lifecycle.Transition can't be parsed: " + input); } } else { return null; } } } static { TypeCoercions.registerAdapter(String.class, Transition.class, new TransitionCoalesceFunction()); RendererHints.register(Transition.class, RendererHints.displayValue(StringFunctions.toStringFunction())); } }