FELIX-593 change accepted and default values for immediate attribute
with respect to the factory attribute
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@662680 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
index f8ca2d1..35fdee5 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
@@ -188,29 +188,20 @@
private ComponentManager createComponentManager( Dictionary configuration, boolean synchronous )
{
long componentId = m_componentRegistry.createComponentId();
- ComponentManager cm = ManagerFactory.createManager( getActivator(), getComponentMetadata(), componentId );
-
+ ImmediateComponentManager cm = new ImmediateComponentManager( getActivator(), getComponentMetadata(),
+ componentId );
+
// add the new component to the activators instances
getActivator().getInstanceReferences().add( cm );
// register with the internal set of created components
m_createdComponents.put( cm, cm );
- // inject configuration if possible
- if ( cm instanceof ImmediateComponentManager )
- {
- ( ( ImmediateComponentManager ) cm ).setFactoryProperties( configuration );
- }
+ // inject configuration
+ cm.setFactoryProperties( configuration );
// enable synchronously or asynchronously depending on the flag
- if ( cm instanceof AbstractComponentManager )
- {
- ( ( AbstractComponentManager ) cm ).enable( synchronous );
- }
- else
- {
- cm.enable();
- }
+ cm.enable( synchronous );
return cm;
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
index 07613e7..ccc1d28 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
@@ -201,9 +201,9 @@
* This method may only be trusted after this instance has been validated
* by the {@link #validate()} call. Else it will either return the value
* of an explicitly set "immediate" attribute or return false if a service
- * element is set or true otherwise. This latter default value deduction
- * may be unsafe while the descriptor has not been completely read.
- *
+ * element or the factory attribute is set or true otherwise. This latter
+ * default value deduction may be unsafe while the descriptor has not been
+ * completely read.
*
* @return a boolean that defines the activation policy
*/
@@ -213,8 +213,8 @@
return m_immediate.booleanValue();
}
- // deduce default value from service element presence
- return m_service == null;
+ // deduce default from service element and factory attribute presence
+ return m_service == null && m_factory == null;
}
/**
@@ -265,60 +265,90 @@
/**
* Method used to verify if the semantics of this metadata are correct
*/
- void validate() {
-
- // First check if the properties are valid (and extract property values)
- Iterator propertyIterator = m_propertyMetaData.iterator();
- while ( propertyIterator.hasNext() ) {
- PropertyMetadata propMeta = (PropertyMetadata) propertyIterator.next();
- propMeta.validate();
- m_properties.put(propMeta.getName(), propMeta.getValue());
+ void validate()
+ {
+
+ // 112.10 The name of the component is required
+ if ( m_name == null )
+ {
+ throw new ComponentException( "The component name has not been set" );
}
- m_propertyMetaData.clear();
-
- // Check that the provided services are valid too
- if(m_service != null) {
- m_service.validate();
- }
-
- // Check that the references are ok
- Iterator referenceIterator = m_references.iterator();
- while ( referenceIterator.hasNext() ) {
- ((ReferenceMetadata)referenceIterator.next()).validate();
- }
-
- // 112.10 The name of the component is required
- if( m_name == null ) {
- throw new ComponentException("The component name has not been set");
- }
-
- // 112.10 There must be one implementation element and the class atribute is required
- if ( m_implementationClassName == null ) {
- throw new ComponentException("The implementation class name has not been set for this component");
- }
-
- // 112.2.3 A delayed component specifies a service, is not specified to be a factory component
- // and does not have the immediate attribute of the component element set to true.
- if ( m_immediate != null && isImmediate() == false && m_service == null ) {
- throw new ComponentException( "Component '" + m_name
- + "' is specified as being delayed but does not provide any service." );
- }
-
- if ( m_factory != null && isImmediate() == false) {
- throw new ComponentException("A factory cannot be a delayed component");
- }
-
- // 112.4.6 The serviceFactory attribute (of a provided service) must not be true if
- // the component is a factory component or an immediate component
- if ( m_service != null ) {
- if ( m_service.isServiceFactory() && ( isFactory() || isImmediate() ) ) {
- throw new ComponentException( "A ServiceFactory service cannot be a factory or immediate component" );
+
+ // 112.10 There must be one implementation element and the class atribute is required
+ if ( m_implementationClassName == null )
+ {
+ throw validationFailure( "Implementation class name missing" );
+ }
+
+ // Next check if the properties are valid (and extract property values)
+ Iterator propertyIterator = m_propertyMetaData.iterator();
+ while ( propertyIterator.hasNext() )
+ {
+ PropertyMetadata propMeta = ( PropertyMetadata ) propertyIterator.next();
+ propMeta.validate( this );
+ m_properties.put( propMeta.getName(), propMeta.getValue() );
+ }
+ m_propertyMetaData.clear();
+
+ // Check that the provided services are valid too
+ if ( m_service != null )
+ {
+ m_service.validate( this );
+ }
+
+ // Check that the references are ok
+ Iterator referenceIterator = m_references.iterator();
+ while ( referenceIterator.hasNext() )
+ {
+ ( ( ReferenceMetadata ) referenceIterator.next() ).validate( this );
+ }
+
+ // verify value of immediate attribute if set
+ if ( m_immediate != null )
+ {
+ if ( isImmediate() )
+ {
+ // FELIX-593: 112.4.3 clarification, immediate is false for factory
+ if ( isFactory() )
+ {
+ throw validationFailure( "Factory cannot be immediate" );
+ }
+ }
+ else
+ {
+ // 112.2.3 A delayed component specifies a service, is not specified to be a factory component
+ // and does not have the immediate attribute of the component element set to true.
+ // FELIX-593: 112.4.3 clarification, immediate may be true for factory
+ if ( m_service == null && !isFactory() )
+ {
+ throw validationFailure( "Delayed must provide a service or be a factory" );
+ }
}
}
-
- m_validated = true;
- // TODO: put a similar flag on the references and the services
+ // 112.4.6 The serviceFactory attribute (of a provided service) must not be true if
+ // the component is a factory component or an immediate component
+ if ( m_service != null )
+ {
+ if ( m_service.isServiceFactory() && ( isFactory() || isImmediate() ) )
+ {
+ throw validationFailure( "ServiceFactory cannot be factory or immediate" );
+ }
+ }
+
+ m_validated = true;
+ // TODO: put a similar flag on the references and the services
}
+
+ /**
+ * Returns a <code>ComponentException</code> for this compeonent with the
+ * given explanation for failure.
+ *
+ * @param reason The explanation for failing to validate this component.
+ */
+ ComponentException validationFailure( String reason )
+ {
+ return new ComponentException( "Component " + getName() + " validation failed: " + reason );
+ }
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java
index ab8068e..f30ea0e 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java
@@ -195,11 +195,12 @@
/**
* Method used to verify if the semantics of this metadata are correct
*/
- public void validate(){
- if(m_name == null)
- {
- throw new ComponentException("Property name attribute is mandatory");
- }
+ public void validate( ComponentMetadata componentMetadata )
+ {
+ if ( m_name == null )
+ {
+ throw componentMetadata.validationFailure( "Property name attribute is mandatory" );
+ }
}
private Object toType(String value) {
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java
index 2378642..75b243f 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java
@@ -330,16 +330,16 @@
* Method used to verify if the semantics of this metadata are correct
*
*/
- void validate()
+ void validate( ComponentMetadata componentMetadata )
{
if ( m_name == null )
{
- throw new ComponentException( "the name for the reference must be set" );
+ throw componentMetadata.validationFailure( "A name must be declared for the reference" );
}
if ( m_interface == null )
{
- throw new ComponentException( "the interface for the reference must be set" );
+ throw componentMetadata.validationFailure( "An interface must be declared for the reference" );
}
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java
index 665a400..1d97d34 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java
@@ -1,103 +1,106 @@
-/*
- * 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;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.osgi.service.component.ComponentException;
-
-/**
- * This class contains the metadata associated to a service that is provided
- * by a component
- *
- */
-public class ServiceMetadata {
-
- // 112.4.6 Flag that indicates if the service is a ServiceFactory
- private boolean m_serviceFactory = false;
-
- // List of provided interfaces
- private List m_provides = new ArrayList();
-
- // 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;
- }
-
- /**
- * 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);
- }
-
- /**
- * Return the flag that defines if it is a service factory or not
- *
- * @return a boolean flag
- */
- public boolean isServiceFactory() {
- return m_serviceFactory;
- }
-
- /**
- * Returns the implemented interfaces
- *
- * @return the implemented interfaces as a string array
- */
- public String [] getProvides() {
- String provides[] = new String[m_provides.size()];
- Iterator it = m_provides.iterator();
- int count = 0;
- while (it.hasNext())
- {
- provides[count++] = it.next().toString();
- }
- return provides;
- }
-
- /**
- * Verify if the semantics of this metadata are correct
- *
- */
- void validate() {
- if(m_provides.size() == 0) {
- throw new ComponentException("At least one provided interface must be given");
- }
- }
-}
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.osgi.service.component.ComponentException;
+
+/**
+ * This class contains the metadata associated to a service that is provided
+ * by a component
+ *
+ */
+public class ServiceMetadata {
+
+ // 112.4.6 Flag that indicates if the service is a ServiceFactory
+ private boolean m_serviceFactory = false;
+
+ // List of provided interfaces
+ private List m_provides = new ArrayList();
+
+ // 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;
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Return the flag that defines if it is a service factory or not
+ *
+ * @return a boolean flag
+ */
+ public boolean isServiceFactory() {
+ return m_serviceFactory;
+ }
+
+ /**
+ * Returns the implemented interfaces
+ *
+ * @return the implemented interfaces as a string array
+ */
+ public String [] getProvides() {
+ String provides[] = new String[m_provides.size()];
+ Iterator it = m_provides.iterator();
+ int count = 0;
+ while (it.hasNext())
+ {
+ provides[count++] = it.next().toString();
+ }
+ return provides;
+ }
+
+ /**
+ * 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" );
+ }
+ }
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java b/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
new file mode 100644
index 0000000..10dd3a2
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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;
+
+
+import junit.framework.TestCase;
+
+import org.osgi.service.component.ComponentException;
+
+
+public class ComponentMetadataTest extends TestCase
+{
+
+ // test various combinations of component metadata with respect to
+ // -- immediate: true, false, unset
+ // -- factory: set, unset
+ // -- service: set, unset
+ // -- servicefactory: true, false, unset
+
+ public void testImmediate()
+ {
+ // immediate is default true if no service element is defined
+ final ComponentMetadata cm0 = createComponentMetadata( null, null );
+ cm0.validate();
+ assertTrue( "Component without service must be immediate", cm0.isImmediate() );
+
+ // immediate is explicit true
+ final ComponentMetadata cm1 = createComponentMetadata( Boolean.TRUE, null );
+ cm1.validate();
+ assertTrue( "Component must be immediate", cm1.isImmediate() );
+
+ // immediate is explicit true
+ final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, null );
+ cm2.setService( createServiceMetadata( null ) );
+ cm2.validate();
+ assertTrue( "Component must be immediate", cm2.isImmediate() );
+
+ // immediate is explicit true
+ final ComponentMetadata cm3 = createComponentMetadata( Boolean.TRUE, null );
+ cm3.setService( createServiceMetadata( Boolean.FALSE ) );
+ cm3.validate();
+ assertTrue( "Component must be immediate", cm3.isImmediate() );
+
+ // validation failure of immediate with service factory
+ final ComponentMetadata cm4 = createComponentMetadata( Boolean.TRUE, null );
+ cm4.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm4.validate();
+ fail( "Expect validation failure for immediate service factory" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+ }
+
+
+ public void testDelayed()
+ {
+ // immediate is default false if service element is defined
+ final ComponentMetadata cm0 = createComponentMetadata( null, null );
+ cm0.setService( createServiceMetadata( null ) );
+ cm0.validate();
+ assertFalse( "Component with service must be delayed", cm0.isImmediate() );
+
+ // immediate is default false if service element is defined
+ final ComponentMetadata cm1 = createComponentMetadata( null, null );
+ cm1.setService( createServiceMetadata( Boolean.TRUE ) );
+ cm1.validate();
+ assertFalse( "Component with service must be delayed", cm1.isImmediate() );
+
+ // immediate is default false if service element is defined
+ final ComponentMetadata cm2 = createComponentMetadata( null, null );
+ cm2.setService( createServiceMetadata( Boolean.FALSE ) );
+ cm2.validate();
+ assertFalse( "Component with service must be delayed", cm2.isImmediate() );
+
+ // immediate is false if service element is defined
+ final ComponentMetadata cm3 = createComponentMetadata( Boolean.FALSE, null );
+ cm3.setService( createServiceMetadata( null ) );
+ cm3.validate();
+ assertFalse( "Component with service must be delayed", cm3.isImmediate() );
+
+ // immediate is false if service element is defined
+ final ComponentMetadata cm4 = createComponentMetadata( Boolean.FALSE, null );
+ cm4.setService( createServiceMetadata( Boolean.TRUE ) );
+ cm4.validate();
+ assertFalse( "Component with service must be delayed", cm4.isImmediate() );
+
+ // immediate is false if service element is defined
+ final ComponentMetadata cm5 = createComponentMetadata( Boolean.FALSE, null );
+ cm5.setService( createServiceMetadata( Boolean.FALSE ) );
+ cm5.validate();
+ assertFalse( "Component with service must be delayed", cm5.isImmediate() );
+
+ // explicit delayed fails when there is no service
+ final ComponentMetadata cm6 = createComponentMetadata( Boolean.FALSE, null );
+ try
+ {
+ cm6.validate();
+ fail( "Expect validation failure for delayed component without service" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+ }
+
+
+ public void testFactory()
+ {
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm0 = createComponentMetadata( null, "factory" );
+ cm0.validate();
+ assertFalse( "Component with factory must be delayed", cm0.isImmediate() );
+
+ // immediate is false if factory is defined
+ final ComponentMetadata cm1 = createComponentMetadata( Boolean.FALSE, "factory" );
+ cm1.validate();
+ assertFalse( "Component with factory must be delayed", cm1.isImmediate() );
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, "factory" );
+ try
+ {
+ cm2.validate();
+ fail( "Expect validation failure for immediate factory component" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm10 = createComponentMetadata( null, "factory" );
+ cm10.setService( createServiceMetadata( null ) );
+ cm10.validate();
+ assertFalse( "Component with factory must be delayed", cm10.isImmediate() );
+
+ // immediate is false if factory is defined
+ final ComponentMetadata cm11 = createComponentMetadata( Boolean.FALSE, "factory" );
+ cm11.setService( createServiceMetadata( null ) );
+ cm11.validate();
+ assertFalse( "Component with factory must be delayed", cm11.isImmediate() );
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm12 = createComponentMetadata( Boolean.TRUE, "factory" );
+ cm12.setService( createServiceMetadata( null ) );
+ try
+ {
+ cm12.validate();
+ fail( "Expect validation failure for immediate factory component" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm20 = createComponentMetadata( null, "factory" );
+ cm20.setService( createServiceMetadata( Boolean.FALSE ) );
+ cm20.validate();
+ assertFalse( "Component with factory must be delayed", cm20.isImmediate() );
+
+ // immediate is false if factory is defined
+ final ComponentMetadata cm21 = createComponentMetadata( Boolean.FALSE, "factory" );
+ cm21.setService( createServiceMetadata( Boolean.FALSE ) );
+ cm21.validate();
+ assertFalse( "Component with factory must be delayed", cm21.isImmediate() );
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm22 = createComponentMetadata( Boolean.TRUE, "factory" );
+ cm22.setService( createServiceMetadata( Boolean.FALSE ) );
+ try
+ {
+ cm22.validate();
+ fail( "Expect validation failure for immediate factory component" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm30 = createComponentMetadata( null, "factory" );
+ cm30.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm30.validate();
+ fail( "Expect validation failure for factory component with service factory" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ // immediate is false if factory is defined
+ final ComponentMetadata cm31 = createComponentMetadata( Boolean.FALSE, "factory" );
+ cm31.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm31.validate();
+ fail( "Expect validation failure for factory component with service factory" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ // immediate is default false if factory is defined
+ final ComponentMetadata cm32 = createComponentMetadata( Boolean.TRUE, "factory" );
+ cm32.setService( createServiceMetadata( Boolean.TRUE ) );
+ try
+ {
+ cm32.validate();
+ fail( "Expect validation failure for immediate factory component with service factory" );
+ }
+ catch ( ComponentException ce )
+ {
+ // expect
+ }
+
+ }
+
+
+ private ComponentMetadata createComponentMetadata( Boolean immediate, String factory )
+ {
+ ComponentMetadata meta = new ComponentMetadata();
+ meta.setName( "place.holder" );
+ meta.setImplementationClassName( "place.holder.implementation" );
+ if ( immediate != null )
+ {
+ meta.setImmediate( immediate.booleanValue() );
+ }
+ if ( factory != null )
+ {
+ meta.setFactoryIdentifier( factory );
+ }
+ return meta;
+ }
+
+
+ private ServiceMetadata createServiceMetadata( Boolean serviceFactory )
+ {
+ ServiceMetadata meta = new ServiceMetadata();
+ meta.addProvide( "place.holder.service" );
+ if ( serviceFactory != null )
+ {
+ meta.setServiceFactory( serviceFactory.booleanValue() );
+ }
+ return meta;
+ }
+}