Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

COSMOS SDD Tooling Examples

Revision as of 15:39, 10 October 2008 by Josh.hester.sas.com (Talk | contribs)

This page contains examples of how to use various functions of the SDD tooling. Please use these examples as references as you create your own applications. Prior knowledge of the SDD is assumed.

SDD Programmatic Interface

The SPI is used to read and write SDDs with a Java interface. These examples will take the reader through reading, writing, and creating SDDs.

Creating SDDs

The SPI is controlled through one instance of a session. In order to use any methods in the SPI, a session must first be created.

SPISession session = SPISession.DEFAULT_INSTANCE;

The SPI objects for the most part correspond to the SDD types. These objects are created from factory objects, so let's create these first.

BaseFactory baseFactory = session.createBaseFactory();
ContentUnitFactory cuFactory = session.createContentUnitFactory();
ArtifactFactory artifactFactory = session.createArtifactFactory();

Each package of the SPI APIs have a factory class. To create an SPI object, all required elements and attributes of the SPI object must be passed into the factory method. This means we'll be creating our deployment descriptor close to the end. Let's create our install artifact first.

Artifact install = artifactFactory.createInstallArtifact();
install.setContentReference("installArtifact");

This sets up our install artifact and sets the content reference to "installArtifact" which will map to one of the contents in the package descriptor. Next we'll add some additional content:

Collection<AdditionalContent> additionalContents = new ArrayList<AdditionalContent>();
additionalContents.add(artifactFactory.createAdditionalContent("bom"));
AdditionalContent additionalContent = artifactFactory.createAdditionalContent("readme");
additionalContent.setType("readme");
additionalContents.add(additionalContent);
install.setAdditionalContents(additionalContents);

A Collection of AdditionalContent types was created and two AdditionalContent objects were created through the artifact factory. The createAdditionalContent method requires the content reference to be defined, which also must match an entry in the package descriptor. All required elements and attributes of the SDD types will be required for the factory methods as well in order to create that type. The final step was to call the appropriate setter method on the install artifact for the additional content.

Now that we have an artifact, we can create our installable unit. Remember that installable units require artifacts.

InstallableUnit iu = cuFactory.createInstallableUnit("IU_ID", "IU_TARGET_REF", install);

We pass in our newly created install artifact to the factory method to create our install artifact.

One of the last objects we need to create are the resources in the topology.

Collection<Resource> resources = new ArrayList<Resource>();
Resource resource = baseFactory.createResource("OS", "OperatingSystem");
resource.setName("Windows Vista");
resource.setDescription(new TranslatableString("The operationg system of the computer.", "osDesc"));
resource.setShortDescription(new TranslatableString("Computer's OS", "osShortDesc"));
resources.add(resource);

Here we have added one resource to our SDD. The factory method takes the reference ID and then the resource type as parameters. In the two description elements, we've introduced the ability for the SDD to handle translatable strings. The first parameter is the default string. The second parameter is the translation key in the properties file that will accompany the SDD.

Now we'll create our final object:

byte b[] = {127, 43, 65, 119, 19, 90, 87, 2, 45, 73, 25, 41, 76, 14, 54, 93};
DeploymentDescriptor dd = baseFactory.createDeploymentDescriptor("1.0", b, 
     Calendar.getInstance().getTime(), iu, resources);

We have everything we need and we finally create the deployment descriptor object. We pass in the schema version (usually 1.0), the descriptor UUID, last modified time, our installable unit, and our resources. Similar techniques can be used to create the package descriptor and add additional elements to the SDD.

Reading SDDs

Using only DOM and the SPI

For reading an SDD, we first need a DOM document. There's a few things I like to setup before reading the actual file into memory.

DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setValidating(false);
docBuilderFactory.setNamespaceAware(true);

DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
docBuilder.setErrorHandler(new ErrorHandler()
{
    public void warning(SAXParseException e) throws SAXException {
        printErrorMessage(e);
    }

    public void error(SAXParseException e) throws SAXException {
        printErrorMessage(e);
    }

    public void fatalError(SAXParseException e) throws SAXException {
        printErrorMessage(e);
    }
            
    private void printErrorMessage(SAXParseException e)
    {
        System.out.println("Line: " + e.getLineNumber() + ": " + e.getMessage());
    }
});

With that all set, we'll create the Document object.

Document doc = docBuilder.parse(new InputSource("mySDD.xml"));

And now our deployment descriptor.

SPISession session = SPISession.DEFAULT_INSTANCE;
DeploymentDescriptor dd = (DeploymentDescriptor) session.buildDescriptorFromDocument(doc);

At this point, you can run through all the getter methods to get at the data you need to read.

Using the Validator

The validator has methods to read files from the disk to provide you with a Document object.

SDD_DAS sddDas = new SDD_DASImpl();
Document doc = sddDas.loadDocument(new FileInputStream("mySDD.xml"));
SPISession session = SPISession.DEFAULT_INSTANCE;
DeploymentDescriptor dd = (DeploymentDescriptor) session.buildDescriptorFromDocument(doc);

Writing SDDs

Using only DOM and the SPI

Once you've either created an SDD or read one in to change some values, you probably want to write it back to the system. Let's setup some DOM objects first.

DOMImplementationRegistry domRegistry = DOMImplementationRegistry.newInstance();
DOMImplementationLS domImpl = (DOMImplementationLS) domRegistry.getDOMImplementation("LS");
LSSerializer serializer = domImpl.createLSSerializer();
serializer.getDomConfig().setParameter("format-pretty-print", true);

This will format our xml like we're used to seeing. Otherwise you may see everything on one line. Now we write it to a file.

Document doc = dd.getOwnerDocument();
FileWriter fw = new FileWriter("mySDD.xml");
BufferedWriter bw = new BufferedWriter(fw);

bw.write(lsSerializer.writeToString(doc));
bw.close();

The dd object here is our deployment descriptor.

Using the Validator

The SDD Validator has methods to write documents to the disk. This will write the SDD to the file mySDD.xml. The null parameter corresponds to the encoding, which defaults to UTF-8. The false parameter tells the validator to save the SDD without validating.

SDD_DAS deploymentDescriptorDAS = new SDD_DASImpl();
deploymentDescriptorDAS.saveDocument(dd.getOwnerDocument(), new FileOutputStream("mySDD.xml"), null, false);

Validator

The validator is used to verify the SDD follows the constraints of the schema. It also allows you to specify your own rules to constrain the SDD. First, we'll look at the easiest way to validate the SDD against the schema.

SDD_DAS deploymentDescriptorDAS = new SDD_DASImpl();
Collection<XMLValidationError> validationErrors = deploymentDescriptorDAS.validate(document);
if (validationErrors.size() > 0) 
{
	for (XMLValidationError error : validationErrors) {
		System.err.println(error.getErrorMessage());
	}
}

Using custom rules

If a custom rule is desired, we'll need to create a rule that the validator can understand. To do that, we create a class that implements ValidationRule. ValidationRule has one method to implement.

public Collection<XMLValidationError> validate(InputStream xmlStream)

It receives an InputStream and returns a collection of XMLValidationError objects. Let's take a look at a sample rule.

public class SchemaVersionValidationRule implements ValidationRule 
{
  String schemaVersion;

  public SchemaVersionValidationRule(String schemaVersion) 
  {
    this.schemaVersion = schemaVersion;
  }

  public Collection<XMLValidationError> validate(InputStream xmlStream) 
  {
    Collection<XMLValidationError> validationErrors = new Vector<XMLValidationError>();

    SDD_DAS sddDas = new SDD_DASImpl();
    Document ddDocument = null;
    try
    {
      ddDocument = sddDas.loadDocument(xmlStream);
    }
    catch (Exception e)
    {
      e.printStackTrace();
      System.exit(1);
    }

    Element dd = ddDocument.getDocumentElement();
    String ddSchema = dd.getAttribute("schemaVersion");

    if (!ddSchema.equals(schemaVersion))
    {
      String errorMsg = "The schema version is not " + schemaVersion;
      validationErrors.add(new XMLValidationError(errorMsg, -1, -1, this, XMLValidationError.ERROR));
    }

    return validationErrors;
  }		
}

This custom rule looks at the schema version in the SDD and returns an error if the wrong version is specified. The constructor of the rule is where we specify the version of the schema we want to see in the SDD. Next is the validate method. We setup the Collection of XMLValidationError types first. Then we get the Document object of our SDD. After that, we get the document element and from that we get the schemaVersion element. We compare this against the version passed into the constructor. If they are different, we create a new XMLValidationError object and add it to the collection. Then we return the collection of errors.

To call this custom rule as a part of our normal validation, we do the following.

SDD_DAS ddDAS = new SDD_DASImpl();
ValidationRule customValidationRule = new SchemaVersionValidationRule("1.0");
ddDAS.addValidation(customValidationRule);

Collection<XMLValidationError> validationErrors = ddDAS.validate(ddDocument);
for (XMLValidationError error : validationErrors) 
{
  System.err.println(error.getErrorMessage());
}

Build Time Generator (BTG)

The BTG will be used to read various sources into SDD fragments and aggregate their content into a single SDD. The Aggregator is still under development, these examples will serve as a guide to use the readers and also how to kick off the merging process from within the Aggregator.

Requisite Packages

In order to use the BTG you will need to pull down the following packages at a minimum:

org.eclipse.cosmos.me.deployment.sdd.common.spi
org.eclipse.cosmos.me.deployment.sdd.common.validation
org.eclipse.cosmos.me.deployment.sdd.tooling.btg

Also you will need to pull down these packages if you wish to use them:

org.eclipse.cosmos.me.deployment.sdd.tooling.btg.aggregator
org.eclipse.cosmos.me.deployment.sdd.tooling.btg.plugin.sddreader
org.eclipse.cosmos.me.deployment.sdd.tooling.btg.plugin.rpmreader

Properties File

The BTG requires a properties file in order to operate. The format is as follows:

[org.eclipse.cosmos.me.deployment.sdd.tooling.btg]
OutputFileNameBase = ESR

followed by a list of the BTG plugins (ie: the aggregator or any readers) you wish to invoke.

Example:

[org.eclipse.cosmos.me.deployment.sdd.tooling.btg.aggregator]
Enabled = true

[org.eclipse.cosmos.me.deployment.sdd.tooling.btg.plugin.sddreader]
Enabled = true
# Name of xml file to read from
FileName = C:\sdd1.xml

[org.eclipse.cosmos.me.deployment.sdd.tooling.btg.plugin.rpmreader]
Enabled = true
# Name of rpm file to read from
FileName = C:\sdd2.rpm

Command Line Arguments

The BTG requires that you specify where the properties file is within a command line argument. The format is as follows:

-propertiesFile "C:\BTG.ini"

Run Configuration

In order to run the BTG, you will need to create a run configuration for it within eclipse. To do this, Click on the down arrow next to the run button in eclipse and select run configurations. Then right click on Eclipse Application on the left, and select "new". Call the new configuration whatever you'd like, I chose "btg". On the right under the main tab for the new configuration, make sure run an application is selected, with the application specified being:

org.eclipse.cosmos.me.deployment.sdd.tooling.btg.application

Then under the arguments tab, clear out the program arguments section completely, and then add in your command line argument from above.

Using the Aggregator

The readers that are specified in the properties file will be invoked and their SDD's will be passed into the Aggregator's aggregateSDDData function within the
Collection<SDDFragment> fragments
variable. From there you can pass the fragments along to the
DeploymentDescriptorType.merge(DeploymentDescriptor dd1, DeploymentDescriptor dd2)
function. This will kick off the merging process. This functionality is still in research and as such is currently commented out.

Back to the top