/* * Copyright (C) 2011 Alexey Matveev <mvaleksej@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.matveev.pomodoro4nb.data; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CopyOnWriteArrayList; import org.matveev.pomodoro4nb.utils.Utils; /** * * @author Alexey Matvey */ public class Properties { public static final Property<UUID> Id = new Property<UUID>("id", UUID.class); public static final Property<String> SerializeKey = new Property<String>("key", String.class); @Ignore public static final Property<String> ClassType = new Property<String>("class", String.class); private final Map<Property<?>, Object> holder; private final List<Properties> elements; private final List<PropertyListener> listeners; public Properties() { holder = new LinkedHashMap<Property<?>, Object>(); elements = new CopyOnWriteArrayList<Properties>(); listeners = new CopyOnWriteArrayList<PropertyListener>(); setProperty(Id, UUID.randomUUID()); setProperty(ClassType, getClass().getName()); setProperty(SerializeKey, getClass().getSimpleName()); } public final <T> T getProperty(Property<T> property) { return property.getType().cast(holder.get(property)); } public final <T> T getProperty(Property<T> property, T fallback) { T value = (T) holder.get(property); return value != null ? property.getType().cast(value) : fallback; } public final <T, V> void setProperty(Property<T> property, V value) { if (!property.getType().equals(value.getClass())) { throw new IllegalArgumentException( "Cannot set value with type '" + value.getClass() + "' to property with type '" + property.getType() + "'"); } V oldValue = (V) holder.get(property); if (value != oldValue) { holder.put(property, value); fire(property, oldValue, value); } } public Set<Property<?>> getProperties() { return holder.keySet(); } public void addElement(Properties e) { checkArguments(e); elements.add(e); } public void addElement(int index, Properties e) { checkArguments(e); elements.add(index, e); } public void removeElement(int index) { elements.remove(index); } public void removeElement(Properties e) { checkArguments(e); elements.remove(e); } public void removeElements() { elements.clear(); } private void checkArguments(Properties element) { if (element == null) { throw new IllegalArgumentException("This container cannot contain 'null' elements"); } final Children children = getClass().getAnnotation(Children.class); if (children == null || !Arrays.asList(children.value()).contains(element.getClass())) { throw new IllegalArgumentException("The container '" + getClass().getName() + "' cannot contain elements with type '" + element.getClass().getName() + "'"); } } public List<Properties> getElements(Class<? extends Properties>... types) { final List<Properties> result = new ArrayList<Properties>(); for (Properties p : getElements()) { final String name = p.getProperty(Properties.ClassType); if (name != null && Utils.isContains(name, types)) { result.add(p); } } return result; } public List<Properties> getElements() { return Collections.unmodifiableList(elements); } protected void fire(Property<?> property, Object oldValue, Object newValue) { for (PropertyListener l : listeners) { l.propertyChange(property, oldValue, newValue); } } public void addPropertyListener(PropertyListener listener) { listeners.add(listener); } public void removePropertyListener(PropertyListener listener) { listeners.remove(listener); } @Override public String toString() { boolean first = true; StringBuilder builder = new StringBuilder(); builder.append('{'); for (Map.Entry<Property<?>, Object> entry : holder.entrySet()) { if (first) { first = false; } else { builder.append(", "); } builder.append(entry.getKey().getName()); builder.append('='); builder.append(entry.getValue()); } builder.append('}'); return builder.toString(); } }