microsoft.exchange.webservices.data.core.service.schema.ServiceObjectSchema.java Source code

Java tutorial

Introduction

Here is the source code for microsoft.exchange.webservices.data.core.service.schema.ServiceObjectSchema.java

Source

/*
 * The MIT License
 * Copyright (c) 2012 Microsoft Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package microsoft.exchange.webservices.data.core.service.schema;

import microsoft.exchange.webservices.data.attribute.EditorBrowsable;
import microsoft.exchange.webservices.data.core.EwsUtilities;
import microsoft.exchange.webservices.data.core.ILazyMember;
import microsoft.exchange.webservices.data.core.LazyMember;
import microsoft.exchange.webservices.data.core.XmlElementNames;
import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.property.PropertyDefinitionFlags;
import microsoft.exchange.webservices.data.misc.OutParam;
import microsoft.exchange.webservices.data.property.complex.ExtendedPropertyCollection;
import microsoft.exchange.webservices.data.property.complex.ICreateComplexPropertyDelegate;
import microsoft.exchange.webservices.data.property.definition.ComplexPropertyDefinition;
import microsoft.exchange.webservices.data.property.definition.IndexedPropertyDefinition;
import microsoft.exchange.webservices.data.property.definition.PropertyDefinition;
import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Represents the base class for all item and folder schema.
 */
@EditorBrowsable(state = EditorBrowsableState.Never)
public abstract class ServiceObjectSchema implements Iterable<PropertyDefinition> {

    private static final Log LOG = LogFactory.getLog(ServiceObjectSchema.class);

    /**
     * The lock object.
     */
    private static final Object lockObject = new Object();

    /**
     * List of all schema types. If you add a new ServiceObject subclass that
     * has an associated schema, add the schema type to the list below.
     */
    private static LazyMember<List<Class<?>>> allSchemaTypes = new LazyMember<List<Class<?>>>(
            new ILazyMember<List<Class<?>>>() {
                public List<Class<?>> createInstance() {
                    List<Class<?>> typeList = new ArrayList<Class<?>>();
                    // typeList.add()
                    /*
                    * typeList.add(AppointmentSchema.class);
                    * typeList.add(CalendarResponseObjectSchema.class);
                    * typeList.add(CancelMeetingMessageSchema.class);
                    * typeList.add(ContactGroupSchema.class);
                    * typeList.add(ContactSchema.class);
                    * typeList.add(EmailMessageSchema.class);
                    * typeList.add(FolderSchema.class);
                    * typeList.add(ItemSchema.class);
                    * typeList.add(MeetingMessageSchema.class);
                    * typeList.add(MeetingRequestSchema.class);
                    * typeList.add(PostItemSchema.class);
                    * typeList.add(PostReplySchema.class);
                    * typeList.add(ResponseMessageSchema.class);
                    * typeList.add(ResponseObjectSchema.class);
                    * typeList.add(ServiceObjectSchema.class);
                    * typeList.add(SearchFolderSchema.class);
                    * typeList.add(TaskSchema.class);
                    */
                    // Verify that all Schema types in the Managed API assembly
                    // have been included.
                    /*
                    * var missingTypes = from type in
                    * Assembly.GetExecutingAssembly().GetTypes() where
                    * type.IsSubclassOf(typeof(ServiceObjectSchema)) &&
                    * !typeList.Contains(type) select type; if
                    * (missingTypes.Count() > 0) { throw new
                    * ServiceLocalException
                    * ("SchemaTypeList does not include all 
                    * defined schema types."
                    * ); }
                    */
                    return typeList;
                }
            });

    /**
     * Dictionary of all property definitions.
     */
    private static LazyMember<Map<String, PropertyDefinitionBase>> allSchemaProperties = new LazyMember<Map<String, PropertyDefinitionBase>>(
            new ILazyMember<Map<String, PropertyDefinitionBase>>() {
                public Map<String, PropertyDefinitionBase> createInstance() {
                    Map<String, PropertyDefinitionBase> propDefDictionary = new HashMap<String, PropertyDefinitionBase>();
                    for (Class<?> c : ServiceObjectSchema.allSchemaTypes.getMember()) {
                        ServiceObjectSchema.addSchemaPropertiesToDictionary(c, propDefDictionary);
                    }
                    return propDefDictionary;
                }
            });

    /**
     * Adds schema property to dictionary.
     *
     * @param type              Schema type.
     * @param propDefDictionary The property definition dictionary.
     */
    protected static void addSchemaPropertiesToDictionary(Class<?> type,
            Map<String, PropertyDefinitionBase> propDefDictionary) {
        Field[] fields = type.getDeclaredFields();
        for (Field field : fields) {
            int modifier = field.getModifiers();
            if (Modifier.isPublic(modifier) && Modifier.isStatic(modifier)) {
                Object o;
                try {
                    o = field.get(null);
                    if (o instanceof PropertyDefinition) {
                        PropertyDefinition propertyDefinition = (PropertyDefinition) o;
                        // Some property definitions descend from
                        // ServiceObjectPropertyDefinition but don't have
                        // a Uri, like ExtendedProperties. Ignore them.
                        if (null != propertyDefinition.getUri() && !propertyDefinition.getUri().isEmpty()) {
                            PropertyDefinitionBase existingPropertyDefinition;
                            if (propDefDictionary.containsKey(propertyDefinition.getUri())) {
                                existingPropertyDefinition = propDefDictionary.get(propertyDefinition.getUri());
                                EwsUtilities.ewsAssert(existingPropertyDefinition == propertyDefinition,
                                        "Schema.allSchemaProperties." + "delegate",
                                        String.format(
                                                "There are at least " + "two distinct property "
                                                        + "definitions with the" + " following URI: %s",
                                                propertyDefinition.getUri()));
                            } else {
                                propDefDictionary.put(propertyDefinition.getUri(), propertyDefinition);
                                // The following is a "generic hack" to register
                                // property that are not public and
                                // thus not returned by the above GetFields
                                // call. It is currently solely used to register
                                // the MeetingTimeZone property.
                                List<PropertyDefinition> associatedInternalProperties = propertyDefinition
                                        .getAssociatedInternalProperties();
                                for (PropertyDefinition associatedInternalProperty : associatedInternalProperties) {
                                    propDefDictionary.put(associatedInternalProperty.getUri(),
                                            associatedInternalProperty);
                                }

                            }
                        }
                    }
                } catch (IllegalArgumentException e) {
                    LOG.error(e);

                    // Skip the field
                } catch (IllegalAccessException e) {
                    LOG.error(e);

                    // Skip the field
                }

            }
        }
    }

    /**
     * Adds the schema property names to dictionary.
     *
     * @param type                   The type.
     * @param propertyNameDictionary The property name dictionary.
     */
    protected static void addSchemaPropertyNamesToDictionary(Class<?> type,
            Map<PropertyDefinition, String> propertyNameDictionary) {

        Field[] fields = type.getDeclaredFields();
        for (Field field : fields) {
            int modifier = field.getModifiers();
            if (Modifier.isPublic(modifier) && Modifier.isStatic(modifier)) {
                Object o;
                try {
                    o = field.get(null);
                    if (o instanceof PropertyDefinition) {
                        PropertyDefinition propertyDefinition = (PropertyDefinition) o;
                        propertyNameDictionary.put(propertyDefinition, field.getName());
                    }
                } catch (IllegalArgumentException e) {
                    LOG.error(e);

                    // Skip the field
                } catch (IllegalAccessException e) {
                    LOG.error(e);

                    // Skip the field
                }
            }
        }
    }

    /**
     * Initializes a new instance.
     */
    protected ServiceObjectSchema() {
        this.registerProperties();
    }

    /**
     * Finds the property definition.
     *
     * @param uri The URI.
     * @return Property definition.
     */
    public static PropertyDefinitionBase findPropertyDefinition(String uri) {
        return ServiceObjectSchema.allSchemaProperties.getMember().get(uri);
    }

    /**
     * Initialize schema property names.
     */
    public static void initializeSchemaPropertyNames() {
        synchronized (lockObject) {
            for (Class<?> type : ServiceObjectSchema.allSchemaTypes.getMember()) {
                Field[] fields = type.getDeclaredFields();
                for (Field field : fields) {
                    int modifier = field.getModifiers();
                    if (Modifier.isPublic(modifier) && Modifier.isStatic(modifier)) {
                        Object o;
                        try {
                            o = field.get(null);
                            if (o instanceof PropertyDefinition) {
                                PropertyDefinition propertyDefinition = (PropertyDefinition) o;
                                propertyDefinition.setName(field.getName());
                            }
                        } catch (IllegalArgumentException e) {
                            LOG.error(e);

                            // Skip the field
                        } catch (IllegalAccessException e) {
                            LOG.error(e);

                            // Skip the field
                        }
                    }
                }
            }
        }
    }

    /**
     * Defines the ExtendedProperties property.
     */
    public static final PropertyDefinition extendedProperties = new ComplexPropertyDefinition<ExtendedPropertyCollection>(
            ExtendedPropertyCollection.class, XmlElementNames.ExtendedProperty,
            EnumSet.of(PropertyDefinitionFlags.AutoInstantiateOnRead, PropertyDefinitionFlags.ReuseInstance,
                    PropertyDefinitionFlags.CanSet, PropertyDefinitionFlags.CanUpdate),
            ExchangeVersion.Exchange2007_SP1, new ICreateComplexPropertyDelegate<ExtendedPropertyCollection>() {
                public ExtendedPropertyCollection createComplexProperty() {
                    return new ExtendedPropertyCollection();
                }
            });

    /**
     * The property.
     */
    private Map<String, PropertyDefinition> properties = new HashMap<String, PropertyDefinition>();

    /**
     * The visible property.
     */
    private List<PropertyDefinition> visibleProperties = new ArrayList<PropertyDefinition>();

    /**
     * The first class property.
     */
    private List<PropertyDefinition> firstClassProperties = new ArrayList<PropertyDefinition>();

    /**
     * The first class summary property.
     */
    private List<PropertyDefinition> firstClassSummaryProperties = new ArrayList<PropertyDefinition>();

    private List<IndexedPropertyDefinition> indexedProperties = new ArrayList<IndexedPropertyDefinition>();

    /**
     * Registers a schema property.
     *
     * @param property   The property to register.
     * @param isInternal Indicates whether the property is internal or should be
     *                   visible to developers.
     */
    private void registerProperty(PropertyDefinition property, boolean isInternal) {
        this.properties.put(property.getXmlElement(), property);

        if (!isInternal) {
            this.visibleProperties.add(property);
        }

        // If this property does not have to be requested explicitly, add
        // it to the list of firstClassProperties.
        if (!property.hasFlag(PropertyDefinitionFlags.MustBeExplicitlyLoaded)) {
            this.firstClassProperties.add(property);
        }

        // If this property can be found, add it to the list of
        // firstClassSummaryProperties
        if (property.hasFlag(PropertyDefinitionFlags.CanFind)) {
            this.firstClassSummaryProperties.add(property);
        }
    }

    /**
     * Registers a schema property that will be visible to developers.
     *
     * @param property The property to register.
     */
    protected void registerProperty(PropertyDefinition property) {
        this.registerProperty(property, false);
    }

    /**
     * Registers an internal schema property.
     *
     * @param property The property to register.
     */
    protected void registerInternalProperty(PropertyDefinition property) {
        this.registerProperty(property, true);
    }

    /**
     * Registers an indexed property.
     *
     * @param indexedProperty The indexed property to register.
     */
    protected void registerIndexedProperty(IndexedPropertyDefinition indexedProperty) {
        this.indexedProperties.add(indexedProperty);
    }

    /**
     * Registers property.
     */
    protected void registerProperties() {
    }

    /**
     * Gets the list of first class property for this service object type.
     *
     * @return the first class property
     */
    public List<PropertyDefinition> getFirstClassProperties() {
        return this.firstClassProperties;
    }

    /**
     * Gets the list of first class summary property for this service object
     * type.
     *
     * @return the first class summary property
     */
    public List<PropertyDefinition> getFirstClassSummaryProperties() {
        return this.firstClassSummaryProperties;
    }

    /**
     * Tries to get property definition.
     *
     * @param xmlElementName             Name of the XML element.
     * @param propertyDefinitionOutParam The property definition.
     * @return True if property definition exists.
     */
    public boolean tryGetPropertyDefinition(String xmlElementName,
            OutParam<PropertyDefinition> propertyDefinitionOutParam) {
        if (this.properties.containsKey(xmlElementName)) {
            propertyDefinitionOutParam.setParam(this.properties.get(xmlElementName));
            return true;
        } else {
            return false;
        }
    }

    /**
     * Returns an iterator over a set of elements of type T.
     *
     * @return an Iterator.
     */
    @Override
    public Iterator<PropertyDefinition> iterator() {
        return this.visibleProperties.iterator();
    }
}