Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ReferenceMetadata.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,752 @@ +/* + * 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.scr.impl.metadata; + +import java.util.Set; +import java.util.TreeSet; + +import org.apache.felix.scr.impl.helper.Logger; + +/** + * Information associated to a dependency + * + */ +public class ReferenceMetadata +{ + public enum ReferenceScope {bundle, prototype, prototype_required} + + // constant for option single reference - 0..1 + public static final String CARDINALITY_0_1 = "0..1"; + + // constant for option multiple reference - 0..n + public static final String CARDINALITY_0_N = "0..n"; + + // constant for required single reference - 1..1 + public static final String CARDINALITY_1_1 = "1..1"; + + // constant for required multiple reference - 1..n + public static final String CARDINALITY_1_N = "1..n"; + + // set of valid cardinality settings + private static final Set<String> CARDINALITY_VALID; + + // constant for static policy + public static final String POLICY_STATIC = "static"; + + // constant for dynamic policy + public static final String POLICY_DYNAMIC = "dynamic"; + + // set of valid policy settings + private static final Set<String> POLICY_VALID; + + // constant for reluctant policy option + public static final String POLICY_OPTION_RELUCTANT = "reluctant"; + + // constant for greedy policy option + public static final String POLICY_OPTION_GREEDY = "greedy"; + + // set of valid policy option settings + private static final Set<String> POLICY_OPTION_VALID; + + // constant for update field strategy + private static final String FIELD_STRATEGY_UPDATE = "update"; + + // constant for replace field strategy + private static final String FIELD_STRATEGY_REPLACE = "replace"; + + // set of valid field strategy settings + private static final Set<String> FIELD_STRATEGY_VALID; + + // constant for field value type service + public static final String FIELD_VALUE_TYPE_SERVICE = "service"; + + // constant for field value type properties + public static final String FIELD_VALUE_TYPE_PROPERTIES = "properties"; + + // constant for field value type reference + public static final String FIELD_VALUE_TYPE_REFERENCE = "reference"; + + // constant for field value type serviceobjects + public static final String FIELD_VALUE_TYPE_SERVICEOBJECTS = "serviceobjects"; + + // constant for field value type tuple + public static final String FIELD_VALUE_TYPE_TUPLE = "tuple"; + + // set of valid field value type settings + private static final Set<String> FIELD_VALUE_TYPE_VALID; + + // Name for the reference (required) + private String m_name = null; + + // Interface name (required) + private String m_interface = null; + + // Cardinality (optional, default="1..1") + private String m_cardinality = null; + + // Target (optional) + private String m_target; + + // Name of the bind method (optional) + private String m_bind = null; + + // Name of the updated method (optional, since DS 1.1-felix) + private String m_updated = null; + + // Name of the unbind method (optional) + private String m_unbind = null; + + // Name of the field (optional, since DS 1.3) + private String m_field; + + // Name of the strategy for the field (optional, since DS 1.3) + private String m_field_option; + + // Name of the value type for the field (optional, since DS 1.3) + private String m_field_collection_type; + + // Policy attribute (optional, default = static) + private String m_policy = null; + + // Policy option attribute (optional, default = reluctant) + private String m_policy_option = null; + + private String m_scopeName; + private ReferenceScope m_scope = ReferenceScope.bundle; + + // Flags that store the values passed as strings + private boolean m_isStatic = true; + private boolean m_isOptional = false; + private boolean m_isMultiple = false; + private boolean m_isReluctant = true; + private boolean m_isReplace = true; + + // Flag that is set once the component is verified (its properties cannot be changed) + private boolean m_validated = false; + + static + { + CARDINALITY_VALID = new TreeSet<String>(); + CARDINALITY_VALID.add( CARDINALITY_0_1 ); + CARDINALITY_VALID.add( CARDINALITY_0_N ); + CARDINALITY_VALID.add( CARDINALITY_1_1 ); + CARDINALITY_VALID.add( CARDINALITY_1_N ); + + POLICY_VALID = new TreeSet<String>(); + POLICY_VALID.add( POLICY_DYNAMIC ); + POLICY_VALID.add( POLICY_STATIC ); + + POLICY_OPTION_VALID = new TreeSet<String>(); + POLICY_OPTION_VALID.add( POLICY_OPTION_RELUCTANT ); + POLICY_OPTION_VALID.add( POLICY_OPTION_GREEDY ); + + FIELD_STRATEGY_VALID = new TreeSet<String>(); + FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_REPLACE ); + FIELD_STRATEGY_VALID.add( FIELD_STRATEGY_UPDATE ); + + FIELD_VALUE_TYPE_VALID = new TreeSet<String>(); + FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_PROPERTIES ); + FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_REFERENCE ); + FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICE ); + FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_SERVICEOBJECTS ); + FIELD_VALUE_TYPE_VALID.add ( FIELD_VALUE_TYPE_TUPLE ); + } + + /////////////////////////////////////////////// setters /////////////////////////////////// + + /** + * Setter for the name attribute + * + * @param name + */ + public void setName( String name ) + { + if ( m_validated ) + { + return; + } + + m_name = name; + } + + + /** + * Setter for the interfaceName attribute + * + * @param interfaceName + */ + public void setInterface( String interfaceName ) + { + if ( m_validated ) + { + return; + } + + m_interface = interfaceName; + + } + + + /** + * Setter for the cardinality attribute + * + * @param cardinality + */ + public void setCardinality( String cardinality ) + { + if ( m_validated ) + { + return; + } + + m_cardinality = cardinality; + + // secondary properties + m_isOptional = CARDINALITY_0_1.equals( cardinality ) || CARDINALITY_0_N.equals( cardinality ); + m_isMultiple = CARDINALITY_0_N.equals( cardinality ) || CARDINALITY_1_N.equals( cardinality ); + } + + + /** + * Setter for the policy attribute + * + * @param policy + */ + public void setPolicy( String policy ) + { + if ( m_validated ) + { + return; + } + + m_policy = policy; + + // secondary property + m_isStatic = POLICY_STATIC.equals( policy ); + } + + + /** + * Setter for the policy option attribute + * + * @param policyOption + */ + public void setPolicyOption( String policyOption ) + { + if ( m_validated ) + { + return; + } + + m_policy_option = policyOption; + + // secondary property + m_isReluctant = POLICY_OPTION_RELUCTANT.equals( policyOption ); + } + + + /** + * Setter for the target attribute (filter) + * + * @param target + */ + public void setTarget( String target ) + { + if ( m_validated ) + { + return; + } + + m_target = ( target == null || target.length() == 0 ) ? null : target; + } + + + /** + * Setter for the bind method attribute + * + * @param bind + */ + public void setBind( String bind ) + { + if ( m_validated ) + { + return; + } + + m_bind = bind; + } + + + /** + * Setter for the updated method attribute + * + * @param updated + */ + public void setUpdated( String updated ) + { + if ( m_validated ) + { + return; + } + + m_updated = updated; + } + + + /** + * Setter for the unbind method attribute + * + * @param unbind + */ + public void setUnbind( String unbind ) + { + if ( m_validated ) + { + return; + } + + m_unbind = unbind; + } + + + /** + * Setter for the field attribute + * + * @param field the field name + */ + public void setField( final String field ) + { + if ( m_validated ) + { + return; + } + + m_field = field; + } + + /** + * Setter for the field strategy attribute + * + * @param strategy the field strategy + */ + public void setFieldOption( final String strategy ) + { + if ( m_validated ) + { + return; + } + + m_field_option = strategy; + + m_isReplace = FIELD_STRATEGY_REPLACE.equals(strategy); + } + + /** + * Setter for the field value type attribute + * + * @param valuetype the field value type + */ + public void setFieldCollectionType( final String valuetype ) + { + if ( m_validated ) + { + return; + } + + m_field_collection_type = valuetype; + } + + public void setScope(String scopeName) { + if ( m_validated ) + { + return; + } + this.m_scopeName = scopeName; + } + + + /////////////////////////////////////////////// getters /////////////////////////////////// + + /** + * Returns the name of the reference + * + * @return A string containing the reference's name + **/ + public String getName() + { + return m_name; + } + + + /** + * Returns the fully qualified name of the class that is used by the component to access the service + * + * @return A string containing a fully qualified name + **/ + public String getInterface() + { + return m_interface; + } + + + /** + * Get the cardinality as a string + * + * @return A string with the cardinality + **/ + public String getCardinality() + { + return m_cardinality; + } + + + /** + * Get the policy as a string + * + * @return A string with the policy + **/ + public String getPolicy() + { + return m_policy; + } + + + /** + * Get the policy option as a string + * + * @return A string with the policy option + **/ + public String getPolicyOption() + { + return m_policy_option; + } + + + /** + * Returns the filter expression that further constrains the set of target services + * + * @return A string with a filter + **/ + public String getTarget() + { + return m_target; + } + + + /** + * Get the name of a method in the component implementation class that is used to notify that + * a service is bound to the component configuration + * + * @return a String with the name of the bind method + **/ + public String getBind() + { + return m_bind; + } + + + /** + * Get the name of a method in the component implementation class that is used to notify that + * the service properties of a bound service have been updated + * + * @return a String with the name of the updated method + **/ + public String getUpdated() + { + return m_updated; + } + + + /** + * Get the name of a method in the component implementation class that is used to notify that + * a service is unbound from the component configuration + * + * @return a String with the name of the unbind method + **/ + public String getUnbind() + { + return m_unbind; + } + + + /** + * Get the name of a field in the component implementation class that is used to hold + * the reference + * + * @return a String with the name of the field + */ + public String getField() + { + return m_field; + } + + + /** + * Get the strategy of a field in the component implementation class that is used to hold + * the reference + * + * @return a String with the strategy name for the field + */ + public String getFieldOption() + { + return m_field_option; + } + + /** + * Get the value type of a field in the component implementation class that is used to hold + * the reference + * + * @return a String with the value type for the field + */ + public String getFieldCollectionType() + { + return m_field_collection_type; + } + + // Getters for boolean values that determine both policy and cardinality + + /** + * Test if dependency's binding policy is static + * + * @return true if static + **/ + public boolean isStatic() + { + return m_isStatic; + } + + /** + * Test if dependency is optional (0..1 or 0..n) + * + * @return true if the dependency is optional + **/ + public boolean isOptional() + { + return m_isOptional; + } + + + /** + * Test if dependency is multiple (0..n or 1..n) + * + * @return true if the dependency is multiple + **/ + public boolean isMultiple() + { + return m_isMultiple; + } + + + /** + * Test if policy option is reluctant + * + * @return true if policy option is reluctant + */ + public boolean isReluctant() + { + return m_isReluctant; + } + + /** + * Test if field strategy is replace. + * + * @return true if field strategy is replace + */ + public boolean isReplace() + { + return m_isReplace; + } + + /** + * Returns the name of the component property referring to the {@link #getTarget() target} + * property of this reference. + * + * @return the name of the target property which is the name of this referene + * suffixed with the string ".target". + */ + public String getTargetPropertyName() + { + return getName() + ".target"; + } + + public String getMinCardinalityName() + { + return getName() + ".cardinality.minimum"; + } + + + public ReferenceScope getScope() { + return m_scope; + } + + /** + * Method used to verify if the semantics of this metadata are correct + * + */ + void validate( final ComponentMetadata componentMetadata, final Logger logger ) + { + final DSVersion dsVersion = componentMetadata.getDSVersion(); + + if ( m_name == null ) + { + // 112.10 name attribute is optional, defaults to interface since DS 1.1 + if ( !dsVersion.isDS11() ) + { + throw componentMetadata.validationFailure( "A name must be declared for the reference" ); + } + setName( getInterface() ); + } + + if ( m_interface == null ) + { + throw componentMetadata.validationFailure( "An interface must be declared for the reference" ); + } + + + if ( m_cardinality == null ) + { + setCardinality( CARDINALITY_1_1 ); + } + else if ( !CARDINALITY_VALID.contains( m_cardinality ) ) + { + throw componentMetadata.validationFailure( "Cardinality must be one of " + CARDINALITY_VALID ); + } + + if ( m_policy == null ) + { + setPolicy( POLICY_STATIC ); + } + else if ( !POLICY_VALID.contains( m_policy ) ) + { + throw componentMetadata.validationFailure( "Policy must be one of " + POLICY_VALID ); + } + + if ( m_policy_option == null ) + { + setPolicyOption( POLICY_OPTION_RELUCTANT ); + } + else if ( !POLICY_OPTION_VALID.contains( m_policy_option ) ) + { + throw componentMetadata.validationFailure( "Policy option must be one of " + POLICY_OPTION_VALID ); + } + else if ( !dsVersion.isDS12() && !POLICY_OPTION_RELUCTANT.equals( m_policy_option ) ) + { + throw componentMetadata.validationFailure( "Policy option must be reluctant for DS < 1.2" ); + } + + if (m_scopeName != null) { + if ( !dsVersion.isDS13() ) + { + throw componentMetadata.validationFailure( "reference scope can be set only for DS >= 1.3"); + } + try + { + m_scope = ReferenceScope.valueOf(m_scopeName); + } + catch (final IllegalArgumentException e) + { + throw componentMetadata.validationFailure( "reference scope must be 'bundle' or 'prototype' not " + m_scopeName); + + } + } + + // checks for event based injection + // updated method is only supported in namespace xxx and later + if ( m_updated != null && !(dsVersion.isDS12() || dsVersion == DSVersion.DS11Felix) ) + { + // FELIX-3648 validation must fail (instead of just ignore) + throw componentMetadata.validationFailure( "updated method declaration requires DS 1.2 or later namespace " ); + } + + // checks for field injection + if ( m_field != null ) + { + // field reference requires DS 1.3 + if ( !dsVersion.isDS13() ) + { + throw componentMetadata.validationFailure( "Field reference requires DS >= 1.3" ); + } + + // field strategy + if ( m_field_option == null ) + { + setFieldOption( FIELD_STRATEGY_REPLACE ); + } + else if ( !FIELD_STRATEGY_VALID.contains( m_field_option ) ) + { + throw componentMetadata.validationFailure( "Field strategy must be one of " + FIELD_STRATEGY_VALID ); + } + if ( !m_isMultiple ) + { + // update is not allowed for unary references + if ( m_field_option.equals(FIELD_STRATEGY_UPDATE) ) + { + throw componentMetadata.validationFailure( "Field strategy update not allowed for unary field references." ); + } + } + + // field value type + if ( !m_isMultiple ) + { + // value type must not be specified for unary references + if ( m_field_collection_type != null ) + { + throw componentMetadata.validationFailure( "Field value type must not be set for unary field references." ); + } + } + else + { + if ( m_field_collection_type == null ) + { + setFieldCollectionType( FIELD_VALUE_TYPE_SERVICE ); + } + else if ( !FIELD_VALUE_TYPE_VALID.contains( m_field_collection_type ) ) + { + throw componentMetadata.validationFailure( "Field value type must be one of " + FIELD_VALUE_TYPE_VALID ); + } + } + + // static references only allow replace strategy + if ( m_isStatic ) + { + if ( ! m_field_option.equals(FIELD_STRATEGY_REPLACE) ) + { + throw componentMetadata.validationFailure( "Field strategy update not allowed for static field references." ); + } + } + } + + m_validated = true; + } + + public String getDebugInfo() + { + return getName() + + "interface=" + this.getInterface() + + ", filter=" + this.getTarget() + + ", policy=" + this.getPolicy() + + ", cardinality=" + this.getCardinality() + + ", bind=" + this.getBind() + + ", unbind=" + this.getUnbind() + + ", updated=" + this.getUpdated() + + ", field=" + this.getField() + + ", field-option=" + this.getFieldOption() + + ", field-collection-type=" + this.getFieldCollectionType(); + } +} \ No newline at end of file
Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ServiceMetadata.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ServiceMetadata.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ServiceMetadata.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/ServiceMetadata.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,137 @@ +/* + * 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.scr.impl.metadata; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class contains the metadata associated to a service that is provided + * by a component + * + */ +public class ServiceMetadata { + + public enum Scope { singleton, bundle, prototype} + + // 112.4.6 Flag that indicates if the service is a ServiceFactory + private Boolean m_serviceFactory; + + private String m_scopeName; + private Scope m_scope = Scope.singleton; + + // List of provided interfaces + private List<String> m_provides = new ArrayList<String>(); + + // Flag that indicates if this metadata has been validated and has become immutable + private boolean m_validated = false; + + /** + * Setter for the servicefactory attribute of the service element + * + * @param serviceFactory + */ + public void setServiceFactory(boolean serviceFactory) { + if(m_validated) { + return; + } + + m_serviceFactory = serviceFactory; + } + + public void setScope(String scopeName) { + if(m_validated) { + return; + } + this.m_scopeName = scopeName; + } + + + + public Scope getScope() { + return m_scope; + } + + /** + * Add a provided interface to this service + * + * @param provide a String containing the name of the provided interface + */ + public void addProvide(String provide) { + if(m_validated) { + return; + } + + m_provides.add(provide); + } + + /** + * Returns the implemented interfaces + * + * @return the implemented interfaces as a string array + */ + public String [] getProvides() { + return m_provides.toArray( new String[m_provides.size()] ); + } + + /** + * Verify if the semantics of this metadata are correct + * + */ + void validate( ComponentMetadata componentMetadata ) + { + if ( m_provides.size() == 0 ) + { + throw componentMetadata + .validationFailure( "At least one provided interface must be declared in the service element" ); + } + for ( String provide: m_provides ) + { + if ( provide == null ) + { + throw componentMetadata + .validationFailure( "Null provides. Possibly service is not specified as value of attribute 'interface'" ); + } + } + if (m_serviceFactory != null) + { + if ( componentMetadata.getDSVersion().isDS13() ) + { + throw componentMetadata.validationFailure("service-factory can only be specified in version 1.2 and earlier"); + } + m_scope = m_serviceFactory? Scope.bundle: Scope.singleton; + } + if ( m_scopeName != null ) + { + if ( !componentMetadata.getDSVersion().isDS13() ) + { + throw componentMetadata.validationFailure("service scope can only be specified in version 1.3 and later"); + } + try + { + m_scope = Scope.valueOf(m_scopeName); + } + catch (IllegalArgumentException e) + { + throw componentMetadata.validationFailure("Service scope may be only 'singleton' 'bundle' or 'prototype' not " + m_scopeName); + } + } + m_validated = true; + } +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/XmlHandler.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/XmlHandler.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/XmlHandler.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/metadata/XmlHandler.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,585 @@ +/* + * 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.scr.impl.metadata; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.felix.scr.impl.helper.Logger; +import org.apache.felix.scr.impl.parser.KXml2SAXHandler; +import org.apache.felix.scr.impl.parser.KXml2SAXParser.Attributes; +import org.apache.felix.scr.impl.parser.ParseException; +import org.osgi.framework.Bundle; +import org.osgi.service.log.LogService; + + +/** + * + * + */ +public class XmlHandler implements KXml2SAXHandler +{ + + // Empty Namespace URI maps to DS 1.0 + public static final String NAMESPACE_URI_EMPTY = ""; + + // Namespace URI of DS 1.0 + public static final String NAMESPACE_URI = "http://www.osgi.org/xmlns/scr/v1.0.0"; + + // Namespace URI of DS 1.1 + public static final String NAMESPACE_URI_1_1 = "http://www.osgi.org/xmlns/scr/v1.1.0"; + + // Namespace URI of DS 1.1-felix (see FELIX-1893) + public static final String NAMESPACE_URI_1_1_FELIX = "http://felix.apache.org/xmlns/scr/v1.1.0-felix"; + + // Namespace URI of DS 1.2 + public static final String NAMESPACE_URI_1_2 = "http://www.osgi.org/xmlns/scr/v1.2.0"; + + // Namespace URI of DS 1.2-felix (see FELIX-3377) + public static final String NAMESPACE_URI_1_2_FELIX = "http://felix.apache.org/xmlns/scr/v1.2.0-felix"; + + // Namespace URI of DS 1.3 + public static final String NAMESPACE_URI_1_3 = "http://www.osgi.org/xmlns/scr/v1.3.0"; + + // Namespace URI of Felix DS extensions 1.0 + public static final String NAMESPACE_URI_1_0_FELIX_EXTENSIONS = "http://felix.apache.org/xmlns/scr/extensions/v1.0.0"; + + //extension features + public static final String CONFIGURABLE_SERVICE_PROPERTIES = "configurableServiceProperties"; + + public static final String PERSISTENT_FACTORY_COMPONENT = "persistentFactoryComponent"; + + public static final String DELETE_CALLS_MODIFY = "deleteCallsModify"; + + public static final String OBSOLETE_FACTORY_COMPONENT_FACTORY = "obsoleteFactoryComponentFactory"; + + public static final String CONFIGURE_WITH_INTERFACES = "configureWithInterfaces"; + + public static final String DELAYED_KEEP_INSTANCES = "delayedKeepInstances"; + + // namespace code for non-DS namespace + public static final int DS_VERSION_NONE = -1; + + // namespace code for the DS 1.0 specification + public static final int DS_VERSION_1_0 = 0; + + // namespace code for the DS 1.1 specification + public static final int DS_VERSION_1_1 = 1; + + // namespace code for the DS 1.1-felix specification + public static final int DS_VERSION_1_1_FELIX = 2; + + // namespace code for the DS 1.2 specification + public static final int DS_VERSION_1_2 = 3; + + // namespace code for the DS 1.2-felix specification + public static final int DS_VERSION_1_2_FELIX = 4; + + // namespace code for the DS 1.3 specification + public static final int DS_VERSION_1_3 = 5; + + // mapping of namespace URI to namespace code + private static final Map<String, DSVersion> NAMESPACE_CODE_MAP; + + // the bundle containing the XML resource being parsed + private final Bundle m_bundle; + + // logger for any messages + private final Logger m_logger; + + private final boolean m_globalObsoleteFactoryComponentFactory; + + private final boolean m_globalDelayedKeepInstances; + + // A reference to the current component + private ComponentMetadata m_currentComponent; + + // The current service + private ServiceMetadata m_currentService; + + // A list of component descriptors contained in the file + private List<ComponentMetadata> m_components = new ArrayList<ComponentMetadata>(); + + // PropertyMetaData whose value attribute is missing, hence has element data + private PropertyMetadata m_pendingProperty; + + /** Flag for detecting the first element. */ + protected boolean firstElement = true; + + /** Override namespace. */ + protected String overrideNamespace; + + /** Flag for elements inside a component element */ + protected boolean isComponent = false; + + static + { + NAMESPACE_CODE_MAP = new HashMap<String, DSVersion>(); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_EMPTY, DSVersion.DS10 ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI, DSVersion.DS10 ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_1, DSVersion.DS11 ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_1_FELIX, DSVersion.DS11Felix ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_2, DSVersion.DS12 ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_2_FELIX, DSVersion.DS12Felix ); + NAMESPACE_CODE_MAP.put( NAMESPACE_URI_1_3, DSVersion.DS13 ); + } + + + // creates an instance with the bundle owning the component descriptor + // file parsed by this instance + public XmlHandler( Bundle bundle, Logger logger, boolean globalObsoleteFactoryComponentFactory, boolean globalDelayedKeepInstances ) + { + m_bundle = bundle; + m_logger = logger; + m_globalObsoleteFactoryComponentFactory = globalObsoleteFactoryComponentFactory; + m_globalDelayedKeepInstances = globalDelayedKeepInstances; + } + + + /** + * Called to retrieve the service descriptors + * + * @return A list of service descriptors + */ + public List<ComponentMetadata> getComponentMetadataList() + { + return m_components; + } + + + /** + * Method called when a tag opens + * + * @param uri + * @param localName + * @param attributes + * @exception ParseException + **/ + public void startElement( String uri, String localName, Attributes attributes ) throws ParseException + { + // according to the spec, the elements should have the namespace, + // except when the root element is the "component" element + // So we check this for the first element, we receive. + if ( firstElement ) + { + firstElement = false; + if ( localName.equals( "component" ) && "".equals( uri ) ) + { + overrideNamespace = NAMESPACE_URI; + } + } + + if ( overrideNamespace != null && "".equals( uri ) ) + { + uri = overrideNamespace; + } + + // FELIX-695: however the spec also states that the inner elements + // of a component are unqualified, so they don't have + // the namespace - we allow both: with or without namespace! + if ( this.isComponent && "".equals(uri) ) + { + uri = NAMESPACE_URI; + } + + // get the namespace code for the namespace uri + DSVersion namespaceCode = NAMESPACE_CODE_MAP.get( uri ); + // from now on uri points to the namespace + if ( namespaceCode != null ) + { + try + { + + // 112.4.3 Component Element + if ( localName.equals( "component" ) ) + { + this.isComponent = true; + + // Create a new ComponentMetadata + m_currentComponent = new ComponentMetadata( namespaceCode ); + + // name attribute is optional (since DS 1.1) + if ( attributes.getAttribute( "name" ) != null ) + { + m_currentComponent.setName( attributes.getAttribute( "name" ) ); + } + + // enabled attribute is optional + if ( attributes.getAttribute( "enabled" ) != null ) + { + m_currentComponent.setEnabled( attributes.getAttribute( "enabled" ).equals( "true" ) ); + } + + // immediate attribute is optional + if ( attributes.getAttribute( "immediate" ) != null ) + { + m_currentComponent.setImmediate( attributes.getAttribute( "immediate" ).equals( "true" ) ); + } + + // factory attribute is optional + if ( attributes.getAttribute( "factory" ) != null ) + { + m_currentComponent.setFactoryIdentifier( attributes.getAttribute( "factory" ) ); + } + + // configuration-policy is optional (since DS 1.1) + if ( attributes.getAttribute( "configuration-policy" ) != null ) + { + m_currentComponent.setConfigurationPolicy( attributes.getAttribute( "configuration-policy" ) ); + } + + // activate attribute is optional (since DS 1.1) + if ( attributes.getAttribute( "activate" ) != null ) + { + m_currentComponent.setActivate( attributes.getAttribute( "activate" ) ); + } + + // deactivate attribute is optional (since DS 1.1) + if ( attributes.getAttribute( "deactivate" ) != null ) + { + m_currentComponent.setDeactivate( attributes.getAttribute( "deactivate" ) ); + } + + // modified attribute is optional (since DS 1.1) + if ( attributes.getAttribute( "modified" ) != null ) + { + m_currentComponent.setModified( attributes.getAttribute( "modified" ) ); + } + + // configuration-pid attribute is optional (since DS 1.2) + String configurationPidString = attributes.getAttribute( "configuration-pid" ); + if (configurationPidString != null) + { + String[] configurationPid = configurationPidString.split( " " ); + m_currentComponent.setConfigurationPid( configurationPid ); + } + + m_currentComponent.setConfigurableServiceProperties("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURABLE_SERVICE_PROPERTIES))); + m_currentComponent.setPersistentFactoryComponent("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, PERSISTENT_FACTORY_COMPONENT))); + m_currentComponent.setDeleteCallsModify("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELETE_CALLS_MODIFY))); + if ( attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, OBSOLETE_FACTORY_COMPONENT_FACTORY) != null) + { + m_currentComponent.setObsoleteFactoryComponentFactory("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, OBSOLETE_FACTORY_COMPONENT_FACTORY))); + } + else if ( !namespaceCode.isDS13() ) + { + m_currentComponent.setObsoleteFactoryComponentFactory(m_globalObsoleteFactoryComponentFactory); + } + m_currentComponent.setConfigureWithInterfaces("true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, CONFIGURE_WITH_INTERFACES))); + m_currentComponent.setDelayedKeepInstances(m_globalDelayedKeepInstances || "true".equals(attributes.getAttribute(NAMESPACE_URI_1_0_FELIX_EXTENSIONS, DELAYED_KEEP_INSTANCES))); + + // Add this component to the list + m_components.add( m_currentComponent ); + } + + // not inside a component element, ignore current element + else if ( !this.isComponent ) + { + m_logger.log( LogService.LOG_DEBUG, + "Not currently parsing a component; ignoring element {0} (bundle {1})", new Object[] + { localName, m_bundle.getLocation() }, null, null, null ); + } + + // 112.4.4 Implementation + else if ( localName.equals( "implementation" ) ) + { + // Set the implementation class name (mandatory) + m_currentComponent.setImplementationClassName( attributes.getAttribute( "class" ) ); + } + // 112.4.5 [...] Property Elements + else if ( localName.equals( "property" ) ) + { + PropertyMetadata prop = new PropertyMetadata(); + + // name attribute is mandatory + prop.setName( attributes.getAttribute( "name" ) ); + + // type attribute is optional + if ( attributes.getAttribute( "type" ) != null ) + { + prop.setType( attributes.getAttribute( "type" ) ); + } + + // 112.4.5: If the value attribute is specified, the body of the element is ignored. + if ( attributes.getAttribute( "value" ) != null ) + { + prop.setValue( attributes.getAttribute( "value" ) ); + m_currentComponent.addProperty( prop ); + } + else + { + // hold the metadata pending + m_pendingProperty = prop; + } + } + // 112.4.5 Properties [...] Elements + else if ( localName.equals( "properties" ) ) + { + readPropertiesEntry( attributes.getAttribute( "entry" ) ); + } + // 112.4.6 Service Element + else if ( localName.equals( "service" ) ) + { + + m_currentService = new ServiceMetadata(); + + // servicefactory attribute is optional + if ( attributes.getAttribute( "servicefactory" ) != null ) + { + m_currentService.setServiceFactory( attributes.getAttribute( "servicefactory" ).equals( "true" ) ); + } + + if ( attributes.getAttribute( "scope" ) != null ) + { + m_currentService.setScope( attributes.getAttribute( "scope" ) ); + } + + m_currentComponent.setService( m_currentService ); + } + else if ( localName.equals( "provide" ) ) + { + m_currentService.addProvide( attributes.getAttribute( "interface" ) ); + } + + // 112.4.7 Reference element + else if ( localName.equals( "reference" ) ) + { + ReferenceMetadata ref = new ReferenceMetadata(); + + // name attribute is optional (since DS 1.1) + if ( attributes.getAttribute( "name" ) != null ) + { + ref.setName( attributes.getAttribute( "name" ) ); + } + + ref.setInterface( attributes.getAttribute( "interface" ) ); + + // Cardinality + if ( attributes.getAttribute( "cardinality" ) != null ) + { + ref.setCardinality( attributes.getAttribute( "cardinality" ) ); + } + + if ( attributes.getAttribute( "policy" ) != null ) + { + ref.setPolicy( attributes.getAttribute( "policy" ) ); + } + + if ( attributes.getAttribute( "policy-option" ) != null ) + { + ref.setPolicyOption( attributes.getAttribute( "policy-option" ) ); + } + + if ( attributes.getAttribute( "scope" ) != null ) + { + ref.setScope( attributes.getAttribute( "scope" ) ); + } + + if ( attributes.getAttribute( "target" ) != null) + { + ref.setTarget( attributes.getAttribute( "target" ) ); + PropertyMetadata prop = new PropertyMetadata(); + prop.setName( (ref.getName() == null? ref.getInterface(): ref.getName()) + ".target"); + prop.setValue( attributes.getAttribute( "target" ) ); + m_currentComponent.addProperty( prop ); + + } + + // method reference + ref.setBind( attributes.getAttribute( "bind" ) ); + ref.setUpdated( attributes.getAttribute( "updated" ) ); + ref.setUnbind( attributes.getAttribute( "unbind" ) ); + + // field reference + ref.setField( attributes.getAttribute( "field" ) ); + ref.setFieldOption( attributes.getAttribute( "field-option" ) ); + ref.setFieldCollectionType( attributes.getAttribute( "field-collection-type" ) ); + + m_currentComponent.addDependency( ref ); + } + + // unexpected element (except the root element "components" + // used by the Maven SCR Plugin, which is just silently ignored) + else if ( !localName.equals( "components" ) ) + { + m_logger.log( LogService.LOG_DEBUG, "Ignoring unsupported element {0} (bundle {1})", new Object[] + { localName, m_bundle.getLocation() }, null, null, null ); + } + } + catch ( Exception ex ) + { + throw new ParseException( "Exception during parsing", ex ); + } + } + + // unexpected namespace (except the root element "components" + // used by the Maven SCR Plugin, which is just silently ignored) + else if ( !localName.equals( "components" ) ) + { + m_logger.log( LogService.LOG_DEBUG, "Ignoring unsupported element '{'{0}'}'{1} (bundle {2})", new Object[] + { uri, localName, m_bundle.getLocation() }, null, null, null ); + } + } + + + /** + * Method called when a tag closes + * + * @param uri + * @param localName + */ + public void endElement( String uri, String localName ) + { + if ( overrideNamespace != null && "".equals( uri ) ) + { + uri = overrideNamespace; + } + + if ( this.isComponent && "".equals(uri) ) + { + uri = NAMESPACE_URI; + } + + if ( NAMESPACE_URI.equals( uri ) ) + { + if ( localName.equals( "component" ) ) + { + this.isComponent = false; + } + else if ( localName.equals( "property" ) && m_pendingProperty != null ) + { + // 112.4.5 body expected to contain property value + // if so, the m_pendingProperty field would be null + // currently, we just ignore this situation + m_pendingProperty = null; + } + } + } + + + /** + * @see org.apache.felix.scr.impl.parser.KXml2SAXHandler#characters(java.lang.String) + */ + public void characters( String text ) + { + // 112.4.5 If the value attribute is not specified, the body must contain one or more values + if ( m_pendingProperty != null ) + { + m_pendingProperty.setValues( text ); + m_currentComponent.addProperty( m_pendingProperty ); + m_pendingProperty = null; + } + } + + + /** + * @see org.apache.felix.scr.impl.parser.KXml2SAXHandler#processingInstruction(java.lang.String, java.lang.String) + */ + public void processingInstruction( String target, String data ) + { + // Not used + } + + + /** + * @see org.apache.felix.scr.impl.parser.KXml2SAXHandler#setLineNumber(int) + */ + public void setLineNumber( int lineNumber ) + { + // Not used + } + + + /** + * @see org.apache.felix.scr.impl.parser.KXml2SAXHandler#setColumnNumber(int) + */ + public void setColumnNumber( int columnNumber ) + { + // Not used + } + + + /** + * Reads the name property file from the bundle owning this descriptor. All + * properties read from the properties file are added to the current + * component's property meta data list. + * + * @param entryName The name of the bundle entry containing the propertes + * to be added. This must not be <code>null</code>. + * + * @throws ParseException If the entry name is <code>null</code> or no + * entry with the given name exists in the bundle or an error occurrs + * reading the properties file. + */ + private void readPropertiesEntry( String entryName ) throws ParseException + { + if ( entryName == null ) + { + throw new ParseException( "Missing entry attribute of properties element", null ); + } + + URL entryURL = m_bundle.getEntry( entryName ); + if ( entryURL == null ) + { + throw new ParseException( "Missing bundle entry " + entryName, null ); + } + + Properties props = new Properties(); + InputStream entryStream = null; + try + { + entryStream = entryURL.openStream(); + props.load( entryStream ); + } + catch ( IOException ioe ) + { + throw new ParseException( "Failed to read properties entry " + entryName, ioe ); + } + finally + { + if ( entryStream != null ) + { + try + { + entryStream.close(); + } + catch ( IOException ignore ) + { + // don't care + } + } + } + + // create PropertyMetadata for the properties from the file + for ( Map.Entry<Object, Object> pEntry: props.entrySet() ) + { + PropertyMetadata prop = new PropertyMetadata(); + prop.setName( String.valueOf( pEntry.getKey() ) ); + prop.setValue( String.valueOf( pEntry.getValue() ) ); + m_currentComponent.addProperty( prop ); + } + } +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXHandler.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXHandler.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXHandler.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXHandler.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,69 @@ +/* + * 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.scr.impl.parser; + +import org.apache.felix.scr.impl.parser.KXml2SAXParser.Attributes; + +/** + * Interface for a SAX like handler with kXML + */ +public interface KXml2SAXHandler { + + /** + * Method called when parsing text + * + * @param text + * @exception ParseException + */ + void characters(String text) throws ParseException; + + /** + * Method called when a tag opens + * + * @param uri + * @param localName + * @param attributes + * @exception ParseException + */ + void startElement( + String uri, + String localName, + Attributes attributes) + throws ParseException; + + /** + * Method called when a tag closes + * + * @param uri + * @param localName + * @exception ParseException + */ + void endElement( + String uri, + String localName) + throws ParseException; + + void processingInstruction(String target, + String data) + throws Exception; + + void setLineNumber(int lineNumber); + + void setColumnNumber(int columnNumber); +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXParser.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXParser.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXParser.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/KXml2SAXParser.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,165 @@ +/* + * 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.scr.impl.parser; + + +import java.io.Reader; +import java.util.Stack; + +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + + +/** + * The KXml2SAXParser extends the XmlParser from kxml. This is a very + * simple parser that does not take into account the DTD + * + */ +public class KXml2SAXParser extends KXmlParser +{ + + /** + * The constructor for a parser, it receives a java.io.Reader. + * + * @param reader The reader + * @throws XmlPullParserException + */ + public KXml2SAXParser( Reader reader ) throws XmlPullParserException + { + super(); + setInput( reader ); + setFeature( FEATURE_PROCESS_NAMESPACES, true ); + } + + + /** + * Parser from the reader provided in the constructor, and call + * the startElement and endElement in a KxmlHandler + * + * @param handler The handler + * @exception Exception thrown by the superclass + */ + public void parseXML( KXml2SAXHandler handler ) throws Exception + { + + final Stack<XmlElement> openElements = new Stack<XmlElement>(); + XmlElement currentElement = null; + final Attributes attributes = new Attributes(); + + while ( next() != XmlPullParser.END_DOCUMENT ) + { + handler.setLineNumber( getLineNumber() ); + handler.setColumnNumber( getColumnNumber() ); + + if ( getEventType() == XmlPullParser.START_TAG ) + { + currentElement = new XmlElement( getNamespace(), getName(), getLineNumber(), getColumnNumber() ); + openElements.push( currentElement ); + + handler.startElement( getNamespace(), getName(), attributes ); + } + else if ( getEventType() == XmlPullParser.END_TAG ) + { + ensureMatchingCurrentElement(currentElement); + openElements.pop(); + currentElement = openElements.isEmpty() ? null : ( XmlElement ) openElements.peek(); + + handler.endElement( getNamespace(), getName() ); + } + else if ( getEventType() == XmlPullParser.TEXT ) + { + String text = getText(); + handler.characters( text ); + } + else if ( getEventType() == XmlPullParser.PROCESSING_INSTRUCTION ) + { + // TODO extract the target from the evt.getText() + handler.processingInstruction( null, getText() ); + } + else + { + // do nothing + } + } + + if ( !openElements.isEmpty() ) + { + throw new ParseException( "Unclosed elements found: " + openElements, null ); + } + } + + + private void ensureMatchingCurrentElement( final XmlElement currentElement ) throws Exception + { + if ( currentElement == null ) + { + throw new ParseException( "Unexpected closing element " + + new XmlElement( getNamespace(), getName(), getLineNumber(), getColumnNumber() ), null ); + } + + if ( !currentElement.match( getNamespace(), getName() ) ) + { + throw new ParseException( "Unexpected closing element " + + new XmlElement( getNamespace(), getName(), getLineNumber(), getColumnNumber() ) + + ": Does not match opening element " + currentElement, null ); + } + } + + private static class XmlElement + { + + final String namespaceUri; + final String name; + final int line; + final int col; + + + XmlElement( final String namespaceUri, final String name, final int line, final int col ) + { + this.namespaceUri = namespaceUri; + this.name = name; + this.line = line; + this.col = col; + } + + + boolean match( final String namespaceUri, final String name ) + { + return namespaceUri.equals( this.namespaceUri ) && name.equals( this.name ); + } + + public String toString() + { + return name + "@" + line + ":" + col; + } + } + + public class Attributes { + + public String getAttribute(String name) { + return getAttributeValue("", name); + } + + public String getAttribute(String uri, String name) { + return getAttributeValue(uri, name); + } + + } +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/ParseException.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/ParseException.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/ParseException.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/parser/ParseException.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,27 @@ +/* + * 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.scr.impl.parser; + +public class ParseException extends Exception +{ + public ParseException(String msg, Exception originalException) { + super(msg, originalException); + } + +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/impl/runtime/ServiceComponentRuntimeImpl.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,358 @@ +/* + * 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.scr.impl.runtime; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.felix.scr.impl.ComponentRegistry; +import org.apache.felix.scr.impl.config.ComponentHolder; +import org.apache.felix.scr.impl.config.ComponentManager; +import org.apache.felix.scr.impl.config.ReferenceManager; +import org.apache.felix.scr.impl.metadata.ComponentMetadata; +import org.apache.felix.scr.impl.metadata.ReferenceMetadata; +import org.osgi.dto.DTO; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.dto.BundleDTO; +import org.osgi.framework.dto.ServiceReferenceDTO; +import org.osgi.service.component.runtime.ServiceComponentRuntime; +import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO; +import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; +import org.osgi.service.component.runtime.dto.ReferenceDTO; +import org.osgi.service.component.runtime.dto.SatisfiedReferenceDTO; +import org.osgi.service.component.runtime.dto.UnsatisfiedReferenceDTO; +import org.osgi.util.promise.Promise; + +public class ServiceComponentRuntimeImpl implements ServiceComponentRuntime +{ + + private static final String[] EMPTY = {}; + + private final BundleContext context; + private final ComponentRegistry componentRegistry; + + + public ServiceComponentRuntimeImpl(BundleContext context,ComponentRegistry componentRegistry) + { + this.context = context; + this.componentRegistry = componentRegistry; + } + + public Collection<ComponentDescriptionDTO> getComponentDescriptionDTOs(Bundle... bundles) + { + List<ComponentHolder<?>> holders; + if (bundles == null || bundles.length == 0) + { + holders = componentRegistry.getComponentHolders(); + } + else + { + holders = componentRegistry.getComponentHolders(bundles); + } + + List<ComponentDescriptionDTO> result = new ArrayList<ComponentDescriptionDTO>(holders.size()); + for (ComponentHolder<?> holder: holders) + { + result.add(holderToDescription(holder)); + } + return result; + } + + public ComponentDescriptionDTO getComponentDescriptionDTO(Bundle bundle, String name) + { + ComponentHolder<?> holder = componentRegistry.getComponentHolder(bundle, name); + if ( holder != null ) + { + return holderToDescription(holder); + } + else + { + return null; + } + } + + public Collection<ComponentConfigurationDTO> getComponentConfigurationDTOs(ComponentDescriptionDTO description) + { + if ( description == null) + { + return Collections.emptyList(); + } + ComponentHolder<?> holder = getHolderFromDescription( description); + //Get a fully filled out valid description DTO + description = holderToDescription(holder); + List<? extends ComponentManager<?>> managers = holder.getComponents(); + List<ComponentConfigurationDTO> result = new ArrayList<ComponentConfigurationDTO>(managers.size()); + for (ComponentManager<?> manager: managers) + { + result.add(managerToConfiguration(manager, description)); + } + return result; + } + + public boolean isComponentEnabled(ComponentDescriptionDTO description) + { + ComponentHolder<?> holder = getHolderFromDescription( description); + return holder.isEnabled(); + } + + public Promise<Void> enableComponent(ComponentDescriptionDTO description) + { + ComponentHolder<?> holder = getHolderFromDescription( description); + return holder.enableComponents(true); + } + + public Promise<Void> disableComponent(ComponentDescriptionDTO description) + { + ComponentHolder<?> holder = getHolderFromDescription( description); + return holder.disableComponents(true); //synchronous + } + + private ComponentConfigurationDTO managerToConfiguration(ComponentManager<?> manager, ComponentDescriptionDTO description) + { + ComponentConfigurationDTO dto = new ComponentConfigurationDTO(); + dto.satisfiedReferences = satisfiedRefManagersToDTO(manager.getReferenceManagers()); + dto.unsatisfiedReferences = unsatisfiedRefManagersToDTO(manager.getReferenceManagers()); + dto.description = description; + dto.id = manager.getId(); + dto.properties = new HashMap<String, Object>(manager.getProperties());//TODO deep copy? + dto.state = manager.getState(); + return dto; + } + + private SatisfiedReferenceDTO[] satisfiedRefManagersToDTO(List<? extends ReferenceManager<?, ?>> referenceManagers) + { + List<SatisfiedReferenceDTO> dtos = new ArrayList<SatisfiedReferenceDTO>(); + for (ReferenceManager<?, ?> ref: referenceManagers) + { + if (ref.isSatisfied()) + { + SatisfiedReferenceDTO dto = new SatisfiedReferenceDTO(); + dto.name = ref.getName(); + dto.target = ref.getTarget(); + List<ServiceReference<?>> serviceRefs = ref.getServiceReferences(); + ServiceReferenceDTO[] srDTOs = new ServiceReferenceDTO[serviceRefs.size()]; + int j = 0; + for (ServiceReference<?> serviceRef : serviceRefs) + { + ServiceReferenceDTO srefDTO = serviceReferenceToDTO(serviceRef); + if (srefDTO != null) + srDTOs[j++] = srefDTO; + } + dto.boundServices = srDTOs; + dtos.add(dto); + } + } + return dtos.toArray( new SatisfiedReferenceDTO[dtos.size()] ); + } + + private UnsatisfiedReferenceDTO[] unsatisfiedRefManagersToDTO(List<? extends ReferenceManager<?, ?>> referenceManagers) + { + List<UnsatisfiedReferenceDTO> dtos = new ArrayList<UnsatisfiedReferenceDTO>(); + for (ReferenceManager<?, ?> ref: referenceManagers) + { + if (!ref.isSatisfied()) + { + UnsatisfiedReferenceDTO dto = new UnsatisfiedReferenceDTO(); + dto.name = ref.getName(); + dto.target = ref.getTarget(); + List<ServiceReference<?>> serviceRefs = ref.getServiceReferences(); + ServiceReferenceDTO[] srDTOs = new ServiceReferenceDTO[serviceRefs.size()]; + int j = 0; + for (ServiceReference<?> serviceRef : serviceRefs) + { + ServiceReferenceDTO srefDTO = serviceReferenceToDTO(serviceRef); + if (srefDTO != null) + srDTOs[j++] = srefDTO; + } + dto.targetServices = srDTOs; + dtos.add(dto); + } + } + return dtos.toArray( new UnsatisfiedReferenceDTO[dtos.size()] ); + } + + private ServiceReferenceDTO serviceReferenceToDTO( ServiceReference<?> serviceRef) + { + if (serviceRef == null) + return null; + + ServiceReferenceDTO dto = new ServiceReferenceDTO(); + Bundle bundle = serviceRef.getBundle(); + if (bundle != null) + dto.bundle = bundle.getBundleId(); + else + dto.bundle = -1; // No bundle ever has -1 as ID, so this indicates no bundle. + + dto.id = (Long) serviceRef.getProperty(Constants.SERVICE_ID); + dto.properties = deepCopy( serviceRef ); + Bundle[] usingBundles = serviceRef.getUsingBundles(); + if (usingBundles != null) + { + long[] usingBundleIds = new long[usingBundles.length]; + for (int i = 0; i < usingBundles.length; i++) + { + usingBundleIds[i] = usingBundles[i].getBundleId(); + } + dto.usingBundles = usingBundleIds; + } + return dto; + } + + private ComponentHolder<?> getHolderFromDescription(ComponentDescriptionDTO description) + { + if (description.bundle == null) + { + throw new IllegalArgumentException("No bundle supplied in ComponentDescriptionDTO named " + description.name); + } + long bundleId = description.bundle.id; + Bundle b = context.getBundle(bundleId); + String name = description.name; + return componentRegistry.getComponentHolder(b, name); + } + + private ComponentDescriptionDTO holderToDescription( ComponentHolder<?> holder ) + { + ComponentDescriptionDTO dto = new ComponentDescriptionDTO(); + ComponentMetadata m = holder.getComponentMetadata(); + dto.activate = m.getActivate(); + dto.bundle = bundleToDTO(holder.getActivator().getBundleContext()); + dto.configurationPid = m.getConfigurationPid().toArray(new String[m.getConfigurationPid().size()]); + dto.configurationPolicy = m.getConfigurationPolicy(); + dto.deactivate = m.getDeactivate(); + dto.defaultEnabled = m.isEnabled(); + dto.factory = m.getFactoryIdentifier(); + dto.immediate = m.isImmediate(); + dto.implementationClass = m.getImplementationClassName(); + dto.modified = m.getModified(); + dto.name = m.getName(); + dto.properties = deepCopy(m.getProperties()); + dto.references = refsToDTO(m.getDependencies()); + dto.scope = m.getServiceMetadata() == null? null: m.getServiceMetadata().getScope().name(); + dto.serviceInterfaces = m.getServiceMetadata() == null? EMPTY: m.getServiceMetadata().getProvides(); + return dto; + } + + private Map<String, Object> deepCopy(Map<String, Object> source) + { + HashMap<String, Object> result = new HashMap<String, Object>(source.size()); + for (Map.Entry<String, Object> entry: source.entrySet()) + { + result.put(entry.getKey(), convert(entry.getValue())); + } + return result; + } + + private Map<String, Object> deepCopy(ServiceReference<?> source) + { + String[] keys = source.getPropertyKeys(); + HashMap<String, Object> result = new HashMap<String, Object>(keys.length); + for (int i = 0; i< keys.length; i++) + { + result.put(keys[i], convert(source.getProperty(keys[i]))); + } + return result; + } + + Object convert(Object source) + { + if (source.getClass().isArray()) + { + Class<?> type = source.getClass().getComponentType(); + if (checkType(type)) + { + return source; + } + return String.valueOf(source); + /* array copy code in case it turns out to be needed + int length = Array.getLength(source); + Object copy = Array.newInstance(type, length); + for (int i = 0; i<length; i++) + { + Array.set(copy, i, Array.get(source, i)); + } + return copy; + */ + } + if (checkType(source.getClass())) + { + return source; + } + return String.valueOf(source); + } + + boolean checkType(Class<?> type) + { + if (type == String.class) return true; + if (type == Boolean.class) return true; + if (Number.class.isAssignableFrom(type)) return true; + if (DTO.class.isAssignableFrom(type)) return true; + return false; + } + + private ReferenceDTO[] refsToDTO(List<ReferenceMetadata> dependencies) + { + ReferenceDTO[] dtos = new ReferenceDTO[dependencies.size()]; + int i = 0; + for (ReferenceMetadata r: dependencies) + { + ReferenceDTO dto = new ReferenceDTO(); + dto.bind = r.getBind(); + dto.cardinality = r.getCardinality(); + dto.field = r.getField(); + dto.fieldOption = r.getFieldOption(); + dto.interfaceName = r.getInterface(); + dto.name = r.getName(); + dto.policy = r.getPolicy(); + dto.policyOption = r.getPolicyOption(); + dto.scope = r.getScope().name(); + dto.target = r.getTarget(); + dto.unbind = r.getUnbind(); + dto.updated = r.getUpdated(); + dtos[i++] = dto; + } + return dtos; + } + + private BundleDTO bundleToDTO(BundleContext bundleContext) + { + if (bundleContext == null) + { + return null; + } + Bundle bundle = bundleContext.getBundle(); + if (bundle == null) + { + return null; + } + BundleDTO b = new BundleDTO(); + b.id = bundle.getBundleId(); + b.lastModified = bundle.getLastModified(); + b.state = bundle.getState(); + b.symbolicName = bundle.getSymbolicName(); + b.version = bundle.getVersion().toString(); + return b; + } +} Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/info/ScrInfo.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/info/ScrInfo.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/info/ScrInfo.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/apache/felix/scr/info/ScrInfo.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,53 @@ +/* + * 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.scr.info; + +import java.io.PrintWriter; + +/** + * Abstraction of command interface. + * + */ +public interface ScrInfo +{ + + /** + * List in text the components for the bundle specified, or all components if null, sorted by component ID + * @param bundleIdentifier bundle the components are in or null for all components + * @param out PrintStream for normal output + * @throws IllegalArgumentException if nothing can be found + */ + void list(String bundleIdentifier, PrintWriter out); + + /** + * List in text detailed information about the specified components. Components can be specified by + * numeric componentId, component name, a regexp to match for component name, or null for all components. + * @param componentId specifier for desired components + * @param out PrintStream for normal output + * @throws IllegalArgumentException if nothing can be found + */ + void info(String componentId, PrintWriter out); + + /** + * List in text the current SCR configuration + * @param out PrintStream for output. + */ + void config(PrintWriter out); + +} \ No newline at end of file Added: felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/osgi/service/component/ComponentConstants.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/osgi/service/component/ComponentConstants.java?rev=1689973&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/osgi/service/component/ComponentConstants.java (added) +++ felix/sandbox/pderop/dependencymanager.ds/org.apache.felix.dependencymanager.ds/src/org/osgi/service/component/ComponentConstants.java Wed Jul 8 22:10:14 2015 @@ -0,0 +1,142 @@ +/* + * Copyright (c) OSGi Alliance (2004, 2015). All Rights Reserved. + * + * Licensed 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.osgi.service.component; + +import org.osgi.annotation.versioning.ProviderType; + +/** + * Defines standard names for Service Component constants. + * + * @author $Id: 624eb5610c2127d24ce76f16b3cc146cbcf6db57 $ + */ +@ProviderType +public interface ComponentConstants { + /** + * Manifest header specifying the XML documents within a bundle that contain + * the bundle's Service Component descriptions. + * <p> + * The attribute value may be retrieved from the {@code Dictionary} object + * returned by the {@code Bundle.getHeaders} method. + */ + public static final String SERVICE_COMPONENT = "Service-Component"; + + /** + * A component property for a component configuration that contains the name + * of the component as specified in the {@code name} attribute of the + * {@code component} element. The value of this property must be of type + * {@code String}. + */ + public final static String COMPONENT_NAME = "component.name"; + + /** + * A component property that contains the generated id for a component + * configuration. The value of this property must be of type {@code Long}. + * + * <p> + * The value of this property is assigned by Service Component Runtime when + * a component configuration is created. Service Component Runtime assigns a + * unique value that is larger than all previously assigned values since + * Service Component Runtime was started. These values are NOT persistent + * across restarts of Service Component Runtime. + */ + public final static String COMPONENT_ID = "component.id"; + + /** + * A service registration property for a Component Factory that contains the + * value of the {@code factory} attribute. The value of this property must + * be of type {@code String}. + */ + public final static String COMPONENT_FACTORY = "component.factory"; + + /** + * The suffix for reference target properties. These properties contain the + * filter to select the target services for a reference. The value of this + * property must be of type {@code String}. + */ + public final static String REFERENCE_TARGET_SUFFIX = ".target"; + + /** + * The reason the component configuration was deactivated is unspecified. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_UNSPECIFIED = 0; + + /** + * The component configuration was deactivated because the component was + * disabled. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_DISABLED = 1; + + /** + * The component configuration was deactivated because a reference became + * unsatisfied. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_REFERENCE = 2; + + /** + * The component configuration was deactivated because its configuration was + * changed. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_CONFIGURATION_MODIFIED = 3; + + /** + * The component configuration was deactivated because its configuration was + * deleted. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_CONFIGURATION_DELETED = 4; + + /** + * The component configuration was deactivated because the component was + * disposed. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_DISPOSED = 5; + + /** + * The component configuration was deactivated because the bundle was + * stopped. + * + * @since 1.1 + */ + public static final int DEACTIVATION_REASON_BUNDLE_STOPPED = 6; + + /** + * Capability name for Service Component Runtime. + * + * <p> + * Used in {@code Provide-Capability} and {@code Require-Capability} + * manifest headers with the {@code osgi.extender} namespace. For example: + * + * <pre> + * Require-Capability: osgi.extender; + * filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))" + * </pre> + * + * @since 1.3 + */ + public static final String COMPONENT_CAPABILITY_NAME = "osgi.component"; +}
