You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/10/09 07:33:21 UTC

svn commit: r454289 [14/22] - in /incubator/harmony/enhanced/classlib/trunk/modules/H-1609: ./ modules/ modules/applet/ modules/applet/src/ modules/applet/src/main/ modules/applet/src/main/java/ modules/applet/src/main/java/java/ modules/applet/src/mai...

Added: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/awt/PSPrinterJob.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/awt/PSPrinterJob.java?view=auto&rev=454289
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/awt/PSPrinterJob.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/awt/PSPrinterJob.java Sun Oct  8 22:33:09 2006
@@ -0,0 +1,619 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/** 
+ * @author Aleksei V. Ivaschenko 
+ * @version $Revision: 1.3 $ 
+ */ 
+
+package org.apache.harmony.x.print.awt;
+
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.HeadlessException;
+import java.awt.KeyboardFocusManager;
+import java.awt.Rectangle;
+import java.awt.Window;
+import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
+import java.awt.print.Paper;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import java.io.PrintStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Locale;
+
+import javax.print.Doc;
+import javax.print.DocFlavor;
+import javax.print.DocPrintJob;
+import javax.print.PrintException;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.print.ServiceUI;
+import javax.print.SimpleDoc;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.print.attribute.Size2DSyntax;
+import javax.print.attribute.standard.Copies;
+import javax.print.attribute.standard.JobName;
+import javax.print.attribute.standard.Media;
+import javax.print.attribute.standard.MediaPrintableArea;
+import javax.print.attribute.standard.MediaSize;
+import javax.print.attribute.standard.MediaSizeName;
+import javax.print.attribute.standard.OrientationRequested;
+import javax.print.attribute.standard.RequestingUserName;
+import javax.swing.JOptionPane;
+
+import org.apache.harmony.x.print.ServiceUIDialog;
+import org.apache.harmony.x.print.attributes.MediaMargins;
+
+
+public class PSPrinterJob extends PrinterJob {
+
+    private Printable psPrintable;
+    private Pageable psDocument;
+    private PageFormat psFormat;
+    private PrintStream stream;
+    
+    PrintRequestAttributeSet attrs;             // Job attributes
+    private PrintService service = null;        // Job print service
+    
+    static String os = null;                    // OS type
+  
+    static {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                os = System.getProperty("os.name");
+                if (os.startsWith("Windows")) {
+                    System.loadLibrary("print");
+                }
+                return null;
+            }
+        });
+    }
+       
+    public PSPrinterJob() {
+        super();
+        attrs = new HashPrintRequestAttributeSet();
+        service = PrintServiceLookup.lookupDefaultPrintService();
+        /* Probably need to add default attributes to attrs here */
+    }
+
+    public void setPrintable(Printable painter) {
+        psPrintable = painter;
+    }
+
+    /*
+     * @see java.awt.print.PrinterJob#setPrintable(Printable, PageFormat)
+     */
+    public void setPrintable(Printable painter, PageFormat format) {
+        psPrintable = painter;
+        psFormat = format;
+    }
+
+    /*
+     * @see java.awt.print.PrinterJob#setPageable(Pageable)
+     */
+    public void setPageable(Pageable document) throws NullPointerException {       
+        if (document == null){
+            throw new NullPointerException("Pageable argument is null");
+        }        
+        psDocument = document; 
+    }
+
+    /*
+     * @see java.awt.print.PrinterJob#print()
+     */
+    public void print() throws PrinterException {
+        Doc doc = null;
+        if (psPrintable != null) {
+            Pageable pageable = new Pageable() {
+                public int getNumberOfPages() {
+                    return UNKNOWN_NUMBER_OF_PAGES;
+                }
+                public PageFormat getPageFormat(int pageIndex)
+                        throws IndexOutOfBoundsException {
+                    return (psFormat != null) ? psFormat : defaultPage();
+                }
+                public Printable getPrintable(int pageIndex)
+                        throws IndexOutOfBoundsException {
+                    return psPrintable;
+                }
+            };
+            
+            doc = new SimpleDoc(pageable,
+                    DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
+        } else if (psDocument != null) {
+            doc = new SimpleDoc(psDocument,
+                    DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
+        } else {
+            throw new PrinterException("Neither Printable nor Pageable were " +
+                    "specified.");
+        }
+        
+        PrintService pService = service;
+        if (pService == null) {
+            pService = PrintServiceLookup.lookupDefaultPrintService();
+        }
+        
+        try {
+            DocPrintJob job = pService.createPrintJob();
+            job.print(doc, attrs);
+        } catch (PrintException pe) {
+            throw new PrinterException(pe.getMessage());
+        }
+    }
+    
+    /*
+     * @see java.awt.print.PrinterJob#print(PrintRequestAttributeSet)
+     */
+    public void print(PrintRequestAttributeSet attributes)
+            throws PrinterException {
+        attrs = attributes;
+        print();
+    }
+        
+    public PrintService getPrintService() {
+        return service;
+    }
+
+    public void setPrintService(PrintService printservice) 
+            throws PrinterException {
+        if (printservice.isDocFlavorSupported(
+                DocFlavor.SERVICE_FORMATTED.PRINTABLE) &&
+            printservice.isDocFlavorSupported(
+                DocFlavor.SERVICE_FORMATTED.PAGEABLE)) {
+            service = printservice;
+        } else {
+            throw new PrinterException("PrintService doesn't support " +
+                    "SERVICE_FORMATTED doc flavors.");
+        }
+    }
+
+    public void setJobName(String jobName) {
+        attrs.add(new JobName(jobName, Locale.getDefault()));
+    }
+
+    public void setCopies(int copies) {
+        attrs.add(new Copies(copies));
+    }
+
+    public int getCopies() {
+        return attrs.containsKey(Copies.class) 
+               ? ((Copies) (attrs.get(Copies.class))).getValue()
+               : 1; 
+    }
+
+    public String getUserName() {
+        return attrs.containsKey(RequestingUserName.class) 
+               ? ((RequestingUserName)(attrs.get(RequestingUserName.class))).
+                        getValue()
+               : null;
+    }
+
+    public String getJobName() {       
+        return attrs.containsKey(JobName.class)  
+               ? ((JobName)(attrs.get(JobName.class))).getValue()
+               : null;        
+    }
+
+    /*
+     * This method shows Windows native print dialog on Windows and 
+     * javax.print.ServiceUI standard print dialog on Linux. We suppose that on
+     * Linux this dialog should contain the list of native print services only,
+     * however corresponding native agent function is not realized yet.
+     * 
+     * Throws HeadlessException if Graphics Environment is headless.
+    */
+    public boolean printDialog() throws HeadlessException {
+        if (GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        }
+
+        if (os.startsWith("Windows")) {         /* Windows OS */
+            
+            /* call Windows native dialog */
+            String res = getPrinter(service.getName(), getCopies());
+            
+            if (res != null) {
+                try {
+                    setPrintService(findPrintService(res));
+                    return true;
+                } catch(PrinterException e) {
+                    JOptionPane.showMessageDialog(KeyboardFocusManager
+                         .getCurrentKeyboardFocusManager().getActiveWindow(),
+                         "Can not set selected printer!", 
+                         "Incorrect service",
+                         JOptionPane.ERROR_MESSAGE);
+                }
+            }
+            return false;
+        } 
+        /* Linux OS */
+        /*
+         * TODO: Need to create new native agent function which returns
+         * a list of native printers. Need to call javax.print.ServiceUI
+         * print dialog with this native printers list instead of all 
+         * registered print services list as it is realized here! 
+         */
+        printDialog(attrs);
+        return false;        
+    }
+
+    /*
+     * Calls cross-platforms print dialog with all registered print services
+     * (this function just calls ServiceUI.printDialog(...) method with 
+     * corresponding parameters).
+     * 
+     * Parameters:
+     *      attrs - attributes for the dialog
+     * 
+     * Throws:
+     *      NullPointerException - if attrs is null
+     *      HeadlessException - if Graphics Environment is headless
+     */
+    public boolean printDialog(PrintRequestAttributeSet dialogAttrs)
+            throws HeadlessException {
+
+        if (dialogAttrs == null) {
+            throw new NullPointerException();
+        } else if (GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        }
+
+        /* Combine this PrinterJob attrs attribute set and printerAttrs set
+           and resolve MediaPrintableArea/MediaMargins conflict if it is 
+           needed */
+        PrintRequestAttributeSet sum = 
+                updateMediaAndMarginsIfNeeded(dialogAttrs);
+
+        Rectangle screen = GraphicsEnvironment.getLocalGraphicsEnvironment().
+                getDefaultScreenDevice().getDefaultConfiguration().getBounds();
+
+        /* call cross-platform print dialog */
+        PrintService newSrv = ServiceUI.printDialog(
+                null, 
+                screen.width / 3, 
+                screen.height / 3, 
+                lookupServicesForDialog(), 
+                service,
+                DocFlavor.SERVICE_FORMATTED.PRINTABLE, 
+                sum);
+
+        if (newSrv!=null) {
+            /* Set selected print service and update attrs attribute set 
+               if user clicked "Print" button */
+            try {
+                setPrintService(newSrv);
+                this.attrs.clear();
+                this.attrs.addAll(sum);
+                return true;
+            } catch (PrinterException e) {
+                System.out.println(e);
+                return false;
+            }
+        }
+        return false;   /* "Cancel button was pressed */
+    }
+
+    /*
+     * This method calls standard page dialog that allows PageFormat 
+     * modification.
+     * Parameters:
+     *      page - PageFormat for modification
+     * Returns:
+     *      original page if the dialog is cancelled or print service for the
+     *      job is not set
+     *      new PageFormat object from the dialog if the user click "Print"
+     *      button
+     * Throws HeadlessException if Graphics Environment is headless. 
+    */
+    public PageFormat pageDialog(PageFormat page) 
+            throws HeadlessException {
+        if (getPrintService() == null) {
+            return page;
+        } 
+
+        /* get attribute set which combines this job attribute set and
+           attributes for the given page PageFormat */
+        HashPrintRequestAttributeSet myattrs = getAttrsForPageFormat(page);
+        return pageDialog(myattrs);
+    }
+
+    /*
+     * This method calls standard page dialog with the given attribute set
+     * Parameters:
+     *      attrs - attribute set for the dialog
+     * Returns:
+     *      original page if the dialog is cancelled or print service for the
+     *      job is not set
+     *      new PageFormat object from the dialog if the user click "Print"
+     *      button
+     * Throws:
+     *      HeadlessException if Graphics Environment is headless.
+     *      NullPointerException if attrs is null
+    */
+    public PageFormat pageDialog(PrintRequestAttributeSet arg_attrs)
+            throws HeadlessException {
+
+        if (GraphicsEnvironment.isHeadless()) {
+            throw new HeadlessException();
+        } else if (arg_attrs == null) {
+            throw new NullPointerException();
+        } else if (getPrintService() == null) {
+            JOptionPane.showMessageDialog(KeyboardFocusManager
+                    .getCurrentKeyboardFocusManager().getActiveWindow(),
+                    "Print service is not set for the PrinterJob!", "Error!",
+                    JOptionPane.ERROR_MESSAGE);
+            return null;
+        }
+
+        Window wnd = KeyboardFocusManager.getCurrentKeyboardFocusManager()
+                .getActiveWindow();
+        Window owner = (((wnd instanceof Dialog)||(wnd instanceof Frame)) 
+                ? wnd : new Frame());
+
+        /* Combine this PrinterJob this.attrs attribute set and attrs set
+            and resolve MediaPrintableArea/MediaMargins conflict if it is
+            needed */
+        PrintRequestAttributeSet sum = updateMediaAndMarginsIfNeeded(arg_attrs);
+
+        Rectangle screen = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                .getDefaultScreenDevice().getDefaultConfiguration().getBounds();
+
+        /* create and show the page dialog */
+        ServiceUIDialog dialog = new ServiceUIDialog(null, 
+                                                     screen.width/3,
+                                                     screen.height/3,
+                                                     getPrintService(),
+                                                     sum,
+                                                     owner);
+        dialog.show();
+
+        if (owner != wnd) {
+            owner.dispose();
+        }
+
+        /* update this.attrs attribute set and result page format to return */
+        if (dialog.getResult() == ServiceUIDialog.APPROVE_PRINT) {
+            PrintRequestAttributeSet newattrs = dialog.getAttributes();
+
+            if (!newattrs.containsKey(Media.class)) {
+                this.attrs.remove(Media.class);
+            }
+            if (!newattrs.containsKey(OrientationRequested.class)) {
+                this.attrs.remove(OrientationRequested.class);
+            }
+            if (!newattrs.containsKey(MediaPrintableArea.class)) {
+                this.attrs.remove(MediaPrintableArea.class);
+            }
+            if (!newattrs.containsKey(MediaMargins.class)) {
+                this.attrs.remove(MediaMargins.class);
+            }
+            this.attrs.addAll(newattrs);
+            return getPageFormatForAttrs(newattrs);
+        } 
+        
+        return null;
+        
+    }
+
+    /* 
+     * Returns this printer job's attribute set
+     */
+    public PrintRequestAttributeSet getAttributes() {
+        return attrs;
+    }
+
+    /*
+     * Native method which calls Windows java native dialog.
+     * This method add/update Copies attribute into the attr attribute set
+     * and set new selected printer if user clicked OK.
+     * It does not change any other PrinterJob attributes now.
+     * TODO: wtite new Windows native agent function which save dialog DEVMODE 
+     * structure and returns correct attribute set for it. 
+     */
+    native String getPrinter(String defaultPrinter, int copies);
+
+    public PageFormat defaultPage(PageFormat page) {
+        attrs.addAll(getAttrsForPageFormat(page));
+        return getPageFormatForAttrs(attrs);
+    }
+
+//  ---------------------------------------------------------------
+
+    /*
+     * Returns PrintRequestAttributeSet which corresponds to given page
+     * PageFormat. We always adds MediaMArgins (not MediaPrintableArea)
+     * attribute for the result attribute set.
+     */
+    protected HashPrintRequestAttributeSet 
+            getAttrsForPageFormat(PageFormat page) {
+
+        HashPrintRequestAttributeSet lattrs=new HashPrintRequestAttributeSet();
+
+        /* Add Orientation attribute */
+        switch (page.getOrientation()) {
+            case PageFormat.LANDSCAPE:
+                lattrs.add(OrientationRequested.LANDSCAPE);
+                break;
+            case PageFormat.PORTRAIT:
+                lattrs.add(OrientationRequested.PORTRAIT);
+                break;
+            case PageFormat.REVERSE_LANDSCAPE:
+                lattrs.add(OrientationRequested.REVERSE_LANDSCAPE);
+                break;
+        }
+
+        /* Add Media attribute */
+        MediaSizeName media = MediaSize.findMedia(
+                (float) (page.getWidth() / 72.0),
+                (float) (page.getHeight() / 72.0), 
+                Size2DSyntax.INCH);
+        if (media != null) {
+            lattrs.add(media);
+        }
+
+        /* Add MediaMargins attribute */
+        lattrs.add(new MediaMargins((float) (page.getImageableX() / 72.0), 
+                (float) (page.getImageableY() / 72.0), 
+                (float) ((page.getWidth() - page.getImageableX() -
+                        page.getImageableWidth()) / 72.0),
+                (float) ((page.getHeight() - page.getImageableHeight() -
+                        page.getImageableY()) / 72.0), 
+                MediaMargins.INCH));
+
+        return lattrs;
+    }
+
+    /*
+     * Returns PageFormat object which corresponds to the given newattrs 
+     * attribute set.
+     */
+    protected PageFormat getPageFormatForAttrs(
+            PrintRequestAttributeSet newattrs) {
+        
+        PageFormat pf = new PageFormat();
+        
+        if (newattrs.containsKey(OrientationRequested.class)) {
+            OrientationRequested or = (OrientationRequested)
+                    newattrs.get(OrientationRequested.class);
+            pf.setOrientation(or.equals(OrientationRequested.LANDSCAPE)  
+                    ? PageFormat.LANDSCAPE
+                    : (or.equals(OrientationRequested.REVERSE_LANDSCAPE)  
+                            ? PageFormat.REVERSE_LANDSCAPE 
+                            : PageFormat.PORTRAIT));
+        }
+
+        Paper paper = new Paper();
+        MediaSize size = MediaSize.getMediaSizeForName(
+                newattrs.containsKey(Media.class) 
+                        && (newattrs.get(Media.class).getClass().
+                                isAssignableFrom(MediaSizeName.class))
+                ? (MediaSizeName)newattrs.get(Media.class) 
+                : MediaSizeName.ISO_A4);
+        paper.setSize(size.getX(Size2DSyntax.INCH) * 72.0, 
+                      size.getY(Size2DSyntax.INCH) * 72.0);
+
+
+        MediaMargins mm;
+        if (newattrs.containsKey(MediaMargins.class)) {
+            mm = (MediaMargins) newattrs.get(MediaMargins.class);
+        } else if(newattrs.containsKey(MediaPrintableArea.class)) {
+            mm = new MediaMargins(size, 
+                 (MediaPrintableArea) attrs.get(MediaPrintableArea.class));
+        } else {
+            mm = new MediaMargins(25.4F, 25.4F, 25.4F, 25.4F, MediaMargins.MM);
+        }
+        paper.setImageableArea(mm.getX1(MediaMargins.INCH) * 72.0, 
+                mm.getY1(MediaMargins.INCH) * 72.0, 
+                (size.getX(Size2DSyntax.INCH) - mm.getX1(MediaMargins.INCH) -
+                mm.getX2(MediaMargins.INCH)) * 72.0,
+                (size.getY(Size2DSyntax.INCH) - mm.getY1(MediaMargins.INCH) -
+                mm.getY2(MediaMargins.INCH)) * 72.0 );
+        pf.setPaper(paper);
+        return pf;
+    }
+
+    /* 
+     * Find PrintService with the given name 
+    */
+    protected PrintService findPrintService(String name) {
+        PrintService srvs [] = 
+                PrintServiceLookup.lookupPrintServices(null, null);
+        if (srvs != null) {
+            for (int i = 0; i < srvs.length; i++) {
+                if (srvs[i].getName().equals(name)) {
+                    return srvs[i];
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * This method returns all registered PrintServices list if this list
+     * contains this printer job's print service.
+     * If this list does not contain this job's print service, this function
+     * returns new print services list which contains all registered services
+     * plus this jib's service. 
+     */
+    protected PrintService[] lookupServicesForDialog() {
+        PrintService [] services = lookupPrintServices();
+        if (services != null) {
+            for (int i = 0; i < services.length; i++) {
+                if (services[i].equals(service)) {
+                    return services;
+                }
+            }
+            PrintService [] ret = new PrintService [services.length + 1];
+            for (int i = 0; i < services.length; i++) {
+                ret[i] = services[i];
+            }
+            ret[services.length] = service;
+            return ret;
+        }
+        
+        return new PrintService [] {service};
+        
+    }
+
+    /* 
+     * This method adds newAttrs attributes to this.attrs attribute set. If
+     * newAttrs contains MediaMargins or MediaPrintableAttribute, result 
+     * attribute set must not contain MediaPrintableArea or MediaMargins from 
+     * this.attrs attribute set because of the possible conflict.
+     */
+    protected PrintRequestAttributeSet updateMediaAndMarginsIfNeeded(
+            PrintRequestAttributeSet newAttrs) {
+
+        /* create copy of this.attrs*/
+        PrintRequestAttributeSet sum = 
+                new HashPrintRequestAttributeSet(this.attrs);
+
+        /* remove MediaMargins and MediaPrintableArea attributes from the copy
+           of job attributes if newAttrs contains  MediaMargins or 
+           PrintableArea */
+        if (newAttrs.containsKey(MediaPrintableArea.class)
+                    || attrs.containsKey(MediaMargins.class)) {
+            sum.remove(MediaPrintableArea.class);
+            sum.remove(MediaMargins.class);
+        }
+
+        sum.addAll(newAttrs);
+        return sum;
+    }
+    
+    /*
+     * TODO: Need to implement this methods 
+     */
+    public void cancel() {
+        /* */
+    }
+
+    public boolean isCancelled() {
+        return false;
+    }
+
+    public PageFormat validatePage(PageFormat page) {
+        return null;
+    }
+
+    
+
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/awt/PSPrinterJob.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSClient.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSClient.java?view=auto&rev=454289
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSClient.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSClient.java Sun Oct  8 22:33:09 2006
@@ -0,0 +1,980 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/** 
+ * @author Igor A. Pyankov 
+ * @version $Revision: 1.5 $ 
+ */ 
+
+package org.apache.harmony.x.print.cups;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilePermission;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Locale;
+
+import javax.print.Doc;
+import javax.print.DocFlavor;
+import javax.print.PrintException;
+import javax.print.attribute.Attribute;
+import javax.print.attribute.AttributeSet;
+import javax.print.attribute.AttributeSetUtilities;
+import javax.print.attribute.DocAttributeSet;
+import javax.print.attribute.HashAttributeSet;
+import javax.print.attribute.HashPrintServiceAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.print.attribute.PrintServiceAttribute;
+import javax.print.attribute.PrintServiceAttributeSet;
+import javax.print.attribute.standard.Destination;
+import javax.print.attribute.standard.DocumentName;
+import javax.print.attribute.standard.JobName;
+import javax.print.attribute.standard.Media;
+import javax.print.attribute.standard.RequestingUserName;
+
+import org.apache.harmony.x.print.PrintClient;
+import org.apache.harmony.x.print.ipp.IppAttribute;
+import org.apache.harmony.x.print.ipp.IppAttributeGroup;
+import org.apache.harmony.x.print.ipp.IppAttributeGroupSet;
+import org.apache.harmony.x.print.ipp.IppDocument;
+import org.apache.harmony.x.print.ipp.IppPrinter;
+import org.apache.harmony.x.print.ipp.IppResponse;
+import org.apache.harmony.x.print.ipp.util.Ipp2Java;
+
+
+/*
+ * CUPSClient is a print client based on CUPS protocol.
+ * (see Common UNIX Printing System, http://www.cups.org/)
+ * 
+ * The CUPS itself extends IPP protocol
+ * (see Internet Printing Protocol, http://www.pwg.org/ipp/index.html)
+ * 
+ * So, this class supports as CUPS as IPP print servers 
+ * 
+ * The class uses special IPP package org.apache.harmony.x.print.ipp for
+ * ipp/cups specific operations.
+ * 
+ * CUPSClient implements PrintClient interface, therefore
+ * see PrintClient.java for more information.
+ * 
+ * 
+ */
+class CUPSClient implements PrintClient {
+    // for debug
+    private static int verbose = 0;
+
+    private IppPrinter printer;
+    private URI printeruri;
+    private PrintServiceAttributeSet attributeset;
+    private DocFlavor[] supportedFlavors = null;
+
+    CUPSClient(String name) throws PrintException {
+        try {
+            this.printeruri = new URI(name);
+            this.printer = new IppPrinter(printeruri);
+            this.attributeset = new HashPrintServiceAttributeSet();
+        } catch (Exception e) {
+            throw new PrintException(e);
+        }
+    }
+
+    /* 
+     * SPECIAL - supportedFlavors is global for perfomance 
+     * but it can be set local for dynamic
+     * 
+     * @org.apache.harmony.x.print.PrintClient#getSupportedDocFlavors()
+     */
+    public DocFlavor[] getSupportedDocFlavors() {
+        if (supportedFlavors == null) {
+            ArrayList df = new ArrayList();
+
+            try {
+                String[] mimetypes = new String[ALLDOCFLAVORS.length];
+                String[] validmimes;
+
+                for (int i = 0, ii = ALLDOCFLAVORS.length; i < ii; i++) {
+                    mimetypes[i] = ALLDOCFLAVORS[i].getMimeType();
+                }
+                validmimes = printer.requestGetSupportedMimeTypes(mimetypes);
+                for (int i = 0, ii = ALLDOCFLAVORS.length; i < ii; i++) {
+                    if (validmimes[i] != null) {
+                        if (validmimes[i].equals("application/ps")) {
+                            /*
+                             * SPECIAL processing application/ps
+                             */
+                            df.add(ipp2java(ALLDOCFLAVORS[i]));
+                        } else {
+                            df.add(ALLDOCFLAVORS[i]);
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                // IGNORE exception
+                e.printStackTrace();
+            }
+
+            supportedFlavors = (df.size() == 0 ? new DocFlavor[] { DocFlavor.INPUT_STREAM.AUTOSENSE }
+                    : (DocFlavor[]) df.toArray(new DocFlavor[0]));
+        }
+        return supportedFlavors;
+    }
+
+    /* 
+     * @see org.apache.harmony.x.print.PrintClient#getAttributes()
+     */
+    public PrintServiceAttributeSet getAttributes() {
+        synchronized (this) {
+            try {
+                IppResponse response;
+                IppAttributeGroup agroup;
+                IppAttribute attr;
+                Object[] attrx = new Object[0];
+
+                response = printer.requestPrinterDescriptionAttributes();
+                agroup = response
+                        .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+                if (agroup != null) {
+                    attributeset.clear();
+                    for (int i = 0, ii = agroup.size(); i < ii; i++) {
+                        attr = (IppAttribute) agroup.get(i);
+                        attrx = Ipp2Java.getJavaByIpp(attr);
+                        for (int j = 0, jj = attrx.length; j < jj; j++) {
+                            if (attrx[j] instanceof PrintServiceAttribute) {
+                                attributeset.add((Attribute) attrx[j]);
+                            }
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                // IGNORE exception
+                e.printStackTrace();
+            }
+        }
+
+        return AttributeSetUtilities.unmodifiableView(attributeset);
+    }
+
+    /*
+     * @see org.apache.harmony.x.PrintClient#getSupportedAttributeCategories()
+     */
+    public Class[] getSupportedAttributeCategories() {
+        ArrayList clazz = new ArrayList();
+
+        try {
+            IppResponse response = printer.requestPrinterAttributes();
+            IppAttributeGroup agroup = response
+                    .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+            String aname;
+            Class claz;
+            IppAttribute attr;
+
+            if (agroup != null) {
+                for (int i = 0, ii = agroup.size(); i < ii; i++) {
+                    attr = (IppAttribute) agroup.get(i);
+                    aname = new String(attr.getName());
+                    if (aname.indexOf("-supported") > 0) {
+                        claz = Ipp2Java.getClassByIppAttributeName(aname
+                                .substring(0, aname.indexOf("-supported")));
+                        if (claz != null) {
+                            clazz.add(claz);
+                        }
+                    }
+                }
+            }
+            // SPECIAL attributes processing
+            getSupportedAttributeCategoriesEx(clazz);
+        } catch (Exception e) {
+            // IGNORE exception
+            // e.printStackTrace();
+        }
+        return (clazz.size() == 0 ? new Class[0] : (Class[]) clazz
+                .toArray(new Class[0]));
+    }
+
+    private void getSupportedAttributeCategoriesEx(ArrayList clazz) {
+        if (!clazz.contains(Destination.class)) {
+            clazz.add(Destination.class);
+        }
+        if (!clazz.contains(RequestingUserName.class)) {
+            clazz.add(RequestingUserName.class);
+        }
+        if (!clazz.contains(JobName.class)) {
+            clazz.add(JobName.class);
+        }
+        if (!clazz.contains(DocumentName.class)) {
+            clazz.add(DocumentName.class);
+        }
+    }
+
+    /*
+     * @see org.apache.harmony.x.print.PrintClient#getDefaultAttributeValue(java.lang.Class)
+     */
+    public Object getDefaultAttributeValue(Class category) {
+        if (category == null) {
+            throw new NullPointerException("Argument is null");
+        }
+        if (!(Attribute.class.isAssignableFrom(category))) {
+            throw new IllegalArgumentException(
+                    "Argument must implement interface Attribute");
+        }
+
+        Object defval[] = null;
+
+        // SPECIAL attributes processing
+        defval = getDefaultAttributeValueEx(category);
+        if (defval != null) {
+            if (defval.length == 0) {
+                return null;
+            }
+            return defval[0];
+        }
+
+        if (Media.class.isAssignableFrom(category)) {
+            category = Media.class;
+        }
+        try {
+            IppResponse response = printer.requestPrinterAttributes();
+            IppAttributeGroup agroup = response
+                    .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+            IppAttribute attr;
+            String aname;
+            int andex;
+
+            if (agroup != null) {
+                aname = Ipp2Java.getIppAttributeNameByClass(category);
+                if (aname != null) {
+                    if (aname.endsWith("-supported")) {
+                        aname = aname.substring(0, aname.indexOf("-supported"));
+                    }
+                    if (aname.endsWith("-default")) {
+                        aname = aname.substring(0, aname.indexOf("-default"));
+                    }
+                    andex = agroup.findAttribute(aname + "-default");
+                    if (andex >= 0) {
+                        attr = (IppAttribute) agroup.get(andex);
+                        defval = Ipp2Java.getJavaByIpp(attr);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            // IGNORE exception
+            e.printStackTrace();
+        }
+
+        return (defval != null && defval.length > 0 ? defval[0] : null);
+    }
+
+    /*
+     * If attribute was processed - return Object[1]
+     * Else - return null
+     */
+    private Object[] getDefaultAttributeValueEx(Class category) {
+        if (Destination.class.isAssignableFrom(category)) {
+            return new Object[0];
+        } else if (RequestingUserName.class.isAssignableFrom(category)) {
+            return new Object[] { new RequestingUserName(
+                    (String) AccessController
+                            .doPrivileged(new PrivilegedAction() {
+                                public Object run() {
+                                    return System.getProperty("user.name");
+                                }
+                            }), Locale.US) };
+        } else if (JobName.class.isAssignableFrom(category)) {
+            return new Object[] { new JobName("Java print job", Locale.US) };
+        } else if (DocumentName.class.isAssignableFrom(category)) {
+            return new Object[] { new DocumentName("Java print document",
+                    Locale.US) };
+        }
+        return null;
+    }
+
+    /*
+     * @see org.apache.harmony.x.print.PrintClient#isAttributeValueSupported(javax.print.attribute.Attribute, 
+     *          javax.print.DocFlavor, javax.print.attribute.AttributeSet)
+     */
+    public boolean isAttributeValueSupported(Attribute attribute,
+            DocFlavor flavor, AttributeSet attributes) {
+
+        // verify parameters
+        if (attribute == null) {
+            throw new NullPointerException("Argument is null");
+        }
+        if (flavor != null && !isDocFlavorSupported(flavor)) {
+            throw new IllegalArgumentException("DocFlavor '" + flavor
+                    + "' is not supported by the print service");
+        }
+
+        // SPECIAL attributes processing
+        boolean[] supportedEx = isAttributeValueSupportedEx(attribute, flavor);
+        if (supportedEx != null) {
+            return supportedEx[0];
+        }
+
+        boolean supported = false;
+        try {
+            IppDocument document;
+            IppResponse response;
+            IppAttributeGroup agroup;
+            IppAttributeGroupSet agroupset;
+            Attribute[] attrs;
+            String mime = null;
+            String aname;
+
+            aname = Ipp2Java.getIppAttributeNameByClass(attribute.getClass(),
+                    -1);
+            if (aname == null) {
+                return false;
+            }
+            if (flavor == null) {
+                mime = "application/octet-stream";
+            } else {
+                mime = java2ipp(flavor).getMimeType();
+            }
+            if (attributes == null || attributes.isEmpty()) {
+                document = new IppDocument("Qwerty", mime, "");
+                agroupset = new IppAttributeGroupSet();
+                agroupset.setAttribute(aname, Ipp2Java.getIppByJava(attribute));
+                response = printer.requestValidateJob(aname, document,
+                        agroupset);
+                agroup = response
+                        .getGroup(IppAttributeGroup.TAG_UNSUPPORTED_ATTRIBUTES);
+
+                if (agroup == null) {
+                    supported = true;
+                } else if (agroup != null && agroup.findAttribute(aname) < 0) {
+                    supported = true;
+                }
+            } else {
+                document = new IppDocument("Qwerty", mime, "");
+                agroupset = new IppAttributeGroupSet();
+                agroupset.setAttribute(aname, Ipp2Java.getIppByJava(attribute));
+                attrs = attributes.toArray();
+                for (int i = 0, ii = attrs.length; i < ii; i++) {
+                    agroupset.setAttribute(Ipp2Java.getIppAttributeNameByClass(
+                            attrs[i].getClass(), -1), Ipp2Java
+                            .getIppByJava(attrs[i]));
+                }
+
+                response = printer.requestValidateJob(aname, document,
+                        agroupset);
+                agroup = response
+                        .getGroup(IppAttributeGroup.TAG_UNSUPPORTED_ATTRIBUTES);
+
+                if (agroup == null) {
+                    supported = true;
+                } else if (agroup != null && agroup.findAttribute(aname) < 0) {
+                    supported = true;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+
+        return supported;
+    }
+
+    /*
+     * If attribute was processed - return boolean[1]
+     * Else return null
+     */
+    private boolean[] isAttributeValueSupportedEx(Attribute avalue,
+            DocFlavor flavor) {
+        if (Destination.class.isAssignableFrom(avalue.getCategory())) {
+            String ms = (flavor != null ? flavor.getMediaSubtype() : "");
+            Class cls = (flavor != null ? flavor.getClass() : null);
+
+            if (ms.equalsIgnoreCase("gif") || ms.equalsIgnoreCase("jpeg")
+                    || ms.equalsIgnoreCase("png")
+                    || ms.equalsIgnoreCase("postscript") || flavor == null
+                    || cls == DocFlavor.SERVICE_FORMATTED.class) {
+                if (!canPrintToFile()) {
+                    return new boolean[] { false };
+                }
+
+                URI uri = ((Destination) avalue).getURI();
+                try {
+                    File file = new File(uri);
+
+                    if (file.isFile()) {
+                        if (file.canWrite()) {
+                            return new boolean[] { true };
+                        }
+                        return new boolean[] { false };
+                    }
+
+                    String path = file.getParent();
+                    File parent = new File(path);
+                    if (parent.isDirectory()) {
+                        if (parent.canWrite()) {
+                            return new boolean[] { true };
+                        }
+                        return new boolean[] { false };
+                    }
+                } catch (Exception e) {
+                    return new boolean[] { false };
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * @see org.apache.harmony.x.print.PrintClient#getSupportedAttributeValues(java.lang.Class, 
+     *          javax.print.DocFlavor, javax.print.attribute.AttributeSet)
+     */
+    public Object getSupportedAttributeValues(Class category, DocFlavor flavor,
+            AttributeSet attributes) {
+        if (category == null) {
+            throw new NullPointerException("Argument is null");
+        }
+        if (!(Attribute.class.isAssignableFrom(category))) {
+            throw new IllegalArgumentException(
+                    "Argument must implement interface Attribute");
+        }
+        if (flavor != null && !isDocFlavorSupported(flavor)) {
+            throw new IllegalArgumentException("DocFlavor '" + flavor
+                    + "' is not supported by the print service");
+        }
+
+        Object vals = null;
+
+        // SPECIAL attributes processing
+        vals = getSupportedAttributeValuesEx(category, flavor);
+        if (vals != null) {
+            if (((Object[]) vals).length == 0) {
+                return null;
+            }
+            return ((Object[]) vals)[0];
+        }
+
+        // General attributes
+        try {
+            String aname = Ipp2Java.getIppAttributeNameByClass(category, 0)
+                    + "-supported";
+            doVerbose(2,
+                    "CUPSClient.java: getSupportedAttributeValues(): ipp attribute: "
+                            + aname);
+            IppResponse response = printer.requestPrinterAttributes(aname,
+                    (flavor == null ? null : java2ipp(flavor).getMimeType()));
+            doVerbose(2,
+                    "CUPSClient.java: getSupportedAttributeValues(): response: "
+                            + response.toString());
+            IppAttributeGroup agroup = response
+                    .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+            doVerbose(1,
+                    "CUPSClient.java: getSupportedAttributeValues(): agroup: "
+                            + agroup.toString());
+            if (agroup != null) {
+                int aind = agroup.findAttribute(aname);
+                if (aind >= 0) {
+                    IppAttribute attr = (IppAttribute) agroup.get(aind);
+                    vals = Ipp2Java.getJavaByIpp(attr);
+                }
+            }
+            doVerbose(1, "CUPSClient.java: getSupportedAttributeValues(): 1");
+            // Make right type/value for return
+            if (vals != null && vals.getClass().isArray()) {
+                Object[] ara = (Object[]) vals;
+                if (ara.length == 1 && ara[0].getClass() != category) {
+                    vals = ara[0];
+                }
+            }
+            doVerbose(1, "CUPSClient.java: getSupportedAttributeValues(): 2");
+            if (vals != null && vals.getClass().isArray()) {
+                int asize = ((Object[]) vals).length;
+                if (asize > 0) {
+                    Class c = ((Object[]) vals)[0].getClass();
+                    /* SPECIAL case for Media* attributes
+                     * 
+                     * Special case for Media* attributes.
+                     * vals[] contains all type of Media classes
+                     * So, c must be Media type, not a[0] type 
+                     */
+                    if (Media.class.isAssignableFrom(c)) {
+                        c = Media.class;
+                    }
+                    doVerbose(1,
+                            "CUPSClient.java: getSupportedAttributeValues(): 3");
+                    Object[] a = (Object[]) Array.newInstance(c, asize);
+                    System.arraycopy(vals, 0, a, 0, a.length);
+
+                    vals = a;
+                } else {
+                    vals = null;
+                }
+            }
+            doVerbose(1, "CUPSClient.java: getSupportedAttributeValues(): 4");
+            if (vals != null && vals.getClass().isArray()) {
+                for (int i = 0, ii = ((Attribute[]) vals).length; i < ii; i++) {
+                    if (!isAttributeValueSupported(((Attribute[]) vals)[i],
+                            flavor, attributes)) {
+                        ((Attribute[]) vals)[i] = null;
+                    }
+                }
+                doVerbose(1,
+                        "CUPSClient.java: getSupportedAttributeValues(): 5");
+                int newvalslength = 0;
+                for (int i = 0, ii = ((Attribute[]) vals).length; i < ii; i++) {
+                    if (((Attribute[]) vals)[i] != null) {
+                        newvalslength++;
+                    }
+                }
+                doVerbose(1,
+                        "CUPSClient.java: getSupportedAttributeValues(): 6");
+                if (newvalslength != ((Attribute[]) vals).length) {
+                    Object[] newvals = new Object[newvalslength];
+                    for (int j = 0, i = 0, ii = ((Attribute[]) vals).length; i < ii; i++) {
+                        if (((Attribute[]) vals)[i] != null) {
+                            newvals[j++] = ((Attribute[]) vals)[i];
+                        }
+                    }
+
+                    vals = newvals;
+                }
+            } else if (vals != null) {
+                if (!isAttributeValueSupported((Attribute) vals, flavor,
+                        attributes)) {
+                    vals = null;
+                }
+            }
+            doVerbose(1, "CUPSClient.java: getSupportedAttributeValues(): 7");
+            return vals;
+        } catch (Exception e) {
+            // IGNORE exception
+            e.printStackTrace();
+        }
+        doVerbose(1, "CUPSClient.java: getSupportedAttributeValues(): 8");
+        return null;
+    } /*  
+     * If category processed - return non-null value
+     */
+
+    private Object[] getSupportedAttributeValuesEx(Class category,
+            DocFlavor flavor) {
+        if (Destination.class.isAssignableFrom(category)) {
+            String ms = flavor.getMediaSubtype();
+
+            if (ms.equalsIgnoreCase("gif") || ms.equalsIgnoreCase("jpeg")
+                    || ms.equalsIgnoreCase("png")
+                    || ms.equalsIgnoreCase("postscript")
+                    || flavor.getClass() == DocFlavor.SERVICE_FORMATTED.class) {
+                try {
+                    return new Object[] { new Destination(new URI(
+                            "file:///foo/bar")) };
+                } catch (URISyntaxException e) {
+                    // return empty array - values are not supported
+                    return new Object[0];
+                }
+            }
+        } else if (RequestingUserName.class.isAssignableFrom(category)) {
+            return new Object[] { new RequestingUserName("I.A.Muser", Locale.US) };
+        } else if (JobName.class.isAssignableFrom(category)) {
+            return new Object[] { new JobName("Foo print job", Locale.US) };
+        } else if (DocumentName.class.isAssignableFrom(category)) {
+            return new Object[] { new DocumentName("Foo document", Locale.US) };
+        }
+        return null;
+    }
+
+    /*
+     * @see org.apache.harmony.x.print.PrintClient#print(javax.print.Doc, 
+     *          javax.print.attribute.PrintRequestAttributeSet)
+     */
+    public void print(Doc doc, PrintRequestAttributeSet attributes)
+            throws PrintException {
+        synchronized (this) {
+            doVerbose(1, "Print " + doc.toString());
+            try {
+                DocFlavor df = doc.getDocFlavor();
+                if (!(df instanceof DocFlavor.INPUT_STREAM
+                        || df instanceof DocFlavor.BYTE_ARRAY
+                        || df instanceof DocFlavor.CHAR_ARRAY
+                        || df instanceof DocFlavor.STRING
+                        || df instanceof DocFlavor.READER || df instanceof DocFlavor.URL)) {
+                    throw new PrintException("Doc flavor "
+                            + df.getRepresentationClassName()
+                            + " is not supported yet");
+                }
+
+                HashAttributeSet as = new HashAttributeSet();
+                DocAttributeSet das;
+                das = doc.getAttributes();
+
+                // construct attributes
+                if (das != null) {
+                    as.addAll(das);
+                }
+                if (attributes != null) {
+                    as.addAll(attributes);
+                }
+                as.addAll(attributeset);
+
+                // print
+                if (as.containsKey(Destination.class)) {
+                    print2destination(doc, (Destination) as
+                            .get(Destination.class));
+                } else {
+                    printsimple(doc, as);
+                }
+            } catch (PrintException e) {
+                throw e;
+            } catch (Exception e) {
+                throw new PrintException(e);
+            }
+        }
+    }
+
+    /*
+     * printing to Destination
+     */
+    private void print2destination(Doc doc, Destination destination)
+            throws PrintException {
+
+        try {
+            DataOutputStream bw = new DataOutputStream(
+                    new BufferedOutputStream(new FileOutputStream(new File(
+                            destination.getURI()))));
+
+            if (doc != null) {
+                if (doc.getDocFlavor() instanceof DocFlavor.INPUT_STREAM) {
+                    InputStream stream = (InputStream) doc.getPrintData();
+                    byte[] buf = new byte[1024 * 8];
+                    int count = 0;
+
+                    while ((count = stream.read(buf, 0, buf.length)) != -1) {
+                        bw.write(buf, 0, count);
+                    }
+                    stream.close();
+                } else if (doc.getDocFlavor() instanceof DocFlavor.URL) {
+                    BufferedInputStream stream = new BufferedInputStream(
+                            ((URL) doc.getPrintData()).openStream());
+                    byte[] buf = new byte[1024 * 8];
+                    int count = 0;
+                    while ((count = stream.read(buf, 0, buf.length)) != -1) {
+                        if (count > 0) {
+                            bw.write(buf, 0, count);
+                        }
+                    }
+                    stream.close();
+                } else if (doc.getDocFlavor() instanceof DocFlavor.BYTE_ARRAY) {
+                    InputStream stream = new ByteArrayInputStream((byte[]) doc
+                            .getPrintData());
+                    byte[] buf = new byte[1024 * 8];
+                    int count = 0;
+
+                    while ((count = stream.read(buf, 0, buf.length)) != -1) {
+                        bw.write(buf, 0, count);
+                    }
+                    stream.close();
+                } else if (doc.getDocFlavor() instanceof DocFlavor.SERVICE_FORMATTED) {
+                    // TODO - print DocFlavor.SERVICE_FORMATTED
+                }
+            }
+
+            bw.flush();
+            bw.close();
+        } catch (Exception e) {
+            throw new PrintException(e);
+        }
+    }
+
+    /*
+     * request IppPrinter printer to print document
+     */
+    private void printsimple(Doc doc, HashAttributeSet as)
+            throws PrintException {
+        IppDocument document;
+        IppResponse response;
+        IppAttributeGroupSet agroupset;
+        Attribute[] attrs;
+        DocFlavor df = doc.getDocFlavor();
+        String docname = doc.toString();
+
+        try {
+            document = new IppDocument(docname, java2ipp(df).getMimeType(), doc
+                    .getPrintData());
+
+            agroupset = new IppAttributeGroupSet();
+            attrs = as.toArray();
+            for (int i = 0, ii = attrs.length; i < ii; i++) {
+                agroupset.setAttribute(Ipp2Java.getIppAttributeNameByClass(
+                        attrs[i].getClass(), -1), Ipp2Java
+                        .getIppByJava(attrs[i]));
+            }
+            document.setAgroups(agroupset);
+
+            doVerbose(1, "Validating print job...");
+            response = printer.requestValidateJob(docname, document, agroupset);
+            doVerbose(1, response.toString());
+            checkResponseIsZero(response, "IPP Validate Job: \n");
+            doVerbose(1, "Validate OK");
+
+            doVerbose(1, "Printing " + docname + "...");
+            response = printer.requestPrintJob(docname, document, agroupset);
+            doVerbose(1, response.toString());
+            checkResponseIsZero(response, "IPP Print Job: \n");
+            doVerbose(1, "Printing OK");
+        } catch (PrintException e) {
+            throw e;
+        } catch (Exception e) {
+            if (getVerbose() > 1) {
+                e.printStackTrace();
+            }
+            throw new PrintException(e);
+        }
+    }
+
+    /*
+     * just check that IppResponse is OK
+     */
+    private void checkResponseIsZero(IppResponse response, String prefix)
+            throws PrintException {
+        if (response.getStatusCode() != 0) {
+            String status = Integer.toHexString(response.getStatusCode());
+            String id = Integer.toHexString(response.getRequestId());
+
+            throw new PrintException(prefix
+                    + "\n================ IPP response id: 0x" + id
+                    + " =====================" + "\nresponse status code: 0x"
+                    + status + "\n" + response.toString()
+                    + "\n================ end IPP response 0x" + id
+                    + " =====================");
+        }
+    }
+
+    /*
+     * convert DocFlavor to DocFlavor ;-)
+     * 
+     * some printers support application/ps instead of application/postscript
+     * So:
+     * if mimetype==application/postscript 
+     *      && printer does not support mimetype application/postscript
+     *      && printer supports mimetype application/ps
+     * then 
+     *      we change mimetype of docflavor to application/ps
+     */
+    private DocFlavor java2ipp(DocFlavor pDocFlavor) {
+        DocFlavor ippDocFlavor = pDocFlavor;
+        String mime = pDocFlavor.getMimeType();
+
+        /*
+         * SPECIAL processing application/ps
+         */
+        if (mime.equals("application/postscript")) {
+            try {
+                IppDocument document = new IppDocument("Qwerty",
+                        "application/postscript", "");
+                IppResponse response = printer.requestValidateJob("Qwerty",
+                        document, null);
+                if (response.getStatusCode() != 0) {
+                    document = new IppDocument("Qwerty", "application/ps", "");
+                    response = printer.requestValidateJob("Qwerty", document,
+                            null);
+                    if (response.getStatusCode() == 0) {
+                        if (pDocFlavor instanceof DocFlavor.INPUT_STREAM) {
+                            ippDocFlavor = new DocFlavor.INPUT_STREAM(
+                                    "application/ps");
+                        } else if (ippDocFlavor instanceof DocFlavor.BYTE_ARRAY) {
+                            ippDocFlavor = new DocFlavor.BYTE_ARRAY(
+                                    "application/ps");
+                        } else if (ippDocFlavor instanceof DocFlavor.URL) {
+                            ippDocFlavor = new DocFlavor.URL("application/ps");
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return ippDocFlavor;
+    }
+
+    /*
+     * opposite to java2ipp() method
+     */
+    private DocFlavor ipp2java(DocFlavor ippDocFlavor) {
+        DocFlavor pDocFlavor = ippDocFlavor;
+        String mime = ippDocFlavor.getMimeType();
+
+        /*
+         * SPECIAL processing application/ps
+         */
+        if (mime.equals("application/ps")) {
+            if (ippDocFlavor instanceof DocFlavor.INPUT_STREAM) {
+                pDocFlavor = DocFlavor.INPUT_STREAM.POSTSCRIPT;
+            } else if (ippDocFlavor instanceof DocFlavor.BYTE_ARRAY) {
+                pDocFlavor = DocFlavor.BYTE_ARRAY.POSTSCRIPT;
+            } else if (ippDocFlavor instanceof DocFlavor.URL) {
+                pDocFlavor = DocFlavor.URL.POSTSCRIPT;
+            }
+        }
+
+        return pDocFlavor;
+    }
+
+    /*
+     * the method's name is saying all
+     */
+    private boolean isDocFlavorSupported(DocFlavor flavor) {
+        if (flavor == null) {
+            throw new NullPointerException("DocFlavor flavor is null");
+        }
+
+        DocFlavor clientFlavors[] = getSupportedDocFlavors();
+        for (int i = 0; i < clientFlavors.length; i++) {
+            if (clientFlavors[i].equals(flavor)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /*
+     * check permission to read/write to any file
+     */
+    private boolean canPrintToFile() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                sm.checkPermission(new FilePermission("<<ALL FILES>>",
+                        "read,write"));
+                return true;
+            } catch (SecurityException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * just list of all doc flavors from specification
+     * it is used in getSupportedDocFlavors() method
+     */
+    private static DocFlavor[] ALLDOCFLAVORS = { DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST,
+            DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_8,
+            DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16,
+            DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16BE,
+            DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16LE,
+            DocFlavor.BYTE_ARRAY.TEXT_PLAIN_US_ASCII,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_HOST,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_8,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16BE,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16LE,
+            DocFlavor.BYTE_ARRAY.TEXT_HTML_US_ASCII,
+            DocFlavor.BYTE_ARRAY.PDF,
+            DocFlavor.BYTE_ARRAY.POSTSCRIPT,
+            DocFlavor.BYTE_ARRAY.PCL,
+            DocFlavor.BYTE_ARRAY.GIF,
+            DocFlavor.BYTE_ARRAY.JPEG,
+            DocFlavor.BYTE_ARRAY.PNG,
+            DocFlavor.BYTE_ARRAY.AUTOSENSE,
+
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_8,
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16,
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16BE,
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16LE,
+            DocFlavor.INPUT_STREAM.TEXT_PLAIN_US_ASCII,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_HOST,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_8,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16BE,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16LE,
+            DocFlavor.INPUT_STREAM.TEXT_HTML_US_ASCII,
+            DocFlavor.INPUT_STREAM.PDF,
+            DocFlavor.INPUT_STREAM.POSTSCRIPT,
+            DocFlavor.INPUT_STREAM.PCL,
+            DocFlavor.INPUT_STREAM.GIF,
+            DocFlavor.INPUT_STREAM.JPEG,
+            DocFlavor.INPUT_STREAM.PNG,
+            DocFlavor.INPUT_STREAM.AUTOSENSE,
+
+            DocFlavor.URL.TEXT_PLAIN_HOST,
+            DocFlavor.URL.TEXT_PLAIN_UTF_8,
+            DocFlavor.URL.TEXT_PLAIN_UTF_16,
+            DocFlavor.URL.TEXT_PLAIN_UTF_16BE,
+            DocFlavor.URL.TEXT_PLAIN_UTF_16LE,
+            DocFlavor.URL.TEXT_PLAIN_US_ASCII,
+            DocFlavor.URL.TEXT_HTML_HOST,
+            DocFlavor.URL.TEXT_HTML_UTF_8,
+            DocFlavor.URL.TEXT_HTML_UTF_16,
+            DocFlavor.URL.TEXT_HTML_UTF_16BE,
+            DocFlavor.URL.TEXT_HTML_UTF_16LE,
+            DocFlavor.URL.TEXT_HTML_US_ASCII,
+            DocFlavor.URL.PDF,
+            DocFlavor.URL.POSTSCRIPT,
+            DocFlavor.URL.PCL,
+            DocFlavor.URL.GIF,
+            DocFlavor.URL.JPEG,
+            DocFlavor.URL.PNG,
+            DocFlavor.URL.AUTOSENSE,
+
+            DocFlavor.CHAR_ARRAY.TEXT_PLAIN,
+            DocFlavor.CHAR_ARRAY.TEXT_HTML,
+
+            DocFlavor.STRING.TEXT_PLAIN,
+            DocFlavor.STRING.TEXT_HTML,
+
+            DocFlavor.READER.TEXT_PLAIN,
+            DocFlavor.READER.TEXT_HTML,
+
+            DocFlavor.SERVICE_FORMATTED.RENDERABLE_IMAGE,
+            DocFlavor.SERVICE_FORMATTED.PRINTABLE,
+            DocFlavor.SERVICE_FORMATTED.PAGEABLE,
+
+            /*
+             * Some printers accept "application/ps" instead of "application/postscript"
+             * So, we have special processing for those DocFlavor
+             * See comments with phrase:
+             * SPECIAL processing application/ps   
+             */
+            new DocFlavor.INPUT_STREAM("application/ps"),
+            new DocFlavor.URL("application/ps"),
+            new DocFlavor.BYTE_ARRAY("application/ps") };
+
+    public static int getVerbose() {
+        return verbose;
+    }
+
+    public static void setVerbose(int newverbose) {
+        verbose = newverbose;
+        IppPrinter.setVerbose(verbose);
+    }
+
+    public static void doVerbose(String v) {
+        System.out.println(v);
+    }
+
+    public static void doVerbose(int level, String v) {
+        if (verbose >= level) {
+            System.out.println(v);
+        }
+    }
+
+}
\ No newline at end of file

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSClient.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSPrintServiceProvider.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSPrintServiceProvider.java?view=auto&rev=454289
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSPrintServiceProvider.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSPrintServiceProvider.java Sun Oct  8 22:33:09 2006
@@ -0,0 +1,552 @@
+/*
+ *  Copyright 2005 - 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/** 
+ * @author Igor A. Pyankov 
+ * @version $Revision: 1.3 $ 
+ */ 
+
+package org.apache.harmony.x.print.cups;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Vector;
+
+import javax.print.DocFlavor;
+import javax.print.MultiDocPrintService;
+import javax.print.PrintException;
+import javax.print.PrintService;
+import javax.print.PrintServiceLookup;
+import javax.print.attribute.AttributeSet;
+
+import org.apache.harmony.x.print.DefaultPrintService;
+import org.apache.harmony.x.print.ipp.IppAttribute;
+import org.apache.harmony.x.print.ipp.IppAttributeGroup;
+import org.apache.harmony.x.print.ipp.IppClient;
+import org.apache.harmony.x.print.ipp.IppOperation;
+import org.apache.harmony.x.print.ipp.IppPrinter;
+import org.apache.harmony.x.print.ipp.IppRequest;
+import org.apache.harmony.x.print.ipp.IppResponse;
+
+
+/*
+ * The class extends PrintServiceLookup and is intended for
+ * looking up CUPS/IPP printers
+ * 
+ * 1. The class allways looks printers on http://localhost:631
+ *    This URL is default URL for default installation of CUPS server
+ * 2. The class accepts two properties:
+ *      print.cups.servers - a list of CUPS servers
+ *      print.ipp.printers - a list of IPP printers 
+ *                           (note, that CUPS printer is IPP printer too) 
+ */
+public class CUPSPrintServiceProvider extends PrintServiceLookup {
+    private static String cupsdefault = "http://localhost:631";
+    private static ArrayList services = new ArrayList();
+    /*
+     * 0 - no
+     * 1 - more
+     * 2 - more and more
+     * ...
+     */
+    private static int verbose = 0;
+
+    static {
+        String verbose_property = (String) AccessController
+                .doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        return System.getProperty("print.cups.verbose");
+                    }
+                });
+        if (verbose_property != null) {
+            try {
+                Integer v = new Integer(verbose_property);
+                setVerbose(v.intValue());
+            } catch (NumberFormatException e) {
+                setVerbose(0);
+            }
+
+        }
+    }
+
+    public CUPSPrintServiceProvider() {
+        super();
+    }
+
+    /*
+     * The method returns array of URLs of CUPS servers
+     */
+    private static String[] getCUPSServersByProperty() {
+        ArrayList cupslist = new ArrayList();
+        cupslist.add(cupsdefault);
+
+        String cupspath = (String) AccessController
+                .doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        return System.getProperty("print.cups.servers");
+                    }
+                });
+        String pathsep = ",";
+        if (cupspath != null && !cupspath.equals("")) {
+            String[] cupss = cupspath.split(pathsep);
+            for (int i = 0, ii = cupss.length; i < ii; i++) {
+                if (!cupss[i].equals("")) {
+                    try {
+                        URI cupsuri = new URI(cupss[i]);
+                        cupslist.add(cupsuri.toString());
+                    } catch (URISyntaxException e) {
+                        if (verbose > 0) {
+                            System.err.println("CUPS url: " + cupss[i]);
+                            e.printStackTrace();
+                        } else {
+                            // IGNORE bad URI exception
+                        }
+                    }
+                }
+            }
+        }
+
+        return (String[]) cupslist.toArray(new String[0]);
+    }
+
+    /*
+     * The method returns array of URLs of IPP printers
+     */
+    private static String[] getIppPrintersByProperty() {
+        ArrayList ipplist = new ArrayList();
+
+        String ipppath = (String) AccessController
+                .doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        return System.getProperty("print.ipp.printers");
+                    }
+                });
+        String pathsep = ","; //System.getProperty("path.separator");
+        if (ipppath != null && !ipppath.equals("")) {
+            String[] ipps = ipppath.split(pathsep);
+            for (int i = 0, ii = ipps.length; i < ii; i++) {
+                if (!ipps[i].equals("")) {
+                    try {
+                        URI cupsuri = new URI(ipps[i]);
+                        ipplist.add(cupsuri.toString());
+                    } catch (URISyntaxException e) {
+                        if (verbose > 0) {
+                            System.err.println("IPP url: " + ipps[i]);
+                            e.printStackTrace();
+                        } else {
+                            // IGNORE bad URI exception
+                        }
+                    }
+                }
+            }
+        }
+
+        return (String[]) ipplist.toArray(new String[0]);
+    }
+
+    /*
+     * @see javax.print.PrintServiceLookup#getDefaultPrintService()
+     */
+    public PrintService getDefaultPrintService() {
+        synchronized (this) {
+            String defaultService = findDefaultPrintService();
+
+            if (defaultService != null) {
+                PrintService service = getServiceStored(defaultService,
+                        services);
+                if (service != null) {
+                    return service;
+                }
+
+                CUPSClient client;
+                try {
+                    client = new CUPSClient(defaultService);
+                    service = new DefaultPrintService(defaultService, client);
+                    services.add(service);
+                    return service;
+                } catch (PrintException e) {
+                    // just ignore
+                    e.printStackTrace();
+                }
+            }
+
+            if (services.size() == 0) {
+                getPrintServices();
+            }
+            if (services.size() > 0) {
+                return (PrintService) services.get(0);
+            }
+
+        }
+        return null;
+    }
+
+    /*
+     * @see javax.print.PrintServiceLookup#getPrintServices()
+     */
+    public PrintService[] getPrintServices() {
+        synchronized (this) {
+            String[] serviceNames = findPrintServices();
+            if (serviceNames == null || serviceNames.length == 0) {
+                services.clear();
+                return new PrintService[0];
+            }
+
+            ArrayList newServices = new ArrayList();
+            for (int i = 0; i < serviceNames.length; i++) {
+                PrintService service = getServiceStored(serviceNames[i],
+                        services);
+                if (service != null) {
+                    newServices.add(service);
+                } else if (getServiceStored(serviceNames[i], newServices) == null) {
+                    try {
+                        CUPSClient client = new CUPSClient(serviceNames[i]);
+
+                        service = new DefaultPrintService(serviceNames[i],
+                                client);
+                        newServices.add(service);
+                    } catch (PrintException e) {
+                        // just ignore
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+            services.clear();
+            services = newServices;
+            return (services.size() == 0) ? new PrintService[0]
+                    : (PrintService[]) services.toArray(new PrintService[0]);
+        }
+    }
+
+    /*
+     * find printers on particular CUPS server
+     */
+    private PrintService[] getCUPSPrintServices(String cups) {
+        synchronized (this) {
+            // just update static field 'services'
+            findPrintServices();
+
+            // next find services on server 'cups'
+            String[] serviceNames = (String[]) findCUPSPrintServices(cups)
+                    .toArray(new String[0]);
+            if (serviceNames == null || serviceNames.length == 0) {
+                return new PrintService[0];
+            }
+
+            // return only those are stored in field 'services'
+            ArrayList newServices = new ArrayList();
+            for (int i = 0; i < serviceNames.length; i++) {
+                PrintService service = getServiceStored(serviceNames[i],
+                        services);
+                if (service != null) {
+                    newServices.add(service);
+                }
+            }
+
+            return (newServices.size() == 0) ? new PrintService[0]
+                    : (PrintService[]) services.toArray(new PrintService[0]);
+        }
+    }
+
+    /*
+     * find printers on localhost only
+     */
+    public PrintService[] getPrintServicesOnLocalHost() {
+        return getCUPSPrintServices(cupsdefault);
+    }
+
+    /*
+     * find service which name is same as serviceName
+     */
+    private PrintService getServiceStored(String serviceName,
+            ArrayList servicesList) {
+        for (int i = 0; i < servicesList.size(); i++) {
+            PrintService service = (PrintService) servicesList.get(i);
+            if (service.getName().equals(serviceName)) {
+                return service;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * @see javax.print.PrintServiceLookup#getPrintServices(javax.print.DocFlavor
+     *      , javax.print.attribute.AttributeSet)
+     */
+    public PrintService[] getPrintServices(DocFlavor flavor,
+            AttributeSet attributes) {
+        PrintService[] cupsservices = getPrintServices();
+        if (flavor == null && attributes == null) {
+            return cupsservices;
+        }
+
+        ArrayList requestedServices = new ArrayList();
+        for (int i = 0; i < cupsservices.length; i++) {
+            try {
+                AttributeSet unsupportedSet = cupsservices[i]
+                        .getUnsupportedAttributes(flavor, attributes);
+                if (unsupportedSet == null) {
+                    requestedServices.add(cupsservices[i]);
+                }
+            } catch (IllegalArgumentException iae) {
+                // DocFlavor not supported by service, skiping.
+            }
+        }
+        return (requestedServices.size() == 0) ? new PrintService[0]
+                : (PrintService[]) requestedServices
+                        .toArray(new PrintService[0]);
+    }
+
+    /*
+     * @see javax.print.PrintServiceLookup#getMultiDocPrintServices(javax.print.DocFlavor[]
+     *      , javax.print.attribute.AttributeSet)
+     */
+    public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors,
+            AttributeSet attributes) {
+        // No multidoc print services available, yet.
+        return new MultiDocPrintService[0];
+    }
+
+    /*
+     * find all printers
+     */
+    private static String[] findPrintServices() {
+        ArrayList ippservices = new ArrayList();
+
+        /*
+         * First, find on localhost and servers from print.cups.servers property
+         * and add them to full list
+         */
+        String[] cupses = CUPSPrintServiceProvider.getCUPSServersByProperty();
+        for (int j = 0; j < cupses.length; j++) {
+            ippservices.addAll(findCUPSPrintServices(cupses[j]));
+        }
+
+        /*
+         * Then, check URLs from print.ipp.printers property and 
+         * if is valid ipp printer add them to full list
+         */
+        String[] ippp = CUPSPrintServiceProvider.getIppPrintersByProperty();
+        for (int j = 0; j < ippp.length; j++) {
+            try {
+                URI ippuri = new URI(ippp[j]);
+                IppPrinter printer = new IppPrinter(ippuri);
+                IppResponse response;
+
+                response = printer.requestPrinterAttributes(
+                        "printer-uri-supported", null);
+
+                Vector gg = response
+                        .getGroupVector(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+                if (gg != null) {
+                    for (int i = 0, ii = gg.size(); i < ii; i++) {
+                        IppAttributeGroup g = (IppAttributeGroup) gg.get(i);
+                        int ai = g.findAttribute("printer-uri-supported");
+
+                        if (ai >= 0) {
+                            IppAttribute a = (IppAttribute) g.get(ai);
+                            Vector v = a.getValue();
+                            if (v.size() > 0) {
+                                ippservices.add(new String((byte[]) v.get(0)));
+                            }
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                if (verbose > 0) {
+                    System.err.println("IPP url: " + ippp[j]);
+                    e.printStackTrace();
+                } else {
+                    // IGNORE - connection refused due to no server, etc.
+                }
+            }
+        }
+
+        // retun array of printers
+        return (String[]) ippservices.toArray(new String[0]);
+    }
+
+    /*
+     * find ipp printers on CUPS server 'cups'
+     */
+    public static ArrayList findCUPSPrintServices(String cups) {
+        ArrayList ippservices = new ArrayList();
+
+        URI cupsuri = null;
+        IppClient c = null;
+        IppRequest request;
+        IppResponse response;
+        IppAttributeGroup agroup;
+        Vector va = new Vector();
+
+        request = new IppRequest(1, 1, IppOperation.TAG_CUPS_GET_PRINTERS,
+                "utf-8", "en-us");
+        agroup = request.getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
+        va.add("printer-uri-supported".getBytes());
+        agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
+                "requested-attributes", va));
+
+        try {
+            cupsuri = new URI(cups);
+            c = new IppClient(cupsuri);
+
+            response = c.request(request.getBytes());
+
+            Vector gg = response
+                    .getGroupVector(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+            if (gg != null) {
+                for (int i = 0, ii = gg.size(); i < ii; i++) {
+                    IppAttributeGroup g = (IppAttributeGroup) gg.get(i);
+                    int ai = g.findAttribute("printer-uri-supported");
+
+                    if (ai >= 0) {
+                        IppAttribute a = (IppAttribute) g.get(ai);
+                        Vector v = a.getValue();
+                        if (v.size() > 0) {
+                            ippservices.add(new String((byte[]) v.get(0)));
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            if (verbose > 0) {
+                System.err.println("CUPS url: " + cups);
+                System.err.println("CUPS uri: " + cupsuri);
+                System.err.println("Ipp client: " + c);
+                System.err.println(request.toString());
+                e.printStackTrace();
+            } else {
+                // IGNORE - connection refused due to no server, etc.
+            }
+        }
+
+        return ippservices;
+    }
+
+    /*
+     * find default printer
+     * At first, try to find default printer on CUPS servers and return first found 
+     * If failed, return first found IPP printer
+     * If failed return null
+     */
+    private static String findDefaultPrintService() {
+        String serviceName = null;
+
+        String[] cupses = CUPSPrintServiceProvider.getCUPSServersByProperty();
+        for (int i = 0; i < cupses.length; i++) {
+            try {
+                URI cupsuri = new URI(cupses[i]);
+                IppClient c = new IppClient(cupsuri);
+                IppRequest request;
+                IppResponse response;
+                IppAttributeGroup agroup;
+                Vector va = new Vector();
+
+                request = new IppRequest(1, 1,
+                        IppOperation.TAG_CUPS_GET_DEFAULT, "utf-8", "en-us");
+                agroup = request
+                        .getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
+                va.add("printer-uri-supported".getBytes());
+                agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
+                        "requested-attributes", va));
+
+                response = c.request(request.getBytes());
+
+                IppAttributeGroup g = response
+                        .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+                if (g != null) {
+                    int ai = g.findAttribute("printer-uri-supported");
+
+                    if (ai >= 0) {
+                        IppAttribute a = (IppAttribute) g.get(ai);
+                        Vector v = a.getValue();
+                        if (v.size() > 0) {
+                            serviceName = new String((byte[]) v.get(0));
+                            break;
+                        }
+                    }
+                }
+            } catch (URISyntaxException e) {
+                //e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                //e.printStackTrace();
+            }
+        }
+        if (serviceName != null && !serviceName.equals("")) {
+            return serviceName;
+        }
+
+        String[] ippp = CUPSPrintServiceProvider.getIppPrintersByProperty();
+        for (int i = 0; i < ippp.length; i++) {
+            try {
+                URI ippuri = new URI(ippp[i]);
+                IppClient c = new IppClient(ippuri);
+                IppRequest request;
+                IppResponse response;
+                IppAttributeGroup agroup;
+                Vector va = new Vector();
+
+                request = new IppRequest(1, 1,
+                        IppOperation.GET_PRINTER_ATTRIBUTES, "utf-8", "en-us");
+                agroup = request
+                        .getGroup(IppAttributeGroup.TAG_OPERATION_ATTRIBUTES);
+                va.add("printer-uri-supported".getBytes());
+                agroup.add(new IppAttribute(IppAttribute.TAG_KEYWORD,
+                        "requested-attributes", va));
+
+                response = c.request(request.getBytes());
+
+                IppAttributeGroup g = response
+                        .getGroup(IppAttributeGroup.TAG_GET_PRINTER_ATTRIBUTES);
+                if (g != null) {
+                    int ai = g.findAttribute("printer-uri-supported");
+
+                    if (ai >= 0) {
+                        IppAttribute a = (IppAttribute) g.get(ai);
+                        Vector v = a.getValue();
+                        if (v.size() > 0) {
+                            serviceName = new String((byte[]) v.get(0));
+                            break;
+                        }
+                    }
+                }
+            } catch (URISyntaxException e) {
+                //e.printStackTrace();
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (Exception e) {
+                //e.printStackTrace();
+            }
+        }
+
+        return serviceName;
+    }
+
+    public static int isVerbose() {
+        return verbose;
+    }
+
+    public static void setVerbose(int newverbose) {
+        CUPSPrintServiceProvider.verbose = newverbose;
+        CUPSClient.setVerbose(newverbose);
+    }
+}
\ No newline at end of file

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/H-1609/modules/print/src/main/java/common/org/apache/harmony/x/print/cups/CUPSPrintServiceProvider.java
------------------------------------------------------------------------------
    svn:executable = *