1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ClassMetadata.java,v 1.1 2008/02/07 17:12:28 mark Exp $
7 */
8
9package com.sleepycat.persist.model;
10
11import java.io.Serializable;
12import java.util.List;
13import java.util.Map;
14
15/**
16 * The metadata for a persistent class.  A persistent class may be specified
17 * with the {@link Entity} or {@link Persistent} annotation.
18 *
19 * <p>{@code ClassMetadata} objects are thread-safe.  Multiple threads may
20 * safely call the methods of a shared {@code ClassMetadata} object.</p>
21 *
22 * <p>This and other metadata classes are classes rather than interfaces to
23 * allow adding properties to the model at a future date without causing
24 * incompatibilities.  Any such property will be given a default value and
25 * its use will be optional.</p>
26 *
27 * @author Mark Hayes
28 */
29public class ClassMetadata implements Serializable {
30
31    private static final long serialVersionUID = -2520207423701776679L;
32
33    private String className;
34    private int version;
35    private String proxiedClassName;
36    private boolean entityClass;
37    private PrimaryKeyMetadata primaryKey;
38    private Map<String,SecondaryKeyMetadata> secondaryKeys;
39    private List<FieldMetadata> compositeKeyFields;
40
41    /**
42     * Used by an {@code EntityModel} to construct persistent class metadata.
43     */
44    public ClassMetadata(String className,
45                         int version,
46                         String proxiedClassName,
47                         boolean entityClass,
48                         PrimaryKeyMetadata primaryKey,
49                         Map<String,SecondaryKeyMetadata> secondaryKeys,
50                         List<FieldMetadata> compositeKeyFields) {
51        this.className = className;
52        this.version = version;
53        this.proxiedClassName = proxiedClassName;
54        this.entityClass = entityClass;
55        this.primaryKey = primaryKey;
56        this.secondaryKeys = secondaryKeys;
57        this.compositeKeyFields = compositeKeyFields;
58    }
59
60    /**
61     * Returns the name of the persistent class.
62     */
63    public String getClassName() {
64        return className;
65    }
66
67    /**
68     * Returns the version of this persistent class.  This may be specified
69     * using the {@link Entity#version} or {@link Persistent#version}
70     * annotation.
71     */
72    public int getVersion() {
73        return version;
74    }
75
76    /**
77     * Returns the class name of the proxied class if this class is a {@link
78     * PersistentProxy}, or null otherwise.
79     */
80    public String getProxiedClassName() {
81        return proxiedClassName;
82    }
83
84    /**
85     * Returns whether this class is an entity class.
86     */
87    public boolean isEntityClass() {
88        return entityClass;
89    }
90
91    /**
92     * Returns the primary key metadata for a key declared in this class, or
93     * null if none is declared.  This may be specified using the {@link
94     * PrimaryKey} annotation.
95     */
96    public PrimaryKeyMetadata getPrimaryKey() {
97        return primaryKey;
98    }
99
100    /**
101     * Returns an unmodifiable map of field name to secondary key metadata for
102     * all secondary keys declared in this class, or null if no secondary keys
103     * are declared in this class.  This metadata may be specified using {@link
104     * SecondaryKey} annotations.
105     */
106    public Map<String,SecondaryKeyMetadata> getSecondaryKeys() {
107        return secondaryKeys;
108    }
109
110    /**
111     * Returns an unmodifiable list of metadata for the fields making up a
112     * composite key, or null if this is a not a composite key class.  The
113     * order of the fields in the returned list determines their stored order
114     * and may be specified using the {@link KeyField} annotation.  When the
115     * composite key class does not implement {@link Comparable}, the order of
116     * the fields is the relative sort order.
117     */
118    public List<FieldMetadata> getCompositeKeyFields() {
119        return compositeKeyFields;
120    }
121
122    @Override
123    public boolean equals(Object other) {
124        if (other instanceof ClassMetadata) {
125            ClassMetadata o = (ClassMetadata) other;
126            return version == o.version &&
127                   entityClass == o.entityClass &&
128                   nullOrEqual(className, o.className) &&
129                   nullOrEqual(proxiedClassName, o.proxiedClassName) &&
130                   nullOrEqual(primaryKey, o.primaryKey) &&
131                   nullOrEqual(secondaryKeys, o.secondaryKeys) &&
132                   nullOrEqual(compositeKeyFields, o.compositeKeyFields);
133        } else {
134            return false;
135        }
136    }
137
138    @Override
139    public int hashCode() {
140        return version +
141               (entityClass ? 1 : 0) +
142               hashCode(className) +
143               hashCode(proxiedClassName) +
144               hashCode(primaryKey) +
145               hashCode(secondaryKeys) +
146               hashCode(compositeKeyFields);
147    }
148
149    static boolean nullOrEqual(Object o1, Object o2) {
150        if (o1 == null) {
151            return o2 == null;
152        } else {
153            return o1.equals(o2);
154        }
155    }
156
157    static int hashCode(Object o) {
158        if (o != null) {
159            return o.hashCode();
160        } else {
161            return 0;
162        }
163    }
164}
165