/*
* 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.karaf.features.internal.management;
import java.net.URI;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.ObjectName;
import javax.management.StandardEmitterMBean;
import javax.management.openmbean.TabularData;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeatureEvent;
import org.apache.karaf.features.FeaturesListener;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
import org.apache.karaf.features.RepositoryEvent;
import org.apache.karaf.features.management.FeaturesServiceMBean;
import org.apache.karaf.features.management.codec.JmxFeature;
import org.apache.karaf.features.management.codec.JmxFeatureEvent;
import org.apache.karaf.features.management.codec.JmxRepository;
import org.apache.karaf.features.management.codec.JmxRepositoryEvent;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
/**
* Implementation of {@link FeaturesServiceMBean}.
*/
public class FeaturesServiceMBeanImpl extends StandardEmitterMBean implements
MBeanRegistration, FeaturesServiceMBean {
private ServiceRegistration<FeaturesListener> registration;
private BundleContext bundleContext;
private ObjectName objectName;
private volatile long sequenceNumber;
private FeaturesService featuresService;
public FeaturesServiceMBeanImpl() throws NotCompliantMBeanException {
super(FeaturesServiceMBean.class,
new NotificationBroadcasterSupport(getBroadcastInfo()));
}
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
objectName = name;
return name;
}
public void postRegister(Boolean registrationDone) {
registration = bundleContext.registerService(FeaturesListener.class,
getFeaturesListener(), new Hashtable<String, String>());
}
public void preDeregister() throws Exception {
registration.unregister();
}
public void postDeregister() {
}
/**
* {@inheritDoc}
*/
public TabularData getFeatures() throws Exception {
try {
List<Feature> allFeatures = Arrays.asList(featuresService.listFeatures());
List<Feature> insFeatures = Arrays.asList(featuresService.listInstalledFeatures());
ArrayList<JmxFeature> features = new ArrayList<>();
for (Feature feature : allFeatures) {
try {
features.add(new JmxFeature(feature, insFeatures.contains(feature)));
} catch (Throwable t) {
t.printStackTrace();
}
}
return JmxFeature.tableFrom(features);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
/**
* {@inheritDoc}
*/
public TabularData getRepositories() throws Exception {
try {
List<Repository> allRepositories = Arrays.asList(featuresService.listRepositories());
ArrayList<JmxRepository> repositories = new ArrayList<>();
for (Repository repository : allRepositories) {
try {
repositories.add(new JmxRepository(repository));
} catch (Throwable t) {
t.printStackTrace();
}
}
return JmxRepository.tableFrom(repositories);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
public void addRepository(String uri) throws Exception {
featuresService.addRepository(new URI(uri));
}
public void addRepository(String uri, boolean install) throws Exception {
featuresService.addRepository(new URI(uri), install);
}
public void removeRepository(String uri) throws Exception {
removeRepository(uri, false);
}
public void removeRepository(String uri, boolean uninstall) throws Exception {
List<URI> uris = new ArrayList<>();
Pattern pattern = Pattern.compile(uri);
for (Repository repository : featuresService.listRepositories()) {
if (repository.getName() != null && !repository.getName().isEmpty()) {
// first regex on the repository name
Matcher nameMatcher = pattern.matcher(repository.getName());
if (nameMatcher.matches()) {
uris.add(repository.getURI());
} else {
// fallback to repository URI regex
Matcher uriMatcher = pattern.matcher(repository.getURI().toString());
if (uriMatcher.matches()) {
uris.add(repository.getURI());
}
}
} else {
// repository name is not defined, fallback to repository URI regex
Matcher uriMatcher = pattern.matcher(repository.getURI().toString());
if (uriMatcher.matches()) {
uris.add(repository.getURI());
}
}
}
for (URI u : uris) {
featuresService.removeRepository(u, uninstall);
}
}
public void refreshRepository(String uri) throws Exception {
if (uri == null || uri.isEmpty()) {
for (Repository repository : featuresService.listRepositories()) {
featuresService.refreshRepository(repository.getURI());
}
} else {
// regex support
Pattern pattern = Pattern.compile(uri);
List<URI> uris = new ArrayList<>();
for (Repository repository : featuresService.listRepositories()) {
URI u = repository.getURI();
Matcher matcher = pattern.matcher(u.toString());
if (matcher.matches()) {
uris.add(u);
}
}
for (URI u :uris) {
featuresService.refreshRepository(u);
}
}
}
public void installFeature(String name) throws Exception {
featuresService.installFeature(name);
}
public void installFeature(String name, boolean noRefresh) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
}
featuresService.installFeature(name, options);
}
public void installFeature(String name, boolean noRefresh, boolean noStart) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
}
if (noStart) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
}
featuresService.installFeature(name, options);
}
public void installFeature(String name, String version) throws Exception {
featuresService.installFeature(name, version);
}
public void installFeature(String name, String version, boolean noRefresh) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
}
featuresService.installFeature(name, version, options);
}
public void installFeature(String name, String version, boolean noRefresh, boolean noStart) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
}
if (noStart) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoStartBundles);
}
featuresService.installFeature(name, version, options);
}
public TabularData infoFeature(String name) throws Exception {
try {
Feature[] features = featuresService.getFeatures(name);
return infoFeature(features);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
public TabularData infoFeature(String name, String version) throws Exception {
try {
Feature[] features = featuresService.getFeatures(name, version);
return infoFeature(features);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
private TabularData infoFeature(Feature[] f) throws Exception {
ArrayList<JmxFeature> features = new ArrayList<>();
for (Feature feature:f) {
JmxFeature jmxFeature;
if (featuresService.isInstalled(feature)) {
jmxFeature = new JmxFeature(feature, true);
} else {
jmxFeature = new JmxFeature(feature, false);
}
features.add(jmxFeature);
}
return JmxFeature.tableFrom(features);
}
public void uninstallFeature(String name) throws Exception {
featuresService.uninstallFeature(name);
}
public void uninstallFeature(String name, boolean noRefresh) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(org.apache.karaf.features.FeaturesService.Option.NoAutoRefreshBundles);
}
featuresService.uninstallFeature(name, options);
}
public void uninstallFeature(String name, String version) throws Exception {
featuresService.uninstallFeature(name, version);
}
public void uninstallFeature(String name, String version, boolean noRefresh) throws Exception {
EnumSet<org.apache.karaf.features.FeaturesService.Option> options = EnumSet.noneOf(org.apache.karaf.features.FeaturesService.Option.class);
if (noRefresh) {
options.add(FeaturesService.Option.NoAutoRefreshBundles);
}
featuresService.uninstallFeature(name, version, options);
}
public void setBundleContext(BundleContext bundleContext) {
this.bundleContext = bundleContext;
}
public void setFeaturesService(FeaturesService featuresService) {
this.featuresService = featuresService;
}
public FeaturesListener getFeaturesListener() {
return new FeaturesListener() {
public void featureEvent(FeatureEvent event) {
if (!event.isReplay()) {
Notification notification = new Notification(FEATURE_EVENT_TYPE, objectName, sequenceNumber++);
notification.setUserData(new JmxFeatureEvent(event).asCompositeData());
sendNotification(notification);
}
}
public void repositoryEvent(RepositoryEvent event) {
if (!event.isReplay()) {
Notification notification = new Notification(REPOSITORY_EVENT_TYPE, objectName, sequenceNumber++);
notification.setUserData(new JmxRepositoryEvent(event).asCompositeData());
sendNotification(notification);
}
}
};
}
private static MBeanNotificationInfo[] getBroadcastInfo() {
String type = Notification.class.getCanonicalName();
MBeanNotificationInfo info1 = new MBeanNotificationInfo(new String[]{FEATURE_EVENT_EVENT_TYPE},
type, "Some features notification");
MBeanNotificationInfo info2 = new MBeanNotificationInfo(new String[]{REPOSITORY_EVENT_EVENT_TYPE},
type, "Some repository notification");
return new MBeanNotificationInfo[]{info1, info2};
}
}