001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.blueprint; 018 019import java.util.LinkedHashMap; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.ConcurrentHashMap; 024 025import org.osgi.framework.Bundle; 026import org.osgi.framework.BundleContext; 027import org.osgi.framework.ServiceRegistration; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031/** 032 * Used by {@link BlueprintCamelContext} to inform about state of Camel context. If running inside Karaf 033 * and Karaf's BundleStateService is accessible, Camel context state will propagate as <em>extended 034 * bundle state</em>. 035 */ 036public class BlueprintCamelStateService { 037 038 public static final Logger LOG = LoggerFactory.getLogger(BlueprintCamelStateService.class); 039 040 public enum State { 041 Starting, 042 Active, 043 Failure 044 } 045 046 private Map<String, State> states; 047 private Map<String, Throwable> exceptions; 048 049 private BundleContext bundleContext; 050 051 private ServiceRegistration<?> registration; 052 public BundleContext getBundleContext() { 053 return bundleContext; 054 } 055 056 public void setBundleContext(BundleContext bundleContext) { 057 this.bundleContext = bundleContext; 058 } 059 060 /** 061 * One of four {@link State states} is set for given {@link org.osgi.framework.Bundle} and context Id. 062 * One (blueprint) bundle may declare one or more Camel context. 063 * @param contextId 064 * @param state 065 */ 066 public void setBundleState(Bundle bundle, String contextId, State state) { 067 setBundleState(bundle, contextId, state, null); 068 } 069 070 /** 071 * One of four {@link State states} is set for given {@link org.osgi.framework.Bundle} and context Id. 072 * One (blueprint) bundle may declare one or more Camel context. 073 * @param contextId 074 * @param state 075 * @param t 076 */ 077 public void setBundleState(Bundle bundle, String contextId, State state, Throwable t) { 078 if (state == State.Failure) { 079 LOG.warn("Changing Camel state for bundle {} to {}", bundle.getBundleId(), state); 080 } else if (LOG.isDebugEnabled()) { 081 LOG.debug("Changing Camel state for bundle {} to {}", bundle.getBundleId(), state); 082 } 083 084 String key = String.format("%d:%s", bundle.getBundleId(), contextId); 085 if (state != null) { 086 states.put(key, state); 087 } else { 088 states.remove(key); 089 } 090 if (t != null) { 091 exceptions.put(key, t); 092 } else { 093 exceptions.remove(key); 094 } 095 } 096 097 /** 098 * Get states for all context registered for given {@link Bundle} 099 * @param bundle 100 * @return 101 */ 102 public List<State> getStates(Bundle bundle) { 103 List<State> result = new LinkedList<>(); 104 for (Map.Entry<String, State> e : states.entrySet()) { 105 if (e.getKey().startsWith(bundle.getBundleId() + ":")) { 106 result.add(e.getValue()); 107 } 108 } 109 return result; 110 } 111 112 /** 113 * Get exceptions for all camel contexts for given bundle 114 * @param bundle 115 * @return 116 */ 117 public Map<String, Throwable> getExceptions(Bundle bundle) { 118 Map<String, Throwable> result = new LinkedHashMap<>(); 119 for (Map.Entry<String, Throwable> e : exceptions.entrySet()) { 120 if (e.getKey().startsWith(bundle.getBundleId() + ":")) { 121 result.put(e.getKey().substring(e.getKey().indexOf(":") + 1), e.getValue()); 122 } 123 } 124 return result; 125 } 126 127 /** 128 * Attempts to register Karaf-specific BundleStateService - if possible 129 */ 130 public void init() { 131 try { 132 states = new ConcurrentHashMap<>(); 133 exceptions = new ConcurrentHashMap<>(); 134 135 registration = new KarafBundleStateServiceCreator().create(bundleContext, this); 136 } catch (NoClassDefFoundError e) { 137 LOG.info("Karaf BundleStateService not accessible. Bundle state won't reflect Camel context state"); 138 } 139 } 140 141 /** 142 * Unregisters any OSGi service registered 143 */ 144 public void destroy() { 145 if (registration != null) { 146 registration.unregister(); 147 } 148 states.clear(); 149 states = null; 150 exceptions.clear(); 151 exceptions = null; 152 } 153 154 /** 155 * Static creator to decouple from optional Karaf classes. 156 */ 157 private static class KarafBundleStateServiceCreator { 158 public ServiceRegistration<?> create(BundleContext context, BlueprintCamelStateService camelStateService) { 159 KarafBundleStateService karafBundleStateService = new KarafBundleStateService(camelStateService); 160 return karafBundleStateService.register(context); 161 } 162 } 163 164}