How to Use the SAS Java Metadata Interface


Sample Program

The following is a sample program that illustrates how to connect to a metadata server, create new objects, and read existing objects.

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.sas.metadata.remote.AssociationList;
import com.sas.metadata.remote.CMetadata;
import com.sas.metadata.remote.Column;
import com.sas.metadata.remote.MdException;
import com.sas.metadata.remote.MdFactory;
import com.sas.metadata.remote.MdFactoryImpl;
import com.sas.metadata.remote.MdOMIUtil;
import com.sas.metadata.remote.MdOMRConnection;
import com.sas.metadata.remote.MdObjectStore;
import com.sas.metadata.remote.MetadataObjects;
import com.sas.metadata.remote.PhysicalTable;
import com.sas.metadata.remote.TextStore;


/**
 * This is a test class that contains the examples for SAS Java Metadata Interface.
 */
public class MdTesterExamples
{

   /**
    * This is the object factory used to create objects.
    */
   private MdFactory _factory = null;

   /**
    * Default constructor
    */
   public MdTesterExamples()
   {
      //intialize the factory
      initializeFactory();
   }

   private void initializeFactory()
   {
      try
      {
         // Construct a new factory.  The boolean parameter is used to determine if
         // the application is running in a remote or local environment.  If the
         // data does not need to be accessible across remote JVMs, then
         // "false" can be used.
         _factory = new MdFactoryImpl(false);

         // Intialize debug logging if necessary
         boolean debug = false;
         if (debug)
         {
            _factory.setDebug(true);
            _factory.setLoggingEnabled(true);

            // Set the output streams for logging.  The logging output can be
            // directed to any OutputStream, including a file.
            _factory.getUtil().setOutputStream(System.out);
            _factory.getUtil().setLogStream(System.out);
         }
         else
         {
            _factory.setDebug(false);
            _factory.setLoggingEnabled(false);
         }

         // To be notified when changes have been persisted to the metadata server
         // within this factory (this includes adding objects, updating objects, and
         // deleting objects), we can add a listener to the factory.
         //
         // See MdFactory.addMdFactoryListener()
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   /**
    * This example makes a connection to the metadata server and checks
    * exceptions if there is an error connecting.  The server name, port,
    * user, and password variables must be substituted with actual values.
    * @return true if the connection was successful
    */
   public boolean connectToServer()
   {
      String serverName = "MACHINE_NAME";
      String serverPort = "8561";
      String serverUser = "USERNAME";
      String serverPass = "PASSWORD";

      try
      {
         MdOMRConnection connection = _factory.getConnection();

         // this statement makes the connection to the server
         connection.makeOMRConnection(serverName, serverPort, serverUser, serverPass);

         // the following statements define error handling and error
         // reporting messages.
      }
      catch (MdException e)
      {
         Throwable t = e.getCause();
         if (t != null)
         {
            String ErrorType = e.getSASMessageSeverity();
            String ErrorMsg = e.getSASMessage();
            if (ErrorType == null)
            {
               // if there is no SAS server message, write a Java/CORBA message.
            }
            else
            {
               // if there is a message from the server:
               System.out.println(ErrorType + ": " + ErrorMsg);
            }
            if (t instanceof org.omg.CORBA.COMM_FAILURE)
            {
               // if there is an invalid port number or host name:
               System.out.println(e.getLocalizedMessage());
            }
            else if (t instanceof org.omg.CORBA.NO_PERMISSION)
            {
               // is there is an invalid user ID or password:
               System.out.println(e.getLocalizedMessage());
            }
         }
         else
         {
            // if we cannot find a nested exception, get message and print.
            System.out.println(e.getLocalizedMessage());
         }
         // if there is an error, print the entire stack trace.
         e.printStackTrace();
         return false;
      }
      catch (RemoteException e)
      {
         //unknown exception.
         e.printStackTrace();
         return false;
      }
      // If no errors occur, then a connection is made.
      return true;
   }

   /**
    * This example displays the status of the metadata server.
    */
   public void displayServerInformation()
   {
      try
      {
         MdOMRConnection connection = _factory.getConnection();

         // Check the status of the metadata server
         System.out.println("\nGetting server status...");
         int status = connection.getServerStatus();
         switch (status)
         {
            case MdOMRConnection.SERVER_STATUS_OK:
               System.out.println("Server is running");
               break;
            case MdOMRConnection.SERVER_STATUS_PAUSED:
               System.out.println("Server is paused");
               break;
            case MdOMRConnection.SERVER_STATUS_ERROR:
               System.out.println("Server is not running");
               break;
         }

         // Check the version of the metadata server
         int version = connection.getPlatformVersion();
         System.out.println("Server version: " + version);
      }
      catch (MdException e)
      {
         e.printStackTrace();
      }
      catch (RemoteException e)
      {
         e.printStackTrace();
      }
   }

   /**
    * This example retrieves a list of the repositories registered on the server.
    * @return the list of available repository (list of CMetadata objects)
    */
   public List getRepositories()
   {
      try
      {
         // Get a list of repositories.
         System.out.println("\nThe repositories contained on this server are: ");

         MdOMIUtil omiUtil = _factory.getOMIUtil();
         List reposList = omiUtil.getRepositories();
         Iterator iter = reposList.iterator();
         while (iter.hasNext())
         {
            //print the name and id of each repository
            CMetadata repository = (CMetadata) iter.next();
            System.out.println("Repository: " +
                               repository.getName()
                               + " (" + repository.getFQID() +")");
         }
         return reposList;
      }
      catch (MdException e)
      {
         e.printStackTrace();
      }
      catch (RemoteException e)
      {
         e.printStackTrace();
      }
      return new ArrayList();
   }

   /**
    * This example lists the metadata types available on the metadata server
    * and their descriptions.
    */
   public void displayMetadataTypes()
   {
      try
      {
         // Get a list of metadata types available on the server.
         System.out.println("\nThe object types contained on this metadata server are: ");
         List nameList = new ArrayList(100);
         List descList = new ArrayList(100);
         _factory.getOMIUtil().getTypes(nameList, descList);
         Iterator iter1 = nameList.iterator();
         Iterator iter2 = descList.iterator();
         while (iter1.hasNext() && iter2.hasNext())
         {
            //print the name and description of each metadata object type
            String name = (String) iter1.next();
            String desc = (String) iter2.next();
            System.out.println("Type: " +
                                name +
                                ", desc: " +
                                desc);
         }
      }
      catch (MdException e)
      {
         e.printStackTrace();
      }
      catch (RemoteException e)
      {
         e.printStackTrace();
      }
   }

   /**
    * This method creates a table, column, and note on the column, using
    * the store methods. It is a good example of how a wizard-style user interface
    * would utilize the MdFactory class.
    * @param Repository CMetadata object with id of form:  A0000001.A5KHUI98
    */
   public void createTable(CMetadata repository)
   {
      if (repository != null)
      {
         try
         {
            System.out.println("\nCreating objects on the server...");

            // We have a repository object.
            // We use the reposFQID method to get its fully qualified ID.
            String reposFQID = repository.getFQID();

            // We need the short Repository ID to create an object.
            // we use the ReposId method to get the short ID.
            String shortReposID = reposFQID.substring(reposFQID.indexOf('.') + 1,
                                    reposFQID.length());

            // Now we create an object store to hold all our objects.
            // This will be used to maintain a list of objects to persist
            // to the server.
            MdObjectStore store = _factory.createObjectStore();

            // Create a PhysicalTable object named "TableTest".
            PhysicalTable table = (PhysicalTable) _factory.createComplexMetadataObject
               (store,
                     null,
                     "TableTest",
                     MetadataObjects.PHYSICALTABLE,
                     shortReposID);

            // Create a Column named "ColumnTest".
            Column column = (Column) _factory.createComplexMetadataObject
               (store,
                     null,
                     "ColumnTest",
                     MetadataObjects.COLUMN,
                     shortReposID);

            // Set the attributes of the column.
            column.setColumnName("MyTestColumnName");
            column.setSASColumnName("MyTestSASColumnName");
            column.setDesc("This is a description of a column");

            // Use the get"AssociationName"() method to associate the column with
            // the table. This method creates an AssociationList object for the table
            // object. The inverse association will be created automatically.
            // The add(MetadataObject) method adds myColumn to the AssociationList.
            table.getColumns().add(column);

            // Create a note for the column named "NoteTest".
            TextStore note = (TextStore) _factory.createComplexMetadataObject
               (store,
                     null,
                     "NoteTest",
                     MetadataObjects.TEXTSTORE,
                     shortReposID);

            // Set the stored text attribute for the note
            note.setStoredText("Information about the note");

            // Associate the note with the column.
            column.getNotes().add(note);

            // Now, perist all of these changes to the server
            table.updateMetadataAll();

            // When finished, clean up the objects in the store if it is no longer
            // being used
            store.dispose();
         }
         catch (MdException e)
         {
            e.printStackTrace();
         }
         catch (RemoteException e)
         {
            e.printStackTrace();
         }
      }
   }

   /**
    * This method reads the newly created objects back from the server.
    * @param repository identifies the repository from which to read our objects.
    */
   public void readTable(CMetadata repository)
   {
      if(repository != null)
      {
         try
         {
            System.out.println("\nReading objects from the server...");

            // First we create an MdObjectStore as a container for all of the objects
            // we will create/read/persist to the server as one collection.
            MdObjectStore store = _factory.createObjectStore();

            // The following statements define GetMetadataObjectsSubset options strings.
            // These XML strings are used in conjunction with SAS Open Metadata Interface
            // flags. The <XMLSELECT> element specifies filter criteria. The 
            // element specifies the metadata properties to be returned for each object
            // from the server.
            String xmlSelect = "<XMLSELECT Search=\"@Name='TableTest'\"/>";
            String template =
               "<Templates>" +
                  "<PhysicalTable Id=\"\" Name=\"\" Desc=\"\">" +
                    "<Columns/>" +
                  "</PhysicalTable>" +
                  "<Column Id=\"\" Name=\"\" Desc=\"\" ColumnName=\"\">" +
                     "<Notes/>" +
                  "</Column>" +
                  "<TextStore Id=\"\" Name=\"\" Desc=\"\" StoredText=\"\"/>" +
                "</Templates>";

            // Add the xml select and template strings together
            String sOptions = xmlSelect + template;

            // The following statements go to the server with a fully-qualified
            // repository ID, specify the type of object we are searching for
            // (MdObjectFactory.PHYSICALTABLE), utilizing the OMI_XMLSELECT, OMI_TEMPLATE,
            // and OMI_GET_METADATA flags. OMI_GET_METADATA tells the server to get all of
            // the attributes specified in the template for each object that is returned.
            //
            // The table, column, and note will be read from the server and created within
            // the specified object store.
            int flags = MdOMIUtil.OMI_XMLSELECT | MdOMIUtil.OMI_TEMPLATE |
                           MdOMIUtil.OMI_GET_METADATA;
            List tableList = _factory.getOMIUtil().getMetadataObjectsSubset(store,
                                                       repository.getFQID(),
                                                       MetadataObjects.PHYSICALTABLE,
                                                       flags,
                                                       sOptions);
            Iterator iter = tableList.iterator();
            while (iter.hasNext())
            {
               // The table returned from the server
               PhysicalTable table = (PhysicalTable) iter.next();
               System.out.println("Found table: " + table.getName() + " (" +
                                    table.getId() + ")");

               // Get the list of columns for this table.
               AssociationList columns = table.getColumns();
               for (int i = 0; i < columns.size(); i++)
               {
                  // The column associated to the table
                  Column column = (Column) columns.get(i);
                  System.out.println("Found column: " + column.getName() + " (" +
                                       column.getId() + ")");
                  System.out.println("\tDescription: " + column.getDesc());
                  System.out.println("\tColumnName: " + column.getColumnName());

                  // We now have a column, and request to get its notes.
                  AssociationList notes = column.getNotes();
                  for (int j = 0; j < notes.size(); j++)
                  {
                     // The note associated to the column
                     TextStore note = (TextStore) notes.get(j);
                     System.out.println("Found textstore: " + note.getName() + " (" +
                                          note.getId() + ")");
                     System.out.println("\tStoredText: " + note.getStoredText());
                  }
               }
            }

            // When finished, clean up the objects in the store if it is no longer
            // being used
            store.dispose();
         }
         catch (MdException e)
         {
            e.printStackTrace();
         }
         catch (RemoteException e)
         {
            e.printStackTrace();
         }
      }
   }

   /**
    * This method deletes the objects we created in repository
    * @param repository
    */
   public void deleteTable(CMetadata repository)
   {
      if(repository != null)
      {
         try
         {
            System.out.println("\nDeleting the objects from the server...");
            MdObjectStore store = _factory.createObjectStore();

            // Create a list containing all of the objects that need to be deleted
            // from the server.
            List deleteList = new ArrayList();

            // Query for the table again
            String xmlSelect = "<XMLSELECT Search=\"@Name='TableTest'\"/>";
            String template = "<Templates>" +
                                 "<PhysicalTable>" +
                                   "<Columns/>" +
                                 "</PhysicalTable>" +
                                 "<Column>" +
                                    "<Notes/>" +
                                 "</Column>" +
                               "</Templates>";

            // Add the xml select and template strings together
            String sOptions = xmlSelect + template;

            int flags = MdOMIUtil.OMI_XMLSELECT | MdOMIUtil.OMI_TEMPLATE |
                           MdOMIUtil.OMI_GET_METADATA;
            List tableList = _factory.getOMIUtil().getMetadataObjectsSubset(store,
                                                       repository.getFQID(),
                                                       MetadataObjects.PHYSICALTABLE,
                                                       flags,
                                                       sOptions);


            // Now that we have the objects, we need to add them to the delete list
            Iterator iter = tableList.iterator();
            while (iter.hasNext())
            {
               PhysicalTable table = (PhysicalTable) iter.next();
               deleteList.add(table);

               // Get the columns
               AssociationList columns = table.getColumns();
               for (int i = 0; i < columns.size(); i++)
               {
                  Column column = (Column) columns.get(i);
                  deleteList.add(column);

                  // Get the notes
                  AssociationList notes = column.getNotes();
                  for (int j = 0; j < notes.size(); j++)
                  {
                     TextStore note = (TextStore) notes.get(j);
                     deleteList.add(note);
                  }
               }
            }

            // Delete everything added to the delete list
            if (deleteList.size() > 0)
            {
               System.out.println("Deleting " + deleteList.size() + " objects");
               _factory.deleteMetadataObjects(deleteList);
            }

            // When finished, clean up the objects in the store if it is no longer
            // being used
            store.dispose();
         }
         catch (MdException e)
         {
            e.printStackTrace();
         }
         catch (RemoteException e)
         {
            e.printStackTrace();
         }
      }
   }

   /**
    * This method displays the PhysicalTable objects contained in repository
    * @param repository CMetadata identifies the repository from which to read
    * the objects.
    */
   public void displayAllTables(CMetadata repository)
   {
      try
      {
         // Print a descriptive message about the request.
         System.out.println("\nRetrieving all PhysicalTable objects contained in " +
               " repository " + repository.getName());

         // Use the short Repository ID to pass in the method.
         String reposID = repository.getFQID();

         // We get a list of "PhysicalTable" objects.
         MdObjectStore store = _factory.createObjectStore();

         // Use the OMI_ALL_SIMPLE flag to get all attributes for each table returned
         int flags = MdOMIUtil.OMI_GET_METADATA | MdOMIUtil.OMI_ALL_SIMPLE;
         List tables = _factory.getOMIUtil().getMetadataObjectsSubset
                (store,
                reposID,                         // Repository to Search
                MetadataObjects.PHYSICALTABLE,   // Type to search for
                flags,
                "" );

         // Print information about them.
         Iterator iter = tables.iterator();
         while( iter.hasNext())
         {
            PhysicalTable ptable = (PhysicalTable)iter.next();
            System.out.println("PhysicalTable: " +
                               ptable.getName() +
                               ", " +
                               ptable.getFQID() +
                               ", " +
                               ptable.getDesc());
         }

         // When finished, clean up the objects in the store if it is no longer
         // being used
         store.dispose();
      }
      catch (MdException e)
      {
         e.printStackTrace();
      }
      catch (RemoteException e)
      {
         e.printStackTrace();
      }
   }

   /**
    * This method retrieves detailed information for a specific PhysicalTable
    * @param table the table to retrieve
    */
   public void getTableInformation(PhysicalTable table)
   {
      try
      {
         // Print a descriptive message about the request.
         System.out.println("\nRetrieving information for a specific PhysicalTable");

         // Create a template to retreive detailed information for this table
         String template = "<Templates>" +
                              "<PhysicalTable>" +
                                "<Columns/>" +
                                "<Notes/>" +
                                "<Keywords/>" +
                              "</PhysicalTable>" +
                            "</Templates>";

         // Use the OMI_ALL_SIMPLE flag to get all attributes for each table returned
         int flags = MdOMIUtil.OMI_GET_METADATA | MdOMIUtil.OMI_ALL_SIMPLE |
                        MdOMIUtil.OMI_TEMPLATE;
         table = (PhysicalTable) _factory.getOMIUtil().getMetadataAllDepths
                (table,
                 null,
                 null,
                 template,
                 flags);

         // Print information about the table
         System.out.println("Table attributes: ");
         System.out.println("  Name = " + table.getName());
         System.out.println("  Id = " + table.getId());
         System.out.println("  Description = " + table.getDesc());
         System.out.println("  Created Date = " + table.getMetadataCreated());
         System.out.println("Table associations: ");
         System.out.println("  Number of Columns = " + table.getColumns().size());
         System.out.println("  Number of Keywords = " + table.getKeywords().size());
         System.out.println("  Number of Notes = " + table.getNotes().size());
      }
      catch (MdException e)
      {
         e.printStackTrace();
      }
      catch (RemoteException e)
      {
         e.printStackTrace();
      }
   }

   /**
    * The main method for the class
    */
   public static void main(String[] args)
   {
      MdTesterExamples tester = new MdTesterExamples();

      // connect to the metadata server
      boolean connected = tester.connectToServer();
      if(connected)
      {
         System.out.println("Connected...");
      }
      else
      {
         System.out.println("Error Connecting...");
         return;
      }

      // now that we are connected, check the status of the server
      tester.displayServerInformation();

      // get the list of repositories on the server
      List repositories = tester.getRepositories();
      CMetadata repos = (CMetadata) repositories.get(0);

      // get the list of metadata types available on the server
      tester.displayMetadataTypes();

      // create a new PhysicalTable object and add it to the metadata server
      tester.createTable(repos);

      // query for the PhysicalTable just added to the metadata server
      tester.readTable(repos);

      // delete the PhysicalTable
      tester.deleteTable(repos);

      System.exit(1);
   }

}