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 }