001/* PrintServiceLookup.java --
002   Copyright (C) 2004, 2006 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.print;
040
041import gnu.classpath.ServiceFactory;
042import gnu.javax.print.CupsPrintServiceLookup;
043
044import java.util.ArrayList;
045import java.util.Arrays;
046import java.util.HashSet;
047import java.util.Iterator;
048
049import javax.print.attribute.AttributeSet;
050
051
052/**
053 * <code>PrintServiceLookup</code> implementations provide a way to lookup 
054 * print services based on different constraints.
055 * <p>
056 * Implementations are located and loaded automatically through the SPI JAR 
057 * file specification. Therefore implementation classes must provide a default 
058 * constructor for instantiation. Furthermore, applications are able to 
059 * register further instances directly at runtime.
060 * </p><p>
061 * If an SecurityManager is installed implementors should call 
062 * <code>checkPrintJobAccess()</code> to disable access for untrusted code. 
063 * This check is to be made in every lookup service implementation for 
064 * flexibility. Print services registered by applications through 
065 * <code>registerService(PrintService)</code> are suppressed in the 
066 * lookup results if a security manager is installed and disallows access. 
067 * </p>
068 * 
069 * @author Michael Koch (konqueror@gmx.de)
070 * @author Wolfgang Baer (WBaer@gmx.de)
071 */
072public abstract class PrintServiceLookup
073{
074  
075  private static final CupsPrintServiceLookup systemProvider;
076  private static final HashSet printServices;
077  private static final HashSet printServiceLookups;
078  
079  static
080  {
081    systemProvider = new CupsPrintServiceLookup();
082    
083    printServices = new HashSet();
084    printServiceLookups = new HashSet();
085    
086    // check for service providers
087    Iterator it = ServiceFactory.lookupProviders(PrintServiceLookup.class);
088    
089    while (it.hasNext())
090      printServiceLookups.add(it.next());    
091  }  
092  
093  /**
094   * Constructs a <code>PrintServiceLookup</code> object.
095   */
096  public PrintServiceLookup()
097  {
098    // nothing to do here 
099  }
100  
101  /**
102   * Explicitly registers the provided print service lookup implementation.
103   * <p>
104   * The registration will silently fail (returning <code>false</code>) if
105   * the lookup service is already registered or the registration somehow
106   * else fails.
107   * </p>
108   *
109   * @param sp the print service lookup implementation to register. 
110   * @return <code>true</code> if registered, <code>false</code> otherwise.
111   */
112  public static boolean registerServiceProvider(PrintServiceLookup sp)
113  {  
114    return printServiceLookups.add(sp);
115  }
116  
117  /**
118   * Explicitly registers the provided print service instance.
119   * <p>
120   * The registration will silently fail (returning <code>false</code>) if
121   * the print service instance is already registered or the registration 
122   * somehow else fails.
123   * </p>
124   * @param service the single print service to register. 
125   * @return <code>true</code> if registered, <code>false</code> otherwise.
126   */
127  public static boolean registerService(PrintService service)
128  {
129    if (service instanceof StreamPrintService)
130      return false;
131
132    // security
133    try
134      {
135        SecurityManager sm = System.getSecurityManager();
136        if (sm != null)
137          sm.checkPrintJobAccess();
138
139        return printServices.add(service);
140      }
141    catch (SecurityException se)
142      {
143        return false;
144      }
145  }
146  
147  /**
148   * Searches print services capable of printing in the given document flavor
149   * which supports the specified printing attributes.
150   * 
151   * @param flavor the document flavor to support. If <code>null</code> this 
152   * constraint is ignored during lookup.
153   * @param attributes the printing attributes to support. If 
154   * <code>null</code> this constraint is ignored during lookup.
155   * @return The resulting available print services, or an array of length 0 
156   * if none is found. 
157   */
158  public static final PrintService[] lookupPrintServices(DocFlavor flavor,
159    AttributeSet attributes)
160  {   
161    ArrayList result = new ArrayList();
162    
163    PrintService[] services = 
164      systemProvider.getPrintServices(flavor, attributes);    
165    result.addAll(Arrays.asList(services));
166             
167    for (Iterator it = printServiceLookups.iterator(); it.hasNext(); )
168      {
169        PrintServiceLookup lookup = (PrintServiceLookup) it.next();
170        services = lookup.getPrintServices(flavor, attributes);   
171        result.addAll(Arrays.asList(services));
172      }
173    
174    for (Iterator it = printServices.iterator(); it.hasNext(); )
175      {
176        PrintService service = (PrintService) it.next();
177        if (systemProvider.checkPrintService(flavor, attributes, service)) 
178          result.add(service);
179      }
180    
181    return (PrintService[]) result.toArray(new PrintService[result.size()]);
182  }
183  
184  /**
185   * Searches print services capable of multi document printing in all of the 
186   * given document flavors and supporting the specified printing attributes.
187   * 
188   * @param flavors the document flavors to support. If <code>null</code> this 
189   * constraint is ignored during lookup.
190   * @param attributes the printing attributes to support. If 
191   * <code>null</code> this constraint is ignored during lookup.
192   * @return The resulting available multi document print services, or an 
193   * array of length 0 if none is found. 
194   */
195  public static final MultiDocPrintService[] lookupMultiDocPrintServices(
196    DocFlavor[] flavors, AttributeSet attributes)
197  {
198    ArrayList result = new ArrayList();
199    
200    MultiDocPrintService[] services = 
201      systemProvider.getMultiDocPrintServices(flavors, attributes);    
202    result.addAll(Arrays.asList(services));
203             
204    for (Iterator it = printServiceLookups.iterator(); it.hasNext(); )
205      {
206        PrintServiceLookup lookup = (PrintServiceLookup) it.next();
207        services = lookup.getMultiDocPrintServices(flavors, attributes);   
208        result.addAll(Arrays.asList(services));
209      }
210    
211    for (Iterator it = printServices.iterator(); it.hasNext(); )
212      {
213        PrintService service = (PrintService) it.next();
214        if (systemProvider.checkMultiDocPrintService(flavors, attributes, service))   
215          result.add(service);
216      }
217    
218    return (MultiDocPrintService[]) result.toArray(
219      new MultiDocPrintService[result.size()]);
220  }
221
222
223  /**
224   * Searches the default print service in the current environment.
225   * <p>
226   * If multiple lookup services are registered and each has a default
227   * print service the result is not specified. Usually the default 
228   * print service of the native platform lookup service is returned.
229   * </p><p>
230   * The GNU classpath implementation will return the CUPS default
231   * printing service as the default print service, if available.
232   * </p><p>
233   * The default print service may be overriden by users through
234   * the property <code>javax.print.defaultPrinter</code>. A service 
235   * specified must be found to be returned as the default.
236   * </p>
237   *  
238   * @return The default print service, or <code>null</code> if none found.
239   */
240  public static final PrintService lookupDefaultPrintService()
241  {
242    // TODO Find out what the property controls and use it
243    // String defaultPrinter = System.getProperty("javax.print.defaultPrinter");
244       
245    // first test for platform specified default services
246    PrintService service = systemProvider.getDefaultPrintService();
247    
248    if (service != null) 
249      return service;
250          
251    // none available by systemDefaultProvider
252    // search in other registered ones and take first      
253    for (Iterator it = printServiceLookups.iterator(); it.hasNext(); )
254      {
255        service = ((PrintServiceLookup) it.next()).getDefaultPrintService();
256        if (service != null)
257          return service;
258      }
259
260    return null;
261  }
262  
263  /**
264   * Not to be called directly by applications.
265   * 
266   * @return The default lookup service of the implementing lookup service or
267   * <code>null</code> if there is no default one.
268   */
269  public abstract PrintService getDefaultPrintService();
270
271  /**
272   * Not to be called directly by applications.
273   * 
274   * @param flavors the document flavors which have to be supported.
275   * @param attributes the attributes which have to be supported.
276   * 
277   * @return The multidoc print services of the implementing lookup service
278   * for the given parameters, or an array of length 0 if none is available.
279   */
280  public abstract MultiDocPrintService[] 
281    getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes);
282
283  /**
284   * Not to be called directly by applications.
285   * 
286   * @return All known print services of the implementing lookup service
287   * regardless of supported features, or an array of length 0 if none is 
288   * available.
289   */
290  public abstract PrintService[] getPrintServices();
291
292  /**
293   * Not to be called directly by applications.
294   * 
295   * @param flavor the document flavor which has to be supported.
296   * @param attributes the attributes which have to be supported.
297   * 
298   * @return The print services of the implementing lookup service
299   * for the given parameters, or an array of length 0 if none is available.
300   */
301  public abstract PrintService[] 
302    getPrintServices(DocFlavor flavor, AttributeSet attributes);
303}