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 }