/**
* 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.camel.component.openshift;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.openshift.client.IApplication;
import com.openshift.client.IDomain;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.impl.ScheduledPollConsumer;
public class OpenShiftConsumer extends ScheduledPollConsumer {
// lets by default poll every 10 sec
private static final long INITIAL_DELAY = 1 * 1000L;
private static final long DELAY = 10 * 1000L;
private final Map<ApplicationState, ApplicationState> oldState = new HashMap<ApplicationState, ApplicationState>();
private volatile boolean initialPoll;
public OpenShiftConsumer(Endpoint endpoint, Processor processor) {
super(endpoint, processor);
setInitialDelay(INITIAL_DELAY);
setDelay(DELAY);
}
@Override
public OpenShiftEndpoint getEndpoint() {
return (OpenShiftEndpoint) super.getEndpoint();
}
@Override
protected void doStart() throws Exception {
initialPoll = true;
super.doStart();
}
@Override
protected int poll() throws Exception {
String openshiftServer = OpenShiftHelper.getOpenShiftServer(getEndpoint());
IDomain domain = OpenShiftHelper.loginAndGetDomain(getEndpoint(), openshiftServer);
if (domain == null) {
return 0;
}
return doPollOnChange(domain);
}
protected int doPollAll(IDomain domain) {
List<IApplication> apps = domain.getApplications();
for (IApplication app : apps) {
Exchange exchange = getEndpoint().createExchange(app);
try {
getProcessor().process(exchange);
} catch (Exception e) {
exchange.setException(e);
}
if (exchange.getException() != null) {
getExceptionHandler().handleException("Error during processing exchange.", exchange, exchange.getException());
}
}
return apps.size();
}
protected int doPollOnChange(IDomain domain) {
// an app can either be
// - added
// - removed
// - state changed
Map<ApplicationState, ApplicationState> newState = new HashMap<ApplicationState, ApplicationState>();
List<IApplication> apps = domain.getApplications();
for (IApplication app : apps) {
ApplicationState state = new ApplicationState(app.getUUID(), app, OpenShiftHelper.getStateForApplication(app));
newState.put(state, state);
}
// compute what is the delta from last time
// so we split up into 3 groups, of added/removed/changed
Map<ApplicationState, ApplicationState> added = new HashMap<ApplicationState, ApplicationState>();
Map<ApplicationState, ApplicationState> removed = new HashMap<ApplicationState, ApplicationState>();
Map<ApplicationState, ApplicationState> changed = new HashMap<ApplicationState, ApplicationState>();
for (ApplicationState state : newState.keySet()) {
if (!oldState.containsKey(state)) {
// its a new app added
added.put(state, state);
} else {
ApplicationState old = oldState.get(state);
if (old != null && !old.getState().equals(state.getState())) {
// the state changed
state.setOldState(old.getState());
changed.put(state, state);
}
}
}
for (ApplicationState state : oldState.keySet()) {
if (!newState.containsKey(state)) {
// its a app removed
removed.put(state, state);
}
}
// only start emitting events after first init poll
int processed = 0;
if (!initialPoll) {
for (ApplicationState add : added.keySet()) {
Exchange exchange = getEndpoint().createExchange(add.getApplication());
exchange.getIn().setHeader(OpenShiftConstants.EVENT_TYPE, "added");
try {
processed++;
getProcessor().process(exchange);
} catch (Exception e) {
exchange.setException(e);
}
if (exchange.getException() != null) {
getExceptionHandler().handleException("Error during processing exchange.", exchange, exchange.getException());
}
}
for (ApplicationState remove : removed.keySet()) {
Exchange exchange = getEndpoint().createExchange(remove.getApplication());
exchange.getIn().setHeader(OpenShiftConstants.EVENT_TYPE, "removed");
try {
processed++;
getProcessor().process(exchange);
} catch (Exception e) {
exchange.setException(e);
}
if (exchange.getException() != null) {
getExceptionHandler().handleException("Error during processing exchange.", exchange, exchange.getException());
}
}
for (ApplicationState change : changed.keySet()) {
Exchange exchange = getEndpoint().createExchange(change.getApplication());
exchange.getIn().setHeader(OpenShiftConstants.EVENT_TYPE, "changed");
exchange.getIn().setHeader(OpenShiftConstants.EVENT_OLD_STATE, change.getOldState());
exchange.getIn().setHeader(OpenShiftConstants.EVENT_NEW_STATE, change.getState());
try {
processed++;
getProcessor().process(exchange);
} catch (Exception e) {
exchange.setException(e);
}
if (exchange.getException() != null) {
getExceptionHandler().handleException("Error during processing exchange.", exchange, exchange.getException());
}
}
}
// update old state with latest state for next poll
oldState.clear();
oldState.putAll(newState);
initialPoll = false;
return processed;
}
private static final class ApplicationState {
private final String uuid;
private final IApplication application;
private final String state;
private String oldState;
private ApplicationState(String uuid, IApplication application, String state) {
this.uuid = uuid;
this.application = application;
this.state = state;
}
public String getUuid() {
return uuid;
}
public IApplication getApplication() {
return application;
}
public String getState() {
return state;
}
public String getOldState() {
return oldState;
}
public void setOldState(String oldState) {
this.oldState = oldState;
}
// only use uuid and state for equals as that is what we want to use for state change detection
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ApplicationState that = (ApplicationState) o;
if (!state.equals(that.state)) {
return false;
}
if (!uuid.equals(that.uuid)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = uuid.hashCode();
result = 31 * result + state.hashCode();
return result;
}
}
}