Difference between revisions of "Documentation/DevGuide/Config/Updating Configuration Data"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (FINAL VERSION FOR L10N)
(4 intermediate revisions by 2 users not shown)
Line 15: Line 15:
 
Updates done through a configuration view are only visible within that view, providing transactional isolation. When a set of updates is ready, it must be committed explicitly to become visible beyond this view. All pending updates are then sent to the configuration provider in one batch. This batch update behavior is controlled through interface <idl>com.sun.star.util.XChangesBatch</idl> that is implemented by the root element of an updatable configuration view.  
 
Updates done through a configuration view are only visible within that view, providing transactional isolation. When a set of updates is ready, it must be committed explicitly to become visible beyond this view. All pending updates are then sent to the configuration provider in one batch. This batch update behavior is controlled through interface <idl>com.sun.star.util.XChangesBatch</idl> that is implemented by the root element of an updatable configuration view.  
  
{{Documentation/Caution|When a set of changes is committed to the provider it becomes visible to other views obtained from the same provider as an atomic and consistent set of changes. Thus, in the local scope of a single <idl>com.sun.star.configuration.ConfigurationProvider</idl> a high degree of transactional behavior is achieved.
+
{{Warn|When a set of changes is committed to the provider it becomes visible to other views obtained from the same provider as an atomic and consistent set of changes. Thus, in the local scope of a single <idl>com.sun.star.configuration.ConfigurationProvider</idl> a high degree of transactional behavior is achieved.
  
 
The configuration management component does not guarantee true transactional behavior. Committing the changes to the <idl>com.sun.star.configuration.ConfigurationProvider</idl> does not ensure persistence or durability of the changes. When the provider writes back the changes to the persistent data store, they become durable. Generally, the <idl>com.sun.star.configuration.ConfigurationProvider</idl> may cache and combine requests, so that updates are propagated to the data store at a later time.  
 
The configuration management component does not guarantee true transactional behavior. Committing the changes to the <idl>com.sun.star.configuration.ConfigurationProvider</idl> does not ensure persistence or durability of the changes. When the provider writes back the changes to the persistent data store, they become durable. Generally, the <idl>com.sun.star.configuration.ConfigurationProvider</idl> may cache and combine requests, so that updates are propagated to the data store at a later time.  
Line 21: Line 21:
 
If several sets of changes are combined before being saved, isolation and consistency may be weakened in case of failure. As long as the backend does not fully support transactions, only parts of an update request might be stored successfully, thus violating atomicity and consistency.  
 
If several sets of changes are combined before being saved, isolation and consistency may be weakened in case of failure. As long as the backend does not fully support transactions, only parts of an update request might be stored successfully, thus violating atomicity and consistency.  
  
If failures occur while writing configuration data into the backend data store, the <idl>com.sun.star.configuration.ConfigurationProvider</idl> resynchronizes with the data stored in the backend. The listeners are notified of any differences as if they had been stored through another view. If an application has more stringent error handling needs, the caching behavior can be adjusted by providing arguments when creating the view.
+
If failures occur while writing configuration data into the backend data store, the <idl>com.sun.star.configuration.ConfigurationProvider</idl> resynchronizes with the data stored in the backend. The listeners are notified of any differences as if they had been stored through another view.
  
In summary, there are few overall guarantees regarding transactional integrity for the configuration database, but locally, the configuration behaves as if the support is in place. Depending on the backend capabilities, the <idl>com.sun.star.configuration.ConfigurationProvider</idl> tries to provide the best approximation to transactional integrity that can be achieved considering the capabilities of the backend without compromising performance.}}
+
In summary, there are few overall guarantees regarding transactional integrity for the configuration database, but locally, the configuration behaves as if the support is in place. The <idl>com.sun.star.configuration.ConfigurationProvider</idl> tries to provide the best approximation to transactional integrity that can be achieved considering the capabilities of the backend without compromising performance.}}
  
 
The following example demonstrates how the configuration interfaces are used to feed a user-interface for preference changes. This shows the framework needed to update configuration values, and demonstrates how listeners are used with configuration views. This example concentrates on properties in group nodes with a fixed structure. It uses the same {{PRODUCTNAME}} Calc grid settings as the previous example. It assumes that there is a class <code>GridOptionsEditor</code> that drives a dialog to display and edit the configuration data:
 
The following example demonstrates how the configuration interfaces are used to feed a user-interface for preference changes. This shows the framework needed to update configuration values, and demonstrates how listeners are used with configuration views. This example concentrates on properties in group nodes with a fixed structure. It uses the same {{PRODUCTNAME}} Calc grid settings as the previous example. It assumes that there is a class <code>GridOptionsEditor</code> that drives a dialog to display and edit the configuration data:
Line 32: Line 32:
 
       final String cGridOptionsPath = "/org.openoffice.Office.Calc/Grid";
 
       final String cGridOptionsPath = "/org.openoffice.Office.Calc/Grid";
 
        
 
        
       // create a synchronous view for better error handling (lazywrite = false)
+
       // create a view
       Object xViewRoot = createUpdatableView(cGridOptionsPath, false);
+
       Object xViewRoot = createUpdatableView(cGridOptionsPath);
 
        
 
        
 
       // the 'editor'
 
       // the 'editor'
Line 76: Line 76:
 
  </source>
 
  </source>
 
In this example, the dialog controller uses the <idl>com.sun.star.beans.XMultiHierarchicalPropertySet</idl> interface to read and change configuration values. If the grid options are changed and committed in another view, <idlml>com.sun.star.util.XChangesListener:changesOccurred</idlml>() is sent to the listener supplied by the dialog which can then update its display accordingly.
 
In this example, the dialog controller uses the <idl>com.sun.star.beans.XMultiHierarchicalPropertySet</idl> interface to read and change configuration values. If the grid options are changed and committed in another view, <idlml>com.sun.star.util.XChangesListener:changesOccurred</idlml>() is sent to the listener supplied by the dialog which can then update its display accordingly.
 
Note that a synchronous <idl>com.sun.star.configuration.ConfigurationUpdateAccess</idl> was created for this example (argument <code>lazywrite==false</code>). As the action here is driven by user interaction, synchronous committing is used to detect errors immediately.
 
  
 
Besides the values for the current user, there are also default values that are determined by merging the schema with any default layers. It is possible to retrieve the default values for individual properties, and to reset a property or a set node to their default states, thus backing out any changes done for the current user. For this purpose, group nodes support the interfaces <idl>com.sun.star.beans.XPropertyState</idl> and <idl>com.sun.star.beans.XMultiPropertyStates</idl>, offering operations to query if a property assumes its default state or the default value, and to reset an updatable property to its default state. The <idl>com.sun.star.beans.Property</idl> structs available through <idlml>com.sun.star.beans.XPropertySetInfo:getPropertyByName</idlml>() or <idlml>com.sun.star.beans.XPropertySetInfo:getProperties</idlml>() are used to determine if a particular item or node supports this operation.
 
Besides the values for the current user, there are also default values that are determined by merging the schema with any default layers. It is possible to retrieve the default values for individual properties, and to reset a property or a set node to their default states, thus backing out any changes done for the current user. For this purpose, group nodes support the interfaces <idl>com.sun.star.beans.XPropertyState</idl> and <idl>com.sun.star.beans.XMultiPropertyStates</idl>, offering operations to query if a property assumes its default state or the default value, and to reset an updatable property to its default state. The <idl>com.sun.star.beans.Property</idl> structs available through <idlml>com.sun.star.beans.XPropertySetInfo:getPropertyByName</idlml>() or <idlml>com.sun.star.beans.XPropertySetInfo:getProperties</idlml>() are used to determine if a particular item or node supports this operation.
Line 136: Line 134:
  
 
  </source>
 
  </source>
{{Documentation/Note|Currently, group nodes do not support the attribute <idlml>com.sun.star.beans.PropertyAttribute:MAYBEDEFAULT</idlml> set in the <idl>com.sun.star.beans.Property</idl> structure available from <idl>com.sun.star.beans.XPropertySetInfo</idl>. Attempts to use <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> to reset an entire group node fail.
+
{{Note|Currently, group nodes do not support the attribute <idlml>com.sun.star.beans.PropertyAttribute:MAYBEDEFAULT</idlml> set in the <idl>com.sun.star.beans.Property</idl> structure available from <idl>com.sun.star.beans.XPropertySetInfo</idl>. Attempts to use <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> to reset an entire group node fail.
  
 
Also, because the group nodes can not be reset, the <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> or <idlml>com.sun.star.beans.XMultiPropertyStates:setAllPropertiesToDefault</idlml> cannot be used to reset all descendants of a node.
 
Also, because the group nodes can not be reset, the <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> or <idlml>com.sun.star.beans.XMultiPropertyStates:setAllPropertiesToDefault</idlml> cannot be used to reset all descendants of a node.
Line 195: Line 193:
 
The example shows a procedure that creates and saves basic settings for connecting to a new data source. It uses an asynchronous <idl>com.sun.star.configuration.ConfigurationUpdateAccess</idl>. Thus, when <idlml>com.sun.star.util.XChangesBatch:commitChanges</idlml> is called, the data becomes visible at the <idl>com.sun.star.configuration.ConfigurationProvider</idl>, but is only stored in the provider's cache. It is written to the data store at later when the cache is automatically flushed by the <idl>com.sun.star.configuration.ConfigurationProvider</idl>. As this is done in the background there is no exception when the write-back fails.
 
The example shows a procedure that creates and saves basic settings for connecting to a new data source. It uses an asynchronous <idl>com.sun.star.configuration.ConfigurationUpdateAccess</idl>. Thus, when <idlml>com.sun.star.util.XChangesBatch:commitChanges</idlml> is called, the data becomes visible at the <idl>com.sun.star.configuration.ConfigurationProvider</idl>, but is only stored in the provider's cache. It is written to the data store at later when the cache is automatically flushed by the <idl>com.sun.star.configuration.ConfigurationProvider</idl>. As this is done in the background there is no exception when the write-back fails.
  
{{Documentation/Caution|The recommended method to configure a new data source is to use the <idl>com.sun.star.sdb.DatabaseContext</idl> service as described in [[Documentation/DevGuide/Database/Data Sources in OpenOffice.org API#DatabaseContext|DatabaseContext]]. This is a high-level service that ensures that all the settings required to establish a connection are properly set.}}
+
{{Warn|The recommended method to configure a new data source is to use the <idl>com.sun.star.sdb.DatabaseContext</idl> service as described in [[Documentation/DevGuide/Database/Data Sources in OpenOffice.org API#DatabaseContext|DatabaseContext]]. This is a high-level service that ensures that all the settings required to establish a connection are properly set.}}
  
 
Among the parameters of the routine is the name of the data source that must be chosen to uniquely identify the data source from other parameters directly related to the above properties. There also is a parameter to pass a list of entries for the <code>DataSourceSettings</code> set.  
 
Among the parameters of the routine is the name of the data source that must be chosen to uniquely identify the data source from other parameters directly related to the above properties. There also is a parameter to pass a list of entries for the <code>DataSourceSettings</code> set.  
Line 251: Line 249:
 
</source>
 
</source>
 
Notice the function <code>createDataSourceDescription</code> in our example. It is called to get a <code>DataSourceDescription</code> instance to access a pre-existing item, or create and insert a new item using the passed name.
 
Notice the function <code>createDataSourceDescription</code> in our example. It is called to get a <code>DataSourceDescription</code> instance to access a pre-existing item, or create and insert a new item using the passed name.
 
The function is optimized to reduce the view to as little data as necessary. To this end it employs the depth parameter when creating the view.
 
 
{{Documentation/Tip|The "depth" parameter for optimization purposes is used here for demonstration purposes only. Use of the "depth" flag does not have a noticeable effect on performance with the current implementation of the {{PRODUCTNAME}} configuration management components. Actually, there are few cases where the use of this parameter has any value.}}
 
 
This results in a view where descendants of the root are only included in the view up to the given nesting depth. In this case, where depth = 1, only the immediate children are loaded. If the requested item is found, the function gets a deeper view for only that item, otherwise it creates a new instance. In the latter case, the item returned is not the root of the view.
 
 
<!--[SOURCE:Config/ConfigExamples.java]-->
 
<!--[SOURCE:Config/ConfigExamples.java]-->
 
  <source lang="java">
 
  <source lang="java">
 
   /** This method gets the DataSourceDescription for a data source.
 
   /** This method gets the DataSourceDescription for a data source.
 
       It either gets the existing entry or creates a new instance.
 
       It either gets the existing entry or creates a new instance.
    
+
   */
      The method attempts to keep the view used as small as possible. In particular there
+
   Object createDataSourceDescription(XMultiServiceFactory xProvider, String sDataSourceName )
      is no view created, that contains data for all data source that are registered.
+
              throws com.sun.star.uno.Exception
  */
+
  {
   Object createDataSourceDescription(XMultiServiceFactory xProvider, String sDataSourceName)
+
          throws com.sun.star.uno.Exception {
+
 
       // The service name: Need an update access:
 
       // The service name: Need an update access:
 
       final String cUpdatableView = "com.sun.star.configuration.ConfigurationUpdateAccess";
 
       final String cUpdatableView = "com.sun.star.configuration.ConfigurationUpdateAccess";
     
+
 
      // The path to the DataSources set node  
+
      // The path to the DataSources set node
 
       final String cDataSourcesPath = "/org.openoffice.Office.DataAccess/DataSources";
 
       final String cDataSourcesPath = "/org.openoffice.Office.DataAccess/DataSources";
     
+
 
      // creation arguments: nodepath  
+
    // creation arguments: nodepath
 
       com.sun.star.beans.PropertyValue aPathArgument = new com.sun.star.beans.PropertyValue();
 
       com.sun.star.beans.PropertyValue aPathArgument = new com.sun.star.beans.PropertyValue();
 
       aPathArgument.Name = "nodepath";
 
       aPathArgument.Name = "nodepath";
 
       aPathArgument.Value = cDataSourcesPath ;
 
       aPathArgument.Value = cDataSourcesPath ;
     
+
 
      // creation arguments: commit mode
+
       Object[] aArguments = new Object[1];
      com.sun.star.beans.PropertyValue aModeArgument = new com.sun.star.beans.PropertyValue();
+
      aModeArgument.Name = "lazywrite";
+
      aModeArgument.Value = new Boolean(true);
+
     
+
      // creation arguments: depth
+
      com.sun.star.beans.PropertyValue aDepthArgument = new com.sun.star.beans.PropertyValue();
+
      aDepthArgument.Name = "depth";
+
      aDepthArgument.Value = new Integer(1);
+
     
+
       Object[] aArguments = new Object[3];
+
 
       aArguments[0] = aPathArgument;
 
       aArguments[0] = aPathArgument;
      aArguments[1] = aModeArgument;
+
 
      aArguments[2] = aDepthArgument;
+
       // create the view
     
+
       Object xViewRoot =
       // create the view: asynchronously updatable, with depth 1
+
       Object xViewRoot =  
+
 
           xProvider.createInstanceWithArguments(cUpdatableView, aArguments);
 
           xProvider.createInstanceWithArguments(cUpdatableView, aArguments);
     
+
 
       XNameAccess xSetOfDataSources = (XNameAccess) UnoRuntime.queryInterface(
+
       XNameAccess xSetOfDataSources =
          XNameAccess.class,xViewRoot);
+
          (XNameAccess) UnoRuntime.queryInterface(XNameAccess.class,xViewRoot);
     
+
 
 
       Object xDataSourceDescriptor = null; // the result
 
       Object xDataSourceDescriptor = null; // the result
       if (xSetOfDataSources .hasByName(sDataSourceName)) {
+
       if ( xSetOfDataSources .hasByName( sDataSourceName ))
           // the element is there, but it is loaded only with depth zero !
+
      {
           try {
+
           // the element is there
 +
           try
 +
          {
 
               // the view should point to the element directly, so we need to extend the path
 
               // the view should point to the element directly, so we need to extend the path
               XHierarchicalName xComposePath = (XHierarchicalName) UnoRuntime.queryInterface(
+
               XHierarchicalName xComposePath = (XHierarchicalName)
                  XHierarchicalName.class, xSetOfDataSources );
+
                  UnoRuntime.queryInterface(XHierarchicalName.class, xSetOfDataSources );
             
+
 
 
               String sElementPath = xComposePath.composeHierarchicalName( sDataSourceName );
 
               String sElementPath = xComposePath.composeHierarchicalName( sDataSourceName );
             
+
 
 
               // use the name of the element now
 
               // use the name of the element now
 
               aPathArgument.Value = sElementPath;
 
               aPathArgument.Value = sElementPath;
             
+
 
               // create another view now (without depth limit)
+
               // create another view now
               Object[] aDeepArguments = new Object[2];
+
               Object[] aDeepArguments = new Object[1];
 
               aDeepArguments[0] = aPathArgument;
 
               aDeepArguments[0] = aPathArgument;
              aDeepArguments[1] = aModeArgument;
+
 
             
+
               // create the view
               // create the view: asynchronously updatable, with unlimited depth
+
               xDataSourceDescriptor =
               xDataSourceDescriptor =  
+
                    xProvider.createInstanceWithArguments(cUpdatableView, aDeepArguments);
                  xProvider.createInstanceWithArguments(cUpdatableView, aDeepArguments);
+
 
             
+
               if ( xDataSourceDescriptor != null) // all went fine
               if ( xDataSourceDescriptor != null) // all went fine  
+
 
               {
 
               {
 
                   // dispose the other view
 
                   // dispose the other view
Line 329: Line 308:
 
               }
 
               }
 
           }
 
           }
           catch (Exception e) {
+
           catch (Exception e)
              // something went wrong, we retry with a new element  
+
          {
              System.out.println("WARNING: An exception occurred while creating a view" +
+
            // something went wrong, we retry with a new element
                  " for an existing data source: " + e);
+
            System.err.println("WARNING: An exception occurred while creating a view for an existing data source: " + e);
              xDataSourceDescriptor = null;
+
            xDataSourceDescriptor = null;
 
           }
 
           }
 
       }
 
       }
         
+
 
 
       // do we have a result element yet ?
 
       // do we have a result element yet ?
       if (xDataSourceDescriptor == null) {
+
       if ( xDataSourceDescriptor == null)
           // get the container  
+
      {
           XNameContainer xSetUpdate = (XNameContainer)UnoRuntime.queryInterface(
+
           // get the container
              XNameContainer.class, xViewRoot);
+
           XNameContainer xSetUpdate =
     
+
              (XNameContainer)UnoRuntime.queryInterface(XNameContainer.class, xViewRoot);
 +
 
 
           // create a new detached set element (instance of DataSourceDescription)
 
           // create a new detached set element (instance of DataSourceDescription)
           XSingleServiceFactory xElementFactory = (XSingleServiceFactory)UnoRuntime.queryInterface(
+
           XSingleServiceFactory xElementFactory =
              XSingleServiceFactory.class, xSetUpdate);
+
              (XSingleServiceFactory)UnoRuntime.queryInterface(XSingleServiceFactory.class, xSetUpdate);
         
+
 
 
           // the new element is the result !
 
           // the new element is the result !
          xDataSourceDescriptor = xElementFactory.createInstance();
+
          xDataSourceDescriptor = xElementFactory.createInstance();
         
+
 
           // insert it - this also names the element  
+
           // insert it - this also names the element
           xSetUpdate.insertByName( sDataSourceName , xDataSourceDescriptor );
+
           xSetUpdate.insertByName( sDataSourceName , xDataSourceDescriptor );
 
       }
 
       }
         
+
 
 
       return xDataSourceDescriptor ;
 
       return xDataSourceDescriptor ;
 
   }
 
   }
Line 420: Line 400:
 
Besides adding a freshly created instance of a template, a set item can be removed from a set and added to any other set supporting the same template for its elements, provided both sets are part of the same view. You cannot move a set item between views, as this contradicts the transactional isolation of views. The set item you removed in one view will still be in its old place in the other. If a set item is moved between sets in one view and the changes are committed, the change appears in another overlapping view as removal of the original item and insertion of a new element in the target location, not as relocation of an identical element.  
 
Besides adding a freshly created instance of a template, a set item can be removed from a set and added to any other set supporting the same template for its elements, provided both sets are part of the same view. You cannot move a set item between views, as this contradicts the transactional isolation of views. The set item you removed in one view will still be in its old place in the other. If a set item is moved between sets in one view and the changes are committed, the change appears in another overlapping view as removal of the original item and insertion of a new element in the target location, not as relocation of an identical element.  
  
{{Documentation/Tip|The methods <idlml>com.sun.star.container.XNamed:setName</idlml>() and <idlml>com.sun.star.container.XChild:setParent</idlml>() are supported by a <idl>com.sun.star.configuration.ConfigurationUpdateAccess</idl> only if it is a <idl>com.sun.star.configuration.SetElement</idl>. They offer another way to move an item within a set or from one set to another set.  
+
{{Tip|The methods <idlml>com.sun.star.container.XNamed:setName</idlml>() and <idlml>com.sun.star.container.XChild:setParent</idlml>() are supported by a <idl>com.sun.star.configuration.ConfigurationUpdateAccess</idl> only if it is a <idl>com.sun.star.configuration.SetElement</idl>. They offer another way to move an item within a set or from one set to another set.  
  
 
In the current release of {{PRODUCTNAME}}, these methods are not supported correctly. You can achieve the same effect by using a sequence of remove item - insert item.  
 
In the current release of {{PRODUCTNAME}}, these methods are not supported correctly. You can achieve the same effect by using a sequence of remove item - insert item.  

Revision as of 19:53, 14 July 2018



A com.sun.star.configuration.ConfigurationUpdateAccess provides operations for updating configuration data, by extending the interfaces supported by a com.sun.star.configuration.ConfigurationAccess.

ConfigurationUpdateAccess services

For com.sun.star.beans.XPropertySet and related interfaces, the semantics are extended to set property values. Support for container interfaces is extended to set properties in group nodes, and insert or remove elements in set nodes. Thus, a com.sun.star.configuration.GroupUpdate supports interface com.sun.star.container.XNameReplace and a com.sun.star.configuration.SetUpdate supports com.sun.star.container.XNameContainer. Only complete trees having the appropriate structure are inserted for sets whose elements are complete structures as described by a template,. To support this, the set object is used as a factory that can create structures of the appropriate type. For this purpose, the set supports com.sun.star.lang.XSingleServiceFactory.

Updates done through a configuration view are only visible within that view, providing transactional isolation. When a set of updates is ready, it must be committed explicitly to become visible beyond this view. All pending updates are then sent to the configuration provider in one batch. This batch update behavior is controlled through interface com.sun.star.util.XChangesBatch that is implemented by the root element of an updatable configuration view.

Documentation caution.png When a set of changes is committed to the provider it becomes visible to other views obtained from the same provider as an atomic and consistent set of changes. Thus, in the local scope of a single com.sun.star.configuration.ConfigurationProvider a high degree of transactional behavior is achieved.

The configuration management component does not guarantee true transactional behavior. Committing the changes to the com.sun.star.configuration.ConfigurationProvider does not ensure persistence or durability of the changes. When the provider writes back the changes to the persistent data store, they become durable. Generally, the com.sun.star.configuration.ConfigurationProvider may cache and combine requests, so that updates are propagated to the data store at a later time.

If several sets of changes are combined before being saved, isolation and consistency may be weakened in case of failure. As long as the backend does not fully support transactions, only parts of an update request might be stored successfully, thus violating atomicity and consistency.

If failures occur while writing configuration data into the backend data store, the com.sun.star.configuration.ConfigurationProvider resynchronizes with the data stored in the backend. The listeners are notified of any differences as if they had been stored through another view.

In summary, there are few overall guarantees regarding transactional integrity for the configuration database, but locally, the configuration behaves as if the support is in place. The com.sun.star.configuration.ConfigurationProvider tries to provide the best approximation to transactional integrity that can be achieved considering the capabilities of the backend without compromising performance.

The following example demonstrates how the configuration interfaces are used to feed a user-interface for preference changes. This shows the framework needed to update configuration values, and demonstrates how listeners are used with configuration views. This example concentrates on properties in group nodes with a fixed structure. It uses the same OpenOffice.org Calc grid settings as the previous example. It assumes that there is a class GridOptionsEditor that drives a dialog to display and edit the configuration data:

  // This method simulates editing configuration data using a GridEditor dialog class 
  public void editGridOptions() throws com.sun.star.uno.Exception {
      // The path to the root element 
      final String cGridOptionsPath = "/org.openoffice.Office.Calc/Grid";
 
      // create a view
      Object xViewRoot = createUpdatableView(cGridOptionsPath);
 
      // the 'editor'
      GridOptionsEditor dialog = new GridOptionsEditor();
 
      // set up the initial values and register listeners
      // get a data access interface, to supply the view with a model 
      XMultiHierarchicalPropertySet xProperties = (XMultiHierarchicalPropertySet)
          UnoRuntime.queryInterface(XMultiHierarchicalPropertySet.class, xViewRoot);
 
      dialog.setModel(xProperties);
 
      // get a listener object (probably an adapter) that notifies
      // the dialog of external changes to its model 
      XChangesListener xListener = dialog.createChangesListener( );
 
      XChangesNotifier xNotifier = 
          (XChangesNotifier)UnoRuntime.queryInterface(XChangesNotifier.class, xViewRoot);
 
      xNotifier.addChangesListener(xListener);
 
      if (dialog.execute() == GridOptionsEditor.SAVE_SETTINGS) {
          // changes have been applied to the view here
          XChangesBatch xUpdateControl = 
              (XChangesBatch) UnoRuntime.queryInterface(XChangesBatch.class,xViewRoot);
 
          try {
              xUpdateControl.commitChanges();
          }
          catch (Exception e) {
              dialog.informUserOfError( e );
          }
      }
 
      // all changes have been handled - clean up and return
      // listener is done now
      xNotifier.removeChangesListener(xListener);
 
      // we are done with the view - dispose it 
      ((XComponent)UnoRuntime.queryInterface(XComponent.class, xViewRoot)).dispose();
  }

In this example, the dialog controller uses the com.sun.star.beans.XMultiHierarchicalPropertySet interface to read and change configuration values. If the grid options are changed and committed in another view, <idlml>com.sun.star.util.XChangesListener:changesOccurred</idlml>() is sent to the listener supplied by the dialog which can then update its display accordingly.

Besides the values for the current user, there are also default values that are determined by merging the schema with any default layers. It is possible to retrieve the default values for individual properties, and to reset a property or a set node to their default states, thus backing out any changes done for the current user. For this purpose, group nodes support the interfaces com.sun.star.beans.XPropertyState and com.sun.star.beans.XMultiPropertyStates, offering operations to query if a property assumes its default state or the default value, and to reset an updatable property to its default state. The com.sun.star.beans.Property structs available through <idlml>com.sun.star.beans.XPropertySetInfo:getPropertyByName</idlml>() or <idlml>com.sun.star.beans.XPropertySetInfo:getProperties</idlml>() are used to determine if a particular item or node supports this operation.

Individual set elements can not be reset because set nodes do not support com.sun.star.beans.XPropertyState. Instead a com.sun.star.configuration.SetAccess supports com.sun.star.beans.XPropertyWithStatethat resets the set as a whole.

The following is an example code using this feature to reset the OpenOffice.org Calc grid settings used in the preceding examples to their default state:

  /// This method resets the grid settings to their default values
  protected void resetGridConfiguration() throws com.sun.star.uno.Exception {
      // The path to the root element 
      final String cGridOptionsPath = "/org.openoffice.Office.Calc/Grid";
 
      // create the view
      Object xViewRoot = createUpdatableView(cGridOptionsPath);
 
      // ### resetting a single nested value ###
      XHierarchicalNameAccess xHierarchicalAccess = 
          (XHierarchicalNameAccess)UnoRuntime.queryInterface(XHierarchicalNameAccess.class, xViewRoot);
 
      // get using absolute name
      Object xOptions = xHierarchicalAccess.getByHierarchicalName(cGridOptionsPath + "/Option");
 
      XPropertyState xOptionState = 
          (XPropertyState)UnoRuntime.queryInterface(XPropertyState.class, xOptions);
 
      xOptionState.setPropertyToDefault("VisibleGrid");
 
      // ### resetting more deeply nested values ###
      Object xResolutionX = xHierarchicalAccess.getByHierarchicalName("Resolution/XAxis");
      Object xResolutionY = xHierarchicalAccess.getByHierarchicalName("Resolution/YAxis");
 
      XPropertyState xResolutionStateX = 
          (XPropertyState)UnoRuntime.queryInterface(XPropertyState.class, xResolutionX);
      XPropertyState xResolutionStateY = 
          (XPropertyState)UnoRuntime.queryInterface(XPropertyState.class, xResolutionY);
 
      xResolutionStateX.setPropertyToDefault("Metric");
      xResolutionStateY.setPropertyToDefault("Metric");
 
      // ### resetting multiple sibling values ###
      Object xSubdivision = xHierarchicalAccess.getByHierarchicalName("Subdivision");
 
      XMultiPropertyStates xSubdivisionStates =
          (XMultiPropertyStates)UnoRuntime.queryInterface(XMultiPropertyStates.class, xSubdivision);
 
      xSubdivisionStates.setAllPropertiesToDefault();
 
      // commit the changes
      XChangesBatch xUpdateControl = 
          (XChangesBatch) UnoRuntime.queryInterface(XChangesBatch.class, xViewRoot);
 
      xUpdateControl.commitChanges();
 
      // we are done with the view - dispose it 
      ((XComponent)UnoRuntime.queryInterface(XComponent.class, xViewRoot)).dispose();
  }
Documentation note.png Currently, group nodes do not support the attribute <idlml>com.sun.star.beans.PropertyAttribute:MAYBEDEFAULT</idlml> set in the com.sun.star.beans.Property structure available from com.sun.star.beans.XPropertySetInfo. Attempts to use <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> to reset an entire group node fail.

Also, because the group nodes can not be reset, the <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> or <idlml>com.sun.star.beans.XMultiPropertyStates:setAllPropertiesToDefault</idlml> cannot be used to reset all descendants of a node.

It is intended to lift this restriction in a future release. To avoid unexpected changes in behavior when this change is introduced, you should apply <idlml>com.sun.star.beans.XPropertyState:setPropertyToDefault</idlml> only to actual properties, such as value items, or set nodes. In particular, you should avoid <idlml>com.sun.star.beans.XMultiPropertyStates:setAllPropertiesToDefault</idlml>() on group nodes.

A more comprehensive example is provided that shows how set elements are created and added, and how it employs advanced techniques for reducing the amount of data that needs to be loaded.

This example uses the OpenOffice.org configuration module org.openoffice.Office.DataAccess. This component has a set item DataSources that contains group items described by the template DataSourceDescription. A data source description holds information about the settings required to connect to a data source.

The template org.openoffice.Office.DataAccess/DataSourceDescription has the following properties that describe the data source connection:

Name Type Comment
URL String Data source URL.
IsPasswordRequired Boolean Is a password needed to connect.
TableFilter String [] Filters tables for display.
TableTypeFilter String [] Filters tables for display.
User String User name to be used for connecting.
LoginTimeout int Default time-out for connection attempt.
SuppressVersionColumns Boolean Controls display of certain data.
DataSourceSettings set node Contains DataSourceSetting entries that contain driver-specific settings.
Bookmarks set node Contains Bookmark entries that link to related documents, for example, Forms.

It also contains the binary properties NumberFormatSettings and LayoutInformation that store information for layout and display of the data source contents. It also contains the set items Tables and Queries containing the layout information for the data access views.

The example shows a procedure that creates and saves basic settings for connecting to a new data source. It uses an asynchronous com.sun.star.configuration.ConfigurationUpdateAccess. Thus, when <idlml>com.sun.star.util.XChangesBatch:commitChanges</idlml> is called, the data becomes visible at the com.sun.star.configuration.ConfigurationProvider, but is only stored in the provider's cache. It is written to the data store at later when the cache is automatically flushed by the com.sun.star.configuration.ConfigurationProvider. As this is done in the background there is no exception when the write-back fails.

Documentation caution.png The recommended method to configure a new data source is to use the com.sun.star.sdb.DatabaseContext service as described in DatabaseContext. This is a high-level service that ensures that all the settings required to establish a connection are properly set.

Among the parameters of the routine is the name of the data source that must be chosen to uniquely identify the data source from other parameters directly related to the above properties. There also is a parameter to pass a list of entries for the DataSourceSettings set.

The resulting routine is:

  // This method stores a data source for given connection data
  void storeDataSource(
          String sDataSourceName,
          String sDataSourceURL,
          String sUser,
          boolean bNeedsPassword,
          int nTimeout,
          com.sun.star.beans.NamedValue [] aDriverSettings,
          String [] aTableFilter ) throws com.sun.star.uno.Exception {
 
      // create the view and get the data source element in a 
      // helper method createDataSourceDescription() (see below)
      Object xDataSource = createDataSourceDescription(getProvider(), sDataSourceName);
 
      // set the values 
      XPropertySet xDataSourceProperties = (XPropertySet)UnoRuntime.queryInterface(
          XPropertySet.class, xDataSource);
 
      xDataSourceProperties.setPropertyValue("URL", sDataSourceURL);
      xDataSourceProperties.setPropertyValue("User", sUser);
      xDataSourceProperties.setPropertyValue("IsPasswordRequired", new Boolean(bNeedsPassword));
      xDataSourceProperties.setPropertyValue("LoginTimeout", new Integer(nTimeout));
 
      if (aTableFilter != null)
          xDataSourceProperties.setPropertyValue("TableFilter", aTableFilter);
 
      // ### store the driver-specific settings ###
      if (aDriverSettings != null) {
          Object xSettingsSet = xDataSourceProperties.getPropertyValue("DataSourceSettings");
 
          // helper for storing (see below)
          storeSettings( xSettingsSet, aDriverSettings);
      }
 
      // ### save the data and dispose the view ###
      // recover the view root (helper method)
      Object xViewRoot = getViewRoot(xDataSource);
 
      // commit the changes
      XChangesBatch xUpdateControl = (XChangesBatch) UnoRuntime.queryInterface(
          XChangesBatch.class, xViewRoot);
 
      xUpdateControl.commitChanges();
 
      // now clean up
      ((XComponent) UnoRuntime.queryInterface(XComponent.class, xViewRoot)).dispose();
  }

Notice the function createDataSourceDescription in our example. It is called to get a DataSourceDescription instance to access a pre-existing item, or create and insert a new item using the passed name.

  /** This method gets the DataSourceDescription for a data source.
      It either gets the existing entry or creates a new instance.
  */
  Object createDataSourceDescription(XMultiServiceFactory xProvider, String sDataSourceName )
              throws com.sun.star.uno.Exception
  {
      // The service name: Need an update access:
      final String cUpdatableView = "com.sun.star.configuration.ConfigurationUpdateAccess";
 
       // The path to the DataSources set node
      final String cDataSourcesPath = "/org.openoffice.Office.DataAccess/DataSources";
 
     // creation arguments: nodepath
      com.sun.star.beans.PropertyValue aPathArgument = new com.sun.star.beans.PropertyValue();
      aPathArgument.Name = "nodepath";
      aPathArgument.Value = cDataSourcesPath ;
 
      Object[] aArguments = new Object[1];
      aArguments[0] = aPathArgument;
 
      // create the view
      Object xViewRoot =
          xProvider.createInstanceWithArguments(cUpdatableView, aArguments);
 
      XNameAccess xSetOfDataSources =
          (XNameAccess) UnoRuntime.queryInterface(XNameAccess.class,xViewRoot);
 
      Object xDataSourceDescriptor = null; // the result
      if ( xSetOfDataSources .hasByName( sDataSourceName ))
      {
          // the element is there
          try
          {
              // the view should point to the element directly, so we need to extend the path
              XHierarchicalName xComposePath = (XHierarchicalName)
                  UnoRuntime.queryInterface(XHierarchicalName.class, xSetOfDataSources );
 
              String sElementPath = xComposePath.composeHierarchicalName( sDataSourceName );
 
              // use the name of the element now
              aPathArgument.Value = sElementPath;
 
              // create another view now
              Object[] aDeepArguments = new Object[1];
              aDeepArguments[0] = aPathArgument;
 
              // create the view
              xDataSourceDescriptor  =
                    xProvider.createInstanceWithArguments(cUpdatableView, aDeepArguments);
 
              if ( xDataSourceDescriptor != null) // all went fine
              {
                  // dispose the other view
                  ((XComponent)UnoRuntime.queryInterface(XComponent.class, xViewRoot)).dispose();
                  xViewRoot = null;
              }
          }
          catch (Exception e)
          {
            // something went wrong, we retry with a new element
             System.err.println("WARNING: An exception occurred while creating a view for an existing data source: " + e);
             xDataSourceDescriptor  = null;
          }
      }
 
      // do we have a result element yet ?
      if ( xDataSourceDescriptor == null)
      {
          // get the container
          XNameContainer xSetUpdate =
              (XNameContainer)UnoRuntime.queryInterface(XNameContainer.class, xViewRoot);
 
          // create a new detached set element (instance of DataSourceDescription)
          XSingleServiceFactory xElementFactory =
              (XSingleServiceFactory)UnoRuntime.queryInterface(XSingleServiceFactory.class, xSetUpdate);
 
          // the new element is the result !
           xDataSourceDescriptor  = xElementFactory.createInstance();
 
          // insert it - this also names the element
          xSetUpdate.insertByName( sDataSourceName ,  xDataSourceDescriptor  );
      }
 
      return xDataSourceDescriptor ;
  }

A method is required to recover the view root from an element object, because it is unknown if the item is the root of the view or a descendant :

  // This method get the view root node given an interface to any node in the view
  public static Object getViewRoot(Object xElement) {
      Object xResult = xElement; 
 
      // set the result to its parent until that would be null 
      Object xParent;
      do {
          XChild xParentAccess =
          (XChild) UnoRuntime.queryInterface(XChild.class,xResult);
 
          if (xParentAccess != null)
              xParent = xParentAccess.getParent();
          else
              xParent = null;
 
          if (xParent != null)
              xResult = xParent;
      }
      while (xParent != null);
 
      return xResult;
  }

Another function used is storeDataSource is storeSettings to store an array of com.sun.star.beans.NamedValues in a set of DataSourceSetting items. A DataSourceSetting contains a single property named Value that is set to any of the basic types supported for configuration values. This example demonstrates the two steps required to add a new item to a set node:

  /// this method stores a number of settings in a set node containing DataSourceSetting objects
  void storeSettings(Object xSettingsSet, com.sun.star.beans.NamedValue [] aSettings)
          throws com.sun.star.uno.Exception {
 
      if (aSettings == null) 
          return;
 
      // get the settings set as a container
      XNameContainer xSettingsContainer = 
          (XNameContainer) UnoRuntime.queryInterface( XNameContainer.class, xSettingsSet);
 
      // and get a factory interface for creating the entries
      XSingleServiceFactory xSettingsFactory = 
          (XSingleServiceFactory) UnoRuntime.queryInterface(XSingleServiceFactory.class, xSettingsSet);
 
      // now insert the individual settings
      for (int i = 0; i < aSettings.length; ++i) {
          // create a DataSourceSetting object
          XPropertySet xSetting = (XPropertySet) 
              UnoRuntime.queryInterface(XPropertySet.class, xSettingsFactory.createInstance());
 
          // can set the value before inserting
          xSetting.setPropertyValue("Value", aSettings[i].Value);
 
          // and now insert or replace as appropriate
          if (xSettingsContainer.hasByName(aSettings[i].Name))
              xSettingsContainer.replaceByName(aSettings[i].Name, xSetting);
          else
              xSettingsContainer.insertByName(aSettings[i].Name, xSetting);
      }
  }

Besides adding a freshly created instance of a template, a set item can be removed from a set and added to any other set supporting the same template for its elements, provided both sets are part of the same view. You cannot move a set item between views, as this contradicts the transactional isolation of views. The set item you removed in one view will still be in its old place in the other. If a set item is moved between sets in one view and the changes are committed, the change appears in another overlapping view as removal of the original item and insertion of a new element in the target location, not as relocation of an identical element.

Tip.png The methods <idlml>com.sun.star.container.XNamed:setName</idlml>() and <idlml>com.sun.star.container.XChild:setParent</idlml>() are supported by a com.sun.star.configuration.ConfigurationUpdateAccess only if it is a com.sun.star.configuration.SetElement. They offer another way to move an item within a set or from one set to another set.

In the current release of OpenOffice.org, these methods are not supported correctly. You can achieve the same effect by using a sequence of remove item - insert item.

In some cases you need to commit the changes in the current view between these two steps.

To rename an item:

/// Does the same as xNamedItem.setName(sNewName) should do
  void renameSetItem(XNamed xNamedItem, String sNewName) throws com.sun.star.uno.Exception {
      XChild xChildItem = (XChild) 
          UnoRuntime.queryInterface(XChild.class, xNamedItem);
 
      XNameContainer xParentSet = (XNameContainer) 
          UnoRuntime.queryInterface(XNameContainer.class, xChildItem.getParent());
 
      String sOldName = xNamedItem.getName();
 
      // now rename the item
      xParentSet.removeByName(sOldName);
      // commit needed to work around known bug
      getViewRoot(xParentSet).commitChanges();
      xParentSet.insertByName(sNewName,xNamedItem);
  }

To move an item to a different parent:

/// Does the same as xChildItem.setParent( xNewParent ) should do
  void moveSetItem(XChild xChildItem, XNameContainer xNewParent) throws com.sun.star.uno.Exception {
      XNamed xNamedItem = (XNamed) 
          UnoRuntime.queryInterface(XNamed.class, xChildItem);
 
      XNameContainer xOldParent = (XNameContainer) 
          UnoRuntime.queryInterface(XNameContainer.class, xChildItem.getParent());
 
      String sItemName = xNamedItem.getName();
 
      // now rename the item
      xOldParent.removeByName(sItemName);
      // commit needed to work around known bug
      getViewRoot(xOldParent).commitChanges();
      xNewParent.insertByName(sItemName,xChildItem);
    }


Content on this page is licensed under the Public Documentation License (PDL).
Personal tools
In other languages