001    /*
002     * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003     * Copyright (C) 2011 NightLabs Consulting GmbH
004     *
005     * This program is free software: you can redistribute it and/or modify
006     * it under the terms of the GNU Affero General Public License as
007     * published by the Free Software Foundation, either version 3 of the
008     * License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU Affero General Public License for more details.
014     *
015     * You should have received a copy of the GNU Affero General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    package org.cumulus4j.keystore.prop;
019    
020    import java.util.Collection;
021    import java.util.UUID;
022    
023    import org.cumulus4j.keystore.KeyStore;
024    
025    /**
026     * <p>
027     * Base class for all properties.
028     * </p>
029     * <p>
030     * The <code>KeyStore</code> supports managing arbitrary properties in the form of
031     * name-value-pairs. The names are plain-text, but the values are encrypted.
032     * A property-value can be of any type for which a subclass of
033     * {@link org.cumulus4j.keystore.prop.Property} exists.
034     * </p>
035     * <p>
036     * <b>Important:</b> Do not instantiate properties yourself! Use {@link KeyStore#getProperty(String, char[], Class, String)}
037     * instead!
038     * </p>
039     *
040     * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
041     *
042     * @param <T> the type of the property-value.
043     */
044    public abstract class Property<T>
045    implements Comparable<Property<?>>
046    {
047            private String name;
048    
049            private UUID xxx;
050    
051            /**
052             * <p>
053             * Get the property's unique name.
054             * </p>
055             * <p>
056             * This name is used as key to uniquely identify a property in the key store.
057             * </p>
058             *
059             * @return the property's name.
060             */
061            public String getName() {
062                    return name;
063            }
064    
065            /**
066             * <p>
067             * Set the property's unique name.
068             * </p>
069             * <p>
070             * You should never call this method directly. The name is set by {@link KeyStore#getProperty(String, char[], Class, String)}.
071             * </p>
072             *
073             * @param name the property's name.
074             */
075            public void setName(String name)
076            {
077                    if (this.name != null && !this.name.equals(name))
078                            throw new IllegalStateException("The name of a property cannot be changed after it has been assigned once!");
079    
080                    this.name = name;
081            }
082    
083            private T value;
084    
085            /**
086             * Get the property's value.
087             * @return the value or <code>null</code>.
088             * @see #setValue(Object)
089             */
090            public T getValue() {
091                    return value;
092            }
093            /**
094             * Set the property's value.
095             * @param value the value or <code>null</code>.
096             * @see #getValue()
097             */
098            public void setValue(T value)
099            {
100                    this.value = value;
101            }
102    
103            /**
104             * <p>
105             * Get the property's {@link #getValue() value} encoded as byte-array or <code>null</code>, if the
106             * property is empty. Note, that this might be <code>null</code>, even though {@link #getValue()} returns
107             * a non-<code>null</code> value; for example an empty {@link Collection} might cause this.
108             * </p>
109             * <p>
110             * This method must encode the value in a way that can be decoded by {@link #setValueEncoded(byte[])}.
111             * </p>
112             * @return the byte-array-representation of the property-value or <code>null</code>.
113             * @see #setValueEncoded(byte[])
114             */
115            public abstract byte[] getValueEncoded();
116    
117            /**
118             * <p>
119             * Set the property's {@link #getValue() value} encoded as byte-array or <code>null</code>,
120             * if the property shall be empty.
121             * </p>
122             * <p>
123             * This method must be symmetric to {@link #getValueEncoded()}, i.e. every possible result of <code>getValueEncoded()</code>
124             * must be understood by this method. A byte-array that is not understood should cause an {@link IllegalArgumentException}.
125             * </p>
126             * @param encodedValue the byte-array-representation of the property-value or <code>null</code>.
127             * @throws IllegalArgumentException if the <code>encodedValue</code> cannot be parsed.
128             * @see #getValueEncoded()
129             */
130            public abstract void setValueEncoded(byte[] encodedValue)
131            throws IllegalArgumentException;
132    
133            @Override
134            public String toString() {
135                    return super.toString() + '[' + getName() + ',' + getValue() + ']';
136            }
137    
138            /**
139             * <p>Internal value used to detect improper usage of the API.</p>
140             * <p>
141             * <b>Important:</b> This method is not part of the API! <b>Do not use this method!</b>
142             * </p>
143             * @return the internal value.
144             * @see KeyStore#getProperty(String, char[], Class, String)
145             */
146            public UUID getXxx() {
147                    return xxx;
148            }
149            /**
150             * <p>Internal value used to detect improper usage of the API.</p>
151             * <p>
152             * <b>Important:</b> This method is not part of the API! <b>Do not use this method!</b>
153             * </p>
154             * @param xxx the internal value.
155             * @see KeyStore#getProperty(String, char[], Class, String)
156             */
157            public void setXxx(UUID xxx) {
158                    this.xxx = xxx;
159            }
160    
161            @Override
162            public int compareTo(Property<?> o)
163            {
164                    if (o == null)
165                            return 1;
166    
167                    if (this.getName() == null) {
168                            if (o.getName() == null)
169                                    return 0;
170                            else
171                                    return -1;
172                    }
173    
174                    if (o.getName() == null)
175                            return 1;
176                    else
177                            return this.getName().compareTo(o.getName());
178            }
179    
180            @Override
181            public int hashCode()
182            {
183                    return name == null ? 0 : name.hashCode();
184            }
185    
186            @Override
187            public boolean equals(Object obj) {
188                    if (this == obj) return true;
189                    if (obj == null) return false;
190                    if (getClass() != obj.getClass()) return false;
191                    Property<?> other = (Property<?>) obj;
192                    return (
193                                    this.getName() == other.getName() ||
194                                    (this.getName() != null && this.getName().equals(other.getName()))
195                    );
196            }
197    }