package adql.query; /* * This file is part of ADQLLibrary. * * ADQLLibrary is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ADQLLibrary 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ADQLLibrary. If not, see <http://www.gnu.org/licenses/>. * * Copyright 2012-2015 - UDS/Centre de DonnĂ©es astronomiques de Strasbourg (CDS), * Astronomisches Rechen Institut (ARI) */ import java.util.Iterator; import java.util.Vector; /** * <p>Represents a list of ADQL items.</p> * * <p>Since it is a list, it is possible to add, remove, modify and iterate on a such object.</p> * * @author Grégory Mantelet (CDS;ARI) * @version 1.4 (06/2015) * * @see ClauseADQL * @see ClauseConstraints * @see adql.query.operand.Operation * @see adql.query.operand.Concatenation */ public abstract class ADQLList< T extends ADQLObject > implements ADQLObject, Iterable<T> { /** Label of the list. */ private final String name; /** List of ADQL items. */ private final Vector<T> list = new Vector<T>(); /** Position inside an ADQL query string. * @since 1.4 */ private TextPosition position = null; /** * Builds an ADQLList with only its name. This name will always prefix the list. * * @param name Prefix/Name of this list. */ protected ADQLList(String name){ if (name != null){ name = name.trim(); if (name.length() == 0) name = null; } this.name = name; } /** * <p>Builds an ADQLList by copying the given one.</p> * <p><i><u>Note:</u> It is a deep copy.</i></p> * * @param toCopy The ADQLList to copy. * @throws Exception If there is an error during the copy. */ @SuppressWarnings("unchecked") protected ADQLList(ADQLList<T> toCopy) throws Exception{ this(toCopy.getName()); for(T obj : toCopy) add((T)obj.getCopy()); position = (toCopy.position != null) ? new TextPosition(toCopy.position) : null; } /** * Adds the given item (if not <i>null</i>) at the end of this clause. * * @param item The ADQL item to add to this clause. * @return <i>true</i> if the given item has been successfully added, <i>false</i> otherwise. * @throws NullPointerException If the given item is <i>null</i>. */ public boolean add(T item) throws NullPointerException{ if (item == null) throw new NullPointerException("It is impossible to add NULL items to an ADQL clause !"); else{ if (list.add(item)){ position = null; return true; }else return false; } } /** * Adds the given item (if not <i>null</i>) at the given position into this clause. * * @param index Position at which the given item must be added. * @param item ADQL item to add to this clause. * @throws NullPointerException If the given item is <i>null</i>. * @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()). */ public void add(int index, T item) throws NullPointerException, ArrayIndexOutOfBoundsException{ if (item != null){ list.add(index, item); position = null; }else throw new NullPointerException("It is impossible to add NULL items to an ADQL clause !"); } /** * Replaces the specified ADQL item by the given one. * * @param index Position of the item to replace. * @param item Replacer of the specified ADQL item. * @return The replaced ADQL item. * @throws NullPointerException If the given item is <i>null</i>. * @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()). */ public T set(int index, T item) throws NullPointerException, ArrayIndexOutOfBoundsException{ if (item != null){ T removed = list.set(index, item); position = null; return removed; }else throw new NullPointerException("It is impossible to replace an ADQL item by a NULL item into an ADQL clause !"); } /** * Gets the specified ADQL item. * * @param index Index of the ADQL item to retrieve. * @return The corresponding ADQL item. * @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()). */ public T get(int index) throws ArrayIndexOutOfBoundsException{ return list.get(index); } /** * Removes the specified ADQL item. * * @param index Index of the ADQL item to remove. * @return The removed ADQL item. * @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()). */ public T remove(int index) throws ArrayIndexOutOfBoundsException{ T removed = list.remove(index); if (removed != null) position = null; return removed; } /** * Clears this clause. */ public void clear(){ list.clear(); position = null; } /** * Gets the length of this clause. * * @return The number of ADQL items contained into this clause. */ public int size(){ return list.size(); } /** * Tells whether this clause contains at least one ADQL item. * * @return <i>true</i> if this clause is empty, <i>false</i> otherwise. */ public boolean isEmpty(){ return list.isEmpty(); } @Override public String getName(){ return name; } @Override public final TextPosition getPosition(){ return position; } /** * Sets the position at which this {@link ADQLList} has been found in the original ADQL query string. * * @param position Position of this {@link ADQLList}. * @since 1.4 */ public final void setPosition(final TextPosition position){ this.position = position; } @Override public String toADQL(){ StringBuffer adql = new StringBuffer((getName() == null) ? "" : (getName() + " ")); for(int i = 0; i < size(); i++){ if (i > 0) adql.append(" " + getSeparator(i) + " "); adql.append(get(i).toADQL()); } return adql.toString(); } @Override public Iterator<T> iterator(){ return list.iterator(); } @Override public ADQLIterator adqlIterator(){ return new ADQLListIterator(this); } /** * Gets the list of all possible separators for this {@link ADQLList}. * * @return Possible separators. */ public abstract String[] getPossibleSeparators(); /** * Gets the separator between the list items index-1 and index. * * @param index Index of the right list item. * @return The corresponding separator. * @throws ArrayIndexOutOfBoundsException If the index is less or equal than 0, or is greater or equal than {@link ADQLList#size() size()}. */ public abstract String getSeparator(int index) throws ArrayIndexOutOfBoundsException; @Override public abstract ADQLObject getCopy() throws Exception; /** * Lets iterating on all ADQL objects of the given {@link ADQLList}. * * @author Grégory Mantelet (CDS) * @version 06/2011 */ public static class ADQLListIterator implements ADQLIterator { protected final ADQLList<ADQLObject> list; protected int index = -1; protected boolean removed = false; @SuppressWarnings("unchecked") public ADQLListIterator(ADQLList<? extends ADQLObject> lst){ list = (ADQLList<ADQLObject>)lst; } @Override public boolean hasNext(){ return index + 1 < list.size(); } @Override public ADQLObject next(){ removed = false; return list.get(++index); } @Override public void replace(ADQLObject replacer) throws UnsupportedOperationException, IllegalStateException{ if (index <= -1) throw new IllegalStateException("replace(ADQLObject) impossible: next() has not yet been called !"); if (removed) throw new IllegalStateException("The remove() has already been called !"); if (replacer == null) remove(); else list.set(index, replacer); } @Override public void remove(){ if (index <= -1) throw new IllegalStateException("remove() impossible: next() has not yet been called !"); if (removed) throw new IllegalStateException("The remove() has already been called !"); list.remove(index--); removed = true; } } }