arcgissamples\geodatabase\classextension\TimeStamper.java
/* Copyright 2010 ESRI * * All rights reserved under the copyright laws of the United States * and applicable international laws, treaties, and conventions. * * You may freely redistribute and use this sample code, with or * without modification, provided you include the original copyright * notice and use restrictions. * * See the use restrictions. * */ package arcgissamples.geodatabase.classextension; import java.io.IOException; import java.util.Date; import com.esri.arcgis.geodatabase.*; import com.esri.arcgis.interop.AutomationException; import com.esri.arcgis.interop.extn.ArcGISCategories; import com.esri.arcgis.interop.extn.ArcGISExtension; import com.esri.arcgis.system.IPropertySet; import com.esri.arcgis.system.PropertySet; @ArcGISExtension(categories = { ArcGISCategories.GeoObjectClassExtensions }) public class TimeStamper implements IClassExtension, _IObjectClassEvents, IObjectClassExtension { private static final long serialVersionUID = -4883301133761264384L; /** * The property set keys used to get and set the extension properties. */ public final static String CREATED_FIELD_PROPERTY = "CREATION_FIELDNAME"; public final static String MODIFIED_FIELD_PROPERTY = "MODIFICATION_FIELDNAME"; public final static String USER_FIELD_PROPERTY = "USER_FIELDNAME"; /** * The default field names to use as timestamp fields, if none are defined when the * class extension is applied. */ private final static String DEFAULT_CREATED_FIELD = "CREATED"; private final static String DEFAULT_MODIFIED_FIELD = "MODIFIED"; private final static String DEFAULT_USER_FIELD = "USERNAME"; /** * The indexes of the timestamp fields within the extension's class. A value of -1 indicates * that the field is not used, or could not be found during initialization. */ private int createdFieldIndex = -1; private int modifiedFieldIndex = -1; private int userFieldIndex = -1; /** * The name that will be entered into the user field. On an ArcSDE geodatabase, this will be * the connected user, while on a local geodatabase this will be the user as specified by the * operating system. */ private String userName = ""; /************************************************************************************************ * com.esri.arcgis.geodatabase.IClassExtension * This is the most crucial interface for Class Extensions. This is * not optional and every class extension must implement this interface. * If there is an error in your code here, none of your users will be able to access the data * in the object class. ************************************************************************************************/ /** * This method initializes the extension, passing in a reference to its class helper. This method is fired * every time your object class is opened. If your object class is contained within a feature * dataset, init() will fire as soon as any of the other feature classes are opened. * Thus, within a feature dataset, if one feature class is opened, all the others are * opened as well. This can cause your class extension's init() method to fire when * you might not expect it. You will typically use init() to initialize objects you want to * store at the class level. */ public void init(IClassHelper classHelper, IPropertySet extensionProperties) throws IOException, AutomationException { // Get a reference to the extension's object class. IClass baseClass = classHelper.esri_getClass(); // Make sure a valid property set was provided. if (extensionProperties != null && extensionProperties.getCount() != 0) { // Get the field names from the property set. Object[] propertyKeysParam = new Object[1]; Object[] propertyValuesParam = new Object[1]; extensionProperties.getAllProperties(propertyKeysParam, propertyValuesParam); String[] propertyKeys = (String[])propertyKeysParam[0]; Object[] propertyValues = (Object[])propertyValuesParam[0]; // Iterate through the key/value pairs. for (int i = 0; i < propertyKeys.length; i++) { // Get the current key/value pair. String propertyKey = propertyKeys[i]; String propertyValue = propertyValues[i].toString(); if (propertyKey.equals(CREATED_FIELD_PROPERTY)) { createdFieldIndex = baseClass.findField(propertyValue); } if (propertyKey.equals(MODIFIED_FIELD_PROPERTY)) { modifiedFieldIndex = baseClass.findField(propertyValue); } if (propertyKey.equals(USER_FIELD_PROPERTY)) { userFieldIndex = baseClass.findField(propertyValue.toString()); userName = getUserName(baseClass); } } } else { // If the extension properties are null or empty, we can assume the class has // been created without extension properties. Apply the default property values. ISchemaLock schemaLock = null; try { // Attempt to acquire an exclusive schema lock. If this fails, an // AutomationException will be raised. schemaLock = new ISchemaLockProxy(classHelper.esri_getClass()); schemaLock.changeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock); // Create a default set of extension properties. IPropertySet propertySet = new PropertySet(); propertySet.setProperty(CREATED_FIELD_PROPERTY, DEFAULT_CREATED_FIELD); propertySet.setProperty(MODIFIED_FIELD_PROPERTY, DEFAULT_MODIFIED_FIELD); propertySet.setProperty(USER_FIELD_PROPERTY, DEFAULT_USER_FIELD); // Use the IClassSchemaEdit2 interface to persist a new set of // extension properties. IClassSchemaEdit2 classSchemaEdit2 = new IClassSchemaEdit2Proxy(classHelper.esri_getClass()); classSchemaEdit2.alterClassExtensionProperties(propertySet); } catch (AutomationException autoExc) { // An exclusive schema lock could not be acquired. Allow the extension to // finish initializing, but no custom behavior will occur. } finally { try { // Ensure that the schema lock is shared. if (schemaLock != null) schemaLock.changeSchemaLock(esriSchemaLock.esriSharedSchemaLock); } catch (Exception exc) { // Ignore any errors at this point. } } } } /** * Informs the extension that its class helper is going away. */ public void shutdown() throws IOException, AutomationException { // Do nothing. } /************************************************************************************************ * com.esri.arcgis.geodatabase._IObjectClassEvents * This is a "fake" interface, in that it mimics the com.esri.arcgis.geodatabase.IObjectClassEvents. The events that IObjectClassEvents * is required to handle in Java have no COM counterparts, therefore a "fake" interface called _IObjectClassEvents was created that can * handle Java events derived from java.util.EventObject. ************************************************************************************************/ /** * This event is fired when an object's attributes or geometry is updated. */ public void onChange(IObject obj) throws IOException, AutomationException { // Make sure the modified field is defined. if (modifiedFieldIndex != -1) { obj.setValue(modifiedFieldIndex, new Date()); } // If the user field is defined, set it as well. if (userFieldIndex != -1) { obj.setValue(userFieldIndex, userName); } } /** * This event is fired when a new object is created in the object class. */ public void onCreate(IObject obj) throws IOException, AutomationException { // Make sure the created field is defined. if (createdFieldIndex != -1) { obj.setValue(createdFieldIndex, new Date()); } // If the user field is defined, set it as well. if (userFieldIndex != -1) { obj.setValue(userFieldIndex, userName); } } /** * This event is fired when an object is deleted from the object class. */ public void onDelete(IObject obj) throws IOException, AutomationException { // Do nothing. } /******************************************************************************** * Utils *********************************************************************************/ /** * Returns the name of the user accessing the object class. If the class is in an ArcSDE * geodatabase, the connected user name will be returned, whereas if the class is in a * local geodatabase the OS user name will be used. */ private String getUserName(IClass baseClass) throws IOException, AutomationException { String userName = null; // Check the class' workspace type. IDataset dataset = new IDatasetProxy(baseClass); Workspace workspace = new Workspace(dataset.getWorkspace()); if (workspace.getType() == esriWorkspaceType.esriRemoteDatabaseWorkspace) { // The database is an ArcSDE database - get the connected user. userName = workspace.getConnectedUser(); } else { // The database is local - get the system-defined user. userName = System.getProperty("user.name"); } return userName; } }