blob: fb0def4c0bc5344e463f07885ed3844d8ee878e1 [file] [log] [blame]
/*
* 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.felix.webconsole.internal.configuration;
import java.util.HashMap;
import java.util.Map;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.service.cm.Configuration;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.MetaTypeInformation;
import org.osgi.service.metatype.MetaTypeService;
import org.osgi.service.metatype.ObjectClassDefinition;
/**
* The <code>ConfigManagerBase</code> is the base class for the
* ConfigurationAdmin support in the web console. It provides various helper
* methods mostly with respect to using the MetaTypeService to access
* configuration descriptions.
*/
class MetaTypeServiceSupport extends MetaTypeSupport {
private final BundleContext bundleContext;
private final MetaTypeService service;
/**
* Create a new support object
* @param bundleContext The bundle context
* @param service The metatype service
*
* @throws ClassCastException if {@code service} is not a MetaTypeService instances
*/
MetaTypeServiceSupport( final BundleContext bundleContext, final Object service ) {
this.bundleContext = bundleContext;
this.service = ( MetaTypeService ) service;
}
/**
* Returns a map of PIDs and providing bundles of MetaType information. The
* map is indexed by PID and the value of each entry is the bundle providing
* the MetaType information for that PID.
*
* @param locale The name of the locale to get the meta data for.
* @return see the method description
*/
Map<String, ObjectClassDefinition> getPidObjectClasses( final String locale ) {
return getObjectClassDefinitions( PID_GETTER, locale );
}
/**
* Returns a map of factory PIDs and providing bundles of MetaType
* information. The map is indexed by factory PID and the value of each
* entry is the bundle providing the MetaType information for that factory
* PID.
*
* @param locale The name of the locale to get the meta data for.
* @return see the method description
*/
Map<String, ObjectClassDefinition> getFactoryPidObjectClasses( final String locale ) {
return getObjectClassDefinitions( FACTORY_PID_GETTER, locale );
}
/**
* Returns the <code>ObjectClassDefinition</code> objects for the IDs
* returned by the <code>idGetter</code>. Depending on the
* <code>idGetter</code> implementation this will be for factory PIDs or
* plain PIDs.
*
* @param idGetter The {@link IdGetter} used to get the list of factory PIDs
* or PIDs from <code>MetaTypeInformation</code> objects.
* @param locale The name of the locale to get the object class definitions
* for.
* @return Map of <code>ObjectClassDefinition</code> objects indexed by the
* PID (or factory PID) to which they pertain
*/
private Map<String, ObjectClassDefinition> getObjectClassDefinitions( final IdGetter idGetter, final String locale ) {
final Map<String, ObjectClassDefinition> objectClassesDefinitions = new HashMap<>();
for ( final Bundle bundle : this.bundleContext.getBundles() ) {
final MetaTypeInformation mti = this.service.getMetaTypeInformation( bundle );
if ( mti != null ) {
final String[] idList = idGetter.getIds( mti );
for ( int j = 0; idList != null && j < idList.length; j++ ) {
// After getting the list of PIDs, a configuration might be
// removed. So the getObjectClassDefinition will throw
// an exception, and this will prevent ALL configuration from
// being displayed. By catching it, the configurations will be
// visible
ObjectClassDefinition ocd = null;
try {
ocd = mti.getObjectClassDefinition( idList[j], locale );
} catch ( IllegalArgumentException ignore ) {
// ignore - just don't show this configuration
}
if ( ocd != null ) {
objectClassesDefinitions.put( idList[j], ocd );
}
}
}
}
return objectClassesDefinitions;
}
ObjectClassDefinition getObjectClassDefinition( Configuration config, String locale ) {
// if the configuration is bound, try to get the object class
// definition from the bundle installed from the given location
if ( config.getBundleLocation() != null ) {
Bundle bundle = getBundle( this.bundleContext, config.getBundleLocation() );
if ( bundle != null ) {
String id = config.getFactoryPid();
if ( null == id ) {
id = config.getPid();
}
return getObjectClassDefinition( bundle, id, locale );
}
}
// get here if the configuration is not bound or if no
// bundle with the bound location is installed. We search
// all bundles for a matching [factory] PID
// if the configuration is a factory one, use the factory PID
if ( config.getFactoryPid() != null ) {
return this.getObjectClassDefinition( config.getFactoryPid(), locale );
}
// otherwise use the configuration PID
return this.getObjectClassDefinition( config.getPid(), locale );
}
ObjectClassDefinition getObjectClassDefinition( Bundle bundle, String pid, String locale ) {
if ( bundle != null ) {
final MetaTypeInformation mti = this.service.getMetaTypeInformation( bundle );
if ( mti != null ) {
// see #getObjectClasses( final IdGetter idGetter, final String locale )
try {
return mti.getObjectClassDefinition( pid, locale );
} catch ( IllegalArgumentException e ) {
// MetaTypeProvider.getObjectClassDefinition might throw illegal
// argument exception. So we must catch it here, otherwise the
// other configurations will not be shown
// See https://issues.apache.org/jira/browse/FELIX-2390
// https://issues.apache.org/jira/browse/FELIX-3694
}
}
}
// fallback to nothing found
return null;
}
ObjectClassDefinition getObjectClassDefinition( String pid, String locale ) {
Bundle[] bundles = bundleContext.getBundles();
for ( final Bundle bundle : bundles) {
final ObjectClassDefinition ocd = this.getObjectClassDefinition( bundle, pid, locale );
if ( ocd != null ) {
return ocd;
}
}
return null;
}
Map<String, MetatypePropertyDescriptor> getAttributeDefinitionMap( Configuration config, String locale ) {
Map<String, MetatypePropertyDescriptor> adMap = new HashMap<>();
ObjectClassDefinition ocd = this.getObjectClassDefinition( config, locale );
if ( ocd != null ) {
AttributeDefinition[] ad = ocd.getAttributeDefinitions( ObjectClassDefinition.ALL );
if ( ad != null ) {
for ( int i = 0; i < ad.length; i++ ) {
adMap.put( ad[i].getID(), new MetatypePropertyDescriptor( ad[i], false ) );
}
}
}
return adMap;
}
/**
* The <code>IdGetter</code> interface is an internal helper to abstract
* retrieving object class definitions from all bundles for either
* pids or factory pids.
*
* @see #PID_GETTER
* @see #FACTORY_PID_GETTER
*/
private static interface IdGetter {
String[] getIds( MetaTypeInformation metaTypeInformation );
}
/**
* The implementation of the {@link IdGetter} interface returning the PIDs
* listed in the meta type information.
*
* @see #getPidObjectClasses(String)
*/
private static final IdGetter PID_GETTER = new IdGetter() {
@Override
public String[] getIds( MetaTypeInformation metaTypeInformation ) {
return metaTypeInformation.getPids();
}
};
/**
* The implementation of the {@link IdGetter} interface returning the
* factory PIDs listed in the meta type information.
*
* @see #getFactoryPidObjectClasses(String)
*/
private static final IdGetter FACTORY_PID_GETTER = new IdGetter() {
@Override
public String[] getIds( MetaTypeInformation metaTypeInformation ) {
return metaTypeInformation.getFactoryPids();
}
};
}