9 Replies Latest reply: May 23, 2012 3:12 PM by Thomas Diesler RSS

Priming the repository

Thomas Diesler Master

David says

 

I have been able to get the repository bundle running in the TCK framework and am now looking a priming it with content.

 

How am I supposed to do this? I looked at some of the tests and came up with the following, but this may not be correct:

 

org.jboss.osgi.repository.RepositoryStorage rs = … from Service Registry ... 
URL contentURL = bundle.getResource("xml/testcontent1.xml"); 
RepositoryReader reader = RepositoryXMLReader.create(contentURL.openStream()); 
XResource resource = reader.nextResource(); 
while (resource != null) { 
     rs.addResource(resource); 
     resource = reader.nextResource(); 
} 

 

The above caused some issues for me, but before diving into those I'd like to understand what the approach is that I'm supposed to use.

  • 1. Re: Priming the repository
    Thomas Diesler Master

    The RepositoryStorage should be obtained from the Repository like this

     

    RepositoryStorage storage = ((XPersistentRepository)getRepository()).getRepositoryStorage();
    

     

    in jbosgi-repository-1.3.0.Beta3 RepositoryStorage is no longer directly available as a service.

     

    This code

     

     

    RepositoryReader reader = RepositoryXMLReader.create(contentURL.openStream()); 
    XResource resource = reader.nextResource(); 
    while (resource != null) { 
         rs.addResource(resource); 
         resource = reader.nextResource(); 
    } 

     

     

    is fine, except that the name 'contentURL' usualy means the URL to the resource content which is available as an attribute on the content capability.

    Part of the resource metadata (in XML) is that URL - it must point to real bytes - otherwise the RepositoryStorage cannot copy them.

     

    Another approach would be to use this API

     

    /**
    * Add a resource from the given input stream
    *
    * @param mime An IANA defined MIME type for the format
    * @param input The bytes for the resource
    * @return The resource being added, which may be a modified copy of the give resource
    * @throws RepositoryStorageException If there is a problem storing the resource
    */
    XResource addResource(String mime, InputStream input) throws RepositoryStorageException;
    
  • 2. Re: Priming the repository
    David Bosschaert Expert

    Thanks Thomas.

    I would like to use the Repository XML as defined by the OSGi R5 spec, so in that case I should probably used the RepositoryXMLReader.

     

    The issue I'm encountering is the following with the code snippet as above:

    java.lang.ClassCastException: org.jboss.osgi.resolver.spi.AbstractResource cannot be cast to org.osgi.service.repository.RepositoryContent
     at org.jboss.osgi.repository.core.FileBasedRepositoryStorage.addResourceInternal(FileBasedRepositoryStorage.java:123)
     at org.jboss.osgi.repository.core.FileBasedRepositoryStorage.addResource(FileBasedRepositoryStorage.java:106)
     at org.jboss.test.osgi.repository.tck.Activator.primeRepository(Activator.java:96)
    

     

     

    The FileRepository casts the XResource to a RespositoryContent, however resources created by the RepositoryXMLReader don't seem to implement this interface.

  • 3. Re: Priming the repository
    Thomas Diesler Master

    Ok, that is a bug - fixing ...

  • 4. Re: Priming the repository
    Thomas Diesler Master

    Fixed in jbosgi-repository-1.3.0.Beta4

     

    @Test
    public void testAddResource() throws Exception {
    
       // Assert empty repository
       Assert.assertNull(storage.getRepositoryReader().nextResource());
    
       // Write the bundle to the location referenced by repository-testA.xml
       getBundleA().as(ZipExporter.class).exportTo(new File("./target/bundleA.jar"), true);
    
       RepositoryReader reader = getRepositoryReader("xml/repository-testA.xml");
       XResource resource = storage.addResource(reader.nextResource());
    
       verifyResource(resource);
    }
    
  • 5. Re: Priming the repository
    David Bosschaert Expert

    The exception is gone and I can now see the following message appearing, which looks good:

     INFO: JBOSGI020400: Resource added: URLResource[org.osgi.test.cases.repository.tb1:1.0.0.test]

     

    However, I don't seem to be able to retrieve the resource using an arbitrary requirement yet.

     

    For example, my resource is defined in XML as follows (the value specified with URL is where the resource can actually be found):

    <repository name='OSGi Repository' increment='1' xmlns='http://www.osgi.org/xmlns/repository/v1.0.0'>
      <resource>
        <capability namespace='osgi.identity'>
          <attribute name='osgi.identity' value='org.osgi.test.cases.repository.tb1' />
          <attribute name='version' type='Version' value='1.0.0.test' />
          <attribute name='type' value='osgi.bundle' />
        </capability>
        <capability namespace='osgi.content'>
          <attribute name='osgi.content' value='a20e2054404fff56d0de8be82cfdace9aec45027b8a1acb4b65b62e034801714' />
          <attribute name='url' value='bundleresource://5.fwk637148086/tb1.jar' />
          <attribute name='size' type='Long' value='3796' />
          <attribute name='mime' value='application/vnd.osgi.bundle' />
        </capability>
        <capability namespace='osgi.wiring.bundle'>
          <attribute name='osgi.wiring.bundle' value='org.osgi.test.cases.repository.tb1' />
          <attribute name='bundle-version' type='Version' value='1.0.0.test' />
        </capability>
        <capability namespace='osgi.wiring.package'>
          <attribute name='osgi.wiring.package' value='org.osgi.test.cases.repository.tb1.pkg1' />
          <attribute name='version' type='Version' value='0.9' />
          <attribute name='bundle-version' type='Version' value='1.0.0.test' />
          <attribute name='bundle-symbolic-name' value='org.osgi.test.cases.repository.tb1' />
        </capability>
      </resource>
    </repository>

     

     

    Then, I use the following to try to retrieve the resource:

     

    RequirementImpl requirement = new RequirementImpl("osgi.wiring.bundle",
      "(&amp;(osgi.wiring.bundle=org.osgi.test.cases.repository.tb1)(bundle-version=1.0.0.test))");
    Map<Requirement, Collection<Capability>> r = repository.findProviders(Collections.singleton(requirement));

     

     

    but the result is always empty. Is this functionality missing at this point in time?

  • 6. Re: Priming the repository
    Thomas Diesler Master

    Fixed in Allow nsvalue in filter if not found as attribute on the requirement

     

    public void testRequireBundleWithFilter() throws Exception {
    
         XRequirementBuilder builder = XRequirementBuilder.create(BundleNamespace.BUNDLE_NAMESPACE);
         builder.getDirectives().put(BundleNamespace.REQUIREMENT_FILTER_DIRECTIVE, "(osgi.wiring.bundle=org.acme.pool)");
         XRequirement req = builder.getRequirement();
    
         Collection<Capability> providers = storage.findProviders(req);
         Assert.assertNotNull(providers);
         Assert.assertEquals(1, providers.size());
    
         XCapability cap = (XCapability) providers.iterator().next();
         Assert.assertNotNull(cap);
    }
    

     

    This however relies on a hack that tries to extract the namespace value from the filter if it is not given as attribute value

     

    static CacheKey create(Requirement req) {
        String namespace = req.getNamespace();
        String value = (String) req.getAttributes().get(namespace);
        if (value == null) {
            Filter filter = getRequiredFilter(req);
            String filterstr = filter.toString();
            int index = filterstr.indexOf("(" + namespace + "=");
            if (index >= 0) {
                value = filterstr.substring(index + namespace.length() + 2);
                index = value.indexOf(")");
                value = value.substring(0, index);
            }
        }
        return new CacheKey(namespace, value);
    }
    
  • 7. Re: Priming the repository
    David Bosschaert Expert

    Thomas Diesler wrote:

     

    This however relies on a hack that tries to extract the namespace value from the filter if it is not given as attribute value

    Not sure why this is needed. Shouldn't the filter be simply applied to the attributes of the capability, e.g. using Filter.matches()? (Given that Capability.getNamespace() equals Requirement.getNamespace())

     

    Basically you should just be able to take the value of the 'filter' directive of the requirement and match that to the map of attributes of the capability. I don't think any special tricks are needed (i.e. the capability attribute that has the same name as the capability namespace doesn't need any special code), or am I missing something?

  • 8. Re: Priming the repository
    Thomas Diesler Master

    We internally cache by key [namespace:value]. Otherwise we would have very large collections of capabilities to iterate over.

  • 9. Re: Priming the repository
    Thomas Diesler Master

    FYI, when adding a resource to the store the sha256 and the size are recalculated and the content url is rewritten. You can find the content & resulting xml in osgi-store/[repository-bundle]/repository