/* Copyright 2008-2010 Gephi Authors : Martin Škurla <bujacik@gmail.com> Website : http://www.gephi.org This file is part of Gephi. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. Copyright 2011 Gephi Consortium. All rights reserved. The contents of this file are subject to the terms of either the GNU General Public License Version 3 only ("GPL") or the Common Development and Distribution License("CDDL") (collectively, the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the License at http://gephi.org/about/legal/license-notice/ or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the specific language governing permissions and limitations under the License. When distributing the software, include this License Header Notice in each file and include the License files at /cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the License Header, with the fields enclosed by brackets [] replaced by your own identifying information: "Portions Copyrighted [year] [name of copyright owner]" If you wish your version of this file to be governed by only the CDDL or only the GPL Version 3, indicate your decision by adding "[Contributor] elects to include this software in this distribution under the [CDDL or GPL Version 3] license." If you do not indicate a single choice of license, a recipient has the option to distribute your version of this file under either the CDDL, the GPL Version 3 or to extend the choice of license to its licensees as provided above. However, if you add GPL Version 3 code and therefore, elected the GPL Version 3 license, then the option applies only if the new code is made subject to such option by the copyright holder. Contributor(s): Portions Copyrighted 2011 Gephi Consortium. */ package org.gephi.data.attributes.type; import java.util.Arrays; /** * Complex type that defines list of any type of items. Can be created from an array or from single * string using either given or default separators. Internal representation of data is array of generic * type. This means that every primitive type must be first converted into wrapper type. The exact * conversion process from String value into given type is done by {@link TypeConvertor TypeConvertor} * class. * * <br/><br/> * <h3>Design guidelines</h3> * This is a basic abstract class that every other 'List' class should extend. In order to not misuse * the API, every extending type should be one of the following: * <ul> * <li>helper type which restricts the type parameter and possibly brings some new functionality (e.g. * {@link NumberList NumberList}). This is not final usable type so it should be declared as abstract. * <li>final type that extends any of defined helper types or basic class and sets the type parameter * (e.g. there are types for representing all primitive types, String, BigInteger & BigDecimal). * These are final usable types so they should be declared as final. * </ul> * * <h3>Flexibility</h3> * The flexibility of this API is done in 2 ways: * <ul> * <li>We can add functionality by defining conversions from any other type in difference from general * supported types through defining new constructors (e.g. {@link StringList StringList} class can * be created from array of characters). We can also restrict the functionality (e.g. BigInteger & * BigDecimal cannot be created from arrays of primitive types). The conversion process should be * done by {@link TypeConvertor TypeConvertor} type if the conversion can be used in more List * implementations or by 'private static T parseXXX()' method in appropriate List implementation if * only this type uses the conversion (e.g. {@link StringList#parse}). * <li>Any other functionality required from 'List' implementations should be done by implementing * appropriate non-static methods in concrete 'List' implementations. * </ul> * * <h3>Extensibility</h3> * This API can be simply extended. New 'List' type should extend base or any helper 'List' type. We can * create final 'List' implementations as well as helper 'list' implementations with appropriate modifiers * (see Design Guidelines). We can define as many constructors responsible for conversions from other * types and as many additional methods as we want.<br/> * To fully integrate new 'List' type into the whole codebase we have to update following types: * <ol> * <li>{@link org.gephi.data.attributes.api.AttributeType AttributeType}: * <ol> * <li>add appropriate enum constants * <li>update {@link org.gephi.data.attributes.api.AttributeType#parse(String str) parse(String)} method * </ol> * <li>{@link org.gephi.data.attributes.model.DataIndex DataIndex}: * <ol> * <li>add appropriate type represented by Class object into * {@link org.gephi.data.attributes.model.DataIndex#SUPPORTED_TYPES SUPPORTED_TYPES} array * </ol> * </ol> * * This class defines {@link #size method for recognizing size} of the list and * {@link #getItem method for getting item by index}. * * @param <T> type parameter defining final List type * * @author Martin Škurla * * @see TypeConvertor */ public abstract class AbstractList<T> { public static final String DEFAULT_SEPARATOR = ",|;"; protected final T[] list; private volatile int hashCode = 0; public AbstractList(String input, Class<T> finalType) { this(input, DEFAULT_SEPARATOR, finalType); } public AbstractList(String input, String separator, Class<T> finalType) { this(TypeConvertor.<T>createArrayFromString(input, separator, finalType)); } public AbstractList(T[] array) { this.list = Arrays.copyOf(array, array.length); } public int size() { return list.length; } public T getItem(int index) { if (index >= list.length) { return null; } return list[index]; } public boolean contains(T value) { for (int i = 0; i < list.length; i++) { if (list[i].equals(value)) { return true; } } return false; } @Override public String toString() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < list.length; i++) { builder.append(list[i]); builder.append(','); } if (list.length > 0) { builder.deleteCharAt(builder.length() - 1); } return builder.toString(); } @Override public boolean equals(Object obj) { if (!(obj instanceof AbstractList<?>)) { return false; } AbstractList<?> s = (AbstractList<?>) obj; if (s.size() != this.size()) { return false; } for (int i = 0; i < list.length; i++) { if (this.getItem(i) != s.getItem(i)) { if (this.getItem(i)!=null&&!this.getItem(i).equals(s.getItem(i))) { return false; }else if(s.getItem(i)!=null&&!s.getItem(i).equals(this.getItem(i))){ return false; } } } return true; } @Override public int hashCode() { if (hashCode == 0) { int hash = 7; for (int i = 0; i < list.length; i++) { hash = 53 * hash + (this.list[i] != null ? this.list[i].hashCode() : 0); } hashCode = hash; } return hashCode; } }