9 Replies Latest reply on May 23, 2012 3:12 PM by thomas.diesler

    Priming the repository

    thomas.diesler

      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

          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
            bosschaert

            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:

            {code}

            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)

            {code}

             

            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

              Ok, that is a bug - fixing ...

              • 4. Re: Priming the repository
                thomas.diesler

                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
                  bosschaert

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

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

                  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):

                  {code:xml}<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>{code}

                   

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

                   

                  {code}RequirementImpl requirement = new RequirementImpl("osgi.wiring.bundle",

                    "(&(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));{code}

                   

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

                  • 6. Re: Priming the repository
                    thomas.diesler

                    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
                      bosschaert

                      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

                        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

                          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