001    /*
002     * $RCSfile: CatalogQuery.java,v $ 
003     *
004     * Created on August 2, 2002, 2:47 PM
005     *
006     * This file is part of the STAR Scheduler.
007     * Copyright (c) 2002-2006 STAR Collaboration - Brookhaven National Laboratory
008     *
009     * STAR Scheduler is free software; you can redistribute it and/or modify
010     * it under the terms of the GNU General Public License as published by
011     * the Free Software Foundation; either version 2 of the License, or
012     * (at your option) any later version.
013     *
014     * STAR Scheduler is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017     * GNU General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with STAR Scheduler; if not, write to the Free Software
021     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
022     */
023    package gov.bnl.star.offline.scheduler;
024    
025    import java.net.URI;
026    import java.util.*;
027    
028    import java.util.logging.Level;
029    import org.apache.log4j.Logger;
030    
031    
032    /** Encapsulate a query to the file catalog. This class is a wrapper around a
033     * URI that describes a file catalog query. The syntax of the URI is:
034     * <p>
035     * catalog:catalogName?query
036     * <p>
037     * catalogName is the name that identifies the catalog that should resolve the
038     * query. If can be directly a machine name, or a more abstract name that can
039     * be resolved to a specific machine at a later time.
040     * <p>
041     * query is the actual query to pass to the catalog. The syntax of the query
042     * is the one defined by the perl interface.
043     * <p>
044     * Different counting methods can be used. By counting methods, we mean the method
045     * used by the query resolver to decide how many and which records to return. Right
046     * now, two methods are supported:
047     * <p>
048     * START-LIMIT, which maps directly to the SQL START LIMIT definition. One can
049     * think the result returned as a view on the total result. Basically, only the
050     * records between start and start+limit are returned. By executing the same
051     * query with a different start, one can view all the result a chunk at a time.
052     * <p>
053     * NFILES, which returns a given number of files (that is of records) in no
054     * particular order. The query resolver is allowed to return whatever files
055     * it decides. This allows the query resolver to perform optimizations.
056     *
057     * @author  Gabriele Carcassi
058     * @version $Revision: 1.28 $ $Date: 2006/11/21 00:41:32 $
059     */
060    public class CatalogQuery implements java.io.Serializable{
061        static private Logger log = Logger.getLogger(CatalogQuery.class.getName());
062        private static final int DEFAULT_N_FILES = 100;
063        private static final String COUNTING_ERROR_MESSAGE = "Can't mix start/limit with nFiles";
064    
065        /** No method for determine how long the result should be was specified. */
066        public static final int NO_COUNTING = 0;
067    
068        /** The method to specify how many records to return is the SQL START and
069         * LIMIT model. */
070        public static final int START_LIMIT_COUNTING = 1;
071    
072        /** The method to specify how many records to return is by returning
073         * the specified number of valid records. Any records in any order can be
074         * returned. */
075        public static final int NFILES_COUNTING = 2;
076        private String uri;
077        private String host;
078        private String query;
079        private String preferStorage;
080        private Integer limit;
081        private Integer start;
082        private boolean singleCopy;
083        private Integer nFiles;
084        
085        
086    
087        
088        private int eventsReturned = 0; 
089        public int getEventsReturned(){ return eventsReturned; }
090        public void setEventsReturned(int eventsReturned){ this.eventsReturned = eventsReturned; } 
091        public void addToEventsReturned(int eventsReturned){ this.eventsReturned += eventsReturned; }
092        
093        private int filesReturned = 0;
094        public int getFilesReturned(){ return filesReturned; }
095        public void setFilesReturned(int filesReturned){ this.filesReturned = filesReturned; }
096        public void filesReturned(){ this.filesReturned ++; }        
097                
098        
099        
100    
101        /** Holds value of property attributes. */
102        private List attributes;
103        
104        /** Creates a query to the file catalog. The query is specified by a URI in this
105         * form: <CODE>catalog:catalogName?query</CODE>
106         * <p>
107         * <CODE>catalogName</CODE> defines which catalog to look. For example,
108         * star.bnl.gov specifies the STAR catalog.
109         * <p>
110         * <CODE>query</CODE> is the query that will be used to search for the entry. The
111         * exact syntax is specified by the catalog itself. For STAR, it
112         * is a series of comma separated assignments between keywords and values.
113         * @param uri specifies the full uri: ex. <CODE>catalog:star.bnl.gov:collision=AuAu200,storage=local</CODE>
114         */
115        public CatalogQuery(String uri) {
116            try {
117                this.uri = uri;
118                parseUri();
119    
120                return;
121            } catch (Exception e) {
122                log.fatal("Couldn't parse catalog query", e);
123            }
124    
125            throw new RuntimeException("The catalog query " + uri +
126                " is malformed");
127        }
128    
129        /** Creates a copy of a given query. The new query has the same URI and
130         * optional parameters, except the counting method, which is not set.
131         * @param query the query to be copied
132         */
133        public CatalogQuery(CatalogQuery query) {
134            uri = query.uri;
135            parseUri();
136            singleCopy = query.singleCopy;
137        }
138        
139        /*Not used*/
140        public CatalogQuery(){}
141    
142        private void parseUri() {
143            String schemeDependant = uri.substring(uri.indexOf(':')+1);
144            host = schemeDependant.substring(0, schemeDependant.indexOf('?'));
145            query = schemeDependant.substring(schemeDependant.indexOf('?') + 1);
146        }
147    
148        /** Returns the catalog to which the query should be sent.
149         * <p>
150         * This method is provided for
151         * forward compatibility and is not actually used
152         * @return the name of a machine
153         */
154        public String getCatalogName() {
155            return host;
156        }
157    
158        /** Returns the query to be passed to the file catalog.
159         * @return the query as specified by the file catalog.
160         */
161        public String getQuery() {
162            return query;
163        }
164    
165    
166        /** Returns the number of records this query should return.
167         * @return number of files the query will return
168         */
169        public Integer getLimit() {
170            return this.limit;
171        }
172    
173        /** Sets the number of records this query should return.
174         * @param limit number of files returned by the query
175         */
176        public void setLimit(Integer limit) {
177            
178            if (limit == null) {
179                this.limit = null;
180            }
181    
182            if ((getCountingType() != NO_COUNTING) &&
183                    (getCountingType() != START_LIMIT_COUNTING)) {
184                throw new RuntimeException(COUNTING_ERROR_MESSAGE);
185            }
186            
187            this.limit = limit;
188        }
189    
190        /** Returns the first element to be returned. In conjuction with limit you can
191         * scroll all the list.
192         * @return row of the first element to be returned
193         */
194        public Integer getStart() {
195            return this.start;
196        }
197    
198        /** Sets the first element to be returned. In conjuction with limit you can
199         * scroll all the list.
200         * @param start row of the first element to be returned
201         */
202        public void setStart(Integer start) {
203            if (start == null) {
204                this.start = null;
205            }
206    
207            if ((getCountingType() != NO_COUNTING) &&
208                    (getCountingType() != START_LIMIT_COUNTING)) {
209                throw new RuntimeException(COUNTING_ERROR_MESSAGE);
210            }
211    
212            this.start = start;
213        }
214    
215        /** Tells whether single copy or multiple copies for the same file should be
216         * returned.
217         * @return true if the query should return only one copy for each file in the catalog
218         */
219        public boolean isSingleCopy() {
220            return this.singleCopy;
221        }
222    
223        /** Tells which copy is preferred in case more than one copy for the same
224         * file is found.
225         * @return a String representing a storage (es. "local", "NFS", ... )
226         */
227        public String getPreferStorage() {
228            if (preferStorage == null) {
229                if (getNFiles().intValue() <= DEFAULT_N_FILES) return "NFS";
230                else return "local";
231            }
232            return this.preferStorage;
233        }
234    
235        /** Sets which copy is preferred in case of more than one copy for the same
236         * file is found.
237         * @param preferStorage a String representing a storage (es. "local", "NFS", ... )
238         */
239        public void setPreferStorage(String preferStorage) {
240            this.preferStorage = preferStorage;
241        }
242    
243        /** Sets whether single copy or multiple copies for the same file should be
244         * returned.
245         * @param singleCopy true if the query should return only one copy for each file in the catalog
246         */
247        public void setSingleCopy(boolean singleCopy) {
248            this.singleCopy = singleCopy;
249        }
250    
251        /** Returns the number of files the query should return. The files returned
252         * by the query if this counting method is used.
253         * @return the number of files returned by the query, or null if this
254         * counting method is not used
255         *
256         */
257        public Integer getNFiles() {
258                
259            if (getCountingType() == NO_COUNTING) {
260                return new Integer(DEFAULT_N_FILES);
261            }
262    
263            return this.nFiles;
264        }
265    
266        /** Sets the number of files the query should return. Files are returned in
267         * no particular order.
268         * @param nFiles the number of files to be returned by the query.
269         *
270         */
271        public void setNFiles(Integer nFiles) {
272    
273            if (nFiles == null) {
274                this.nFiles = null;
275            }
276    
277            if ((getCountingType() != NO_COUNTING) &&
278                    (getCountingType() != NFILES_COUNTING)) {
279                throw new RuntimeException(COUNTING_ERROR_MESSAGE);
280            }
281    
282            this.nFiles = nFiles;
283        }
284    
285        /** Returns the counting method used to decide how many records the query
286         * should return.
287         * @return NO_COUNTING, START_LIMIT_COUNTING or NFILES_COUNTING depending on the counting
288         * method defined on the query
289         */
290        public int getCountingType() {
291            if (nFiles != null) {
292                return NFILES_COUNTING;
293            }
294    
295            if ((limit != null) || (start != null)) {
296                return START_LIMIT_COUNTING;
297            }
298    
299            return NO_COUNTING;
300        }
301        
302        /** Getter for property attributes.
303         * @return Value of property attributes.
304         *
305         */
306        public List getAttributes() {
307            return this.attributes;
308        }
309        
310        /** Setter for property attributes.
311         * @param attributes New value of property attributes.
312         *
313         */
314        public void setAttributes(List attributes) {
315            this.attributes = attributes;
316        }
317        
318        
319        
320    }