Path: blob/master/src/java.desktop/unix/classes/sun/print/UnixPrintService.java
41152 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.print;2627import java.io.File;28import java.net.URI;29import java.net.URISyntaxException;30import java.util.ArrayList;31import java.util.Locale;3233import java.awt.GraphicsEnvironment;34import java.awt.Toolkit;35import javax.print.DocFlavor;36import javax.print.DocPrintJob;37import javax.print.PrintService;38import javax.print.ServiceUIFactory;39import javax.print.attribute.Attribute;40import javax.print.attribute.AttributeSet;41import javax.print.attribute.AttributeSetUtilities;42import javax.print.attribute.HashAttributeSet;43import javax.print.attribute.PrintServiceAttribute;44import javax.print.attribute.PrintServiceAttributeSet;45import javax.print.attribute.HashPrintServiceAttributeSet;46import javax.print.attribute.Size2DSyntax;47import javax.print.attribute.standard.PrinterName;48import javax.print.attribute.standard.PrinterIsAcceptingJobs;49import javax.print.attribute.standard.QueuedJobCount;50import javax.print.attribute.standard.JobName;51import javax.print.attribute.standard.JobSheets;52import javax.print.attribute.standard.RequestingUserName;53import javax.print.attribute.standard.Chromaticity;54import javax.print.attribute.standard.ColorSupported;55import javax.print.attribute.standard.Copies;56import javax.print.attribute.standard.CopiesSupported;57import javax.print.attribute.standard.Destination;58import javax.print.attribute.standard.DialogOwner;59import javax.print.attribute.standard.DialogTypeSelection;60import javax.print.attribute.standard.Fidelity;61import javax.print.attribute.standard.Media;62import javax.print.attribute.standard.MediaPrintableArea;63import javax.print.attribute.standard.MediaSize;64import javax.print.attribute.standard.MediaSizeName;65import javax.print.attribute.standard.OrientationRequested;66import javax.print.attribute.standard.PageRanges;67import javax.print.attribute.standard.PrinterState;68import javax.print.attribute.standard.PrinterStateReason;69import javax.print.attribute.standard.PrinterStateReasons;70import javax.print.attribute.standard.Severity;71import javax.print.attribute.standard.SheetCollate;72import javax.print.attribute.standard.Sides;73import javax.print.event.PrintServiceAttributeListener;747576@SuppressWarnings("removal")77public class UnixPrintService implements PrintService, AttributeUpdater,78SunPrinterJobService {7980/* define doc flavors for text types in the default encoding of81* this platform since we can always read those.82*/83private static String encoding = "ISO8859_1";84private static DocFlavor textByteFlavor;8586private static DocFlavor[] supportedDocFlavors = null;87private static final DocFlavor[] supportedDocFlavorsInit = {88DocFlavor.BYTE_ARRAY.POSTSCRIPT,89DocFlavor.INPUT_STREAM.POSTSCRIPT,90DocFlavor.URL.POSTSCRIPT,91DocFlavor.BYTE_ARRAY.GIF,92DocFlavor.INPUT_STREAM.GIF,93DocFlavor.URL.GIF,94DocFlavor.BYTE_ARRAY.JPEG,95DocFlavor.INPUT_STREAM.JPEG,96DocFlavor.URL.JPEG,97DocFlavor.BYTE_ARRAY.PNG,98DocFlavor.INPUT_STREAM.PNG,99DocFlavor.URL.PNG,100101DocFlavor.CHAR_ARRAY.TEXT_PLAIN,102DocFlavor.READER.TEXT_PLAIN,103DocFlavor.STRING.TEXT_PLAIN,104105DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_8,106DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16,107DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16BE,108DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16LE,109DocFlavor.BYTE_ARRAY.TEXT_PLAIN_US_ASCII,110111112DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_8,113DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16,114DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16BE,115DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16LE,116DocFlavor.INPUT_STREAM.TEXT_PLAIN_US_ASCII,117118119DocFlavor.URL.TEXT_PLAIN_UTF_8,120DocFlavor.URL.TEXT_PLAIN_UTF_16,121DocFlavor.URL.TEXT_PLAIN_UTF_16BE,122DocFlavor.URL.TEXT_PLAIN_UTF_16LE,123DocFlavor.URL.TEXT_PLAIN_US_ASCII,124125DocFlavor.SERVICE_FORMATTED.PAGEABLE,126DocFlavor.SERVICE_FORMATTED.PRINTABLE,127128DocFlavor.BYTE_ARRAY.AUTOSENSE,129DocFlavor.URL.AUTOSENSE,130DocFlavor.INPUT_STREAM.AUTOSENSE131};132133private static final DocFlavor[] supportedHostDocFlavors = {134DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST,135DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,136DocFlavor.URL.TEXT_PLAIN_HOST137};138139String[] lpcStatusCom = {140"",141"| grep -E '^[ 0-9a-zA-Z_-]*@' | awk '{print $2, $3}'"142};143144String[] lpcQueueCom = {145"",146"| grep -E '^[ 0-9a-zA-Z_-]*@' | awk '{print $4}'"147};148149static {150encoding = java.security.AccessController.doPrivileged(151new sun.security.action.GetPropertyAction("file.encoding"));152}153154/* let's try to support a few of these */155private static final Class<?>[] serviceAttrCats = {156PrinterName.class,157PrinterIsAcceptingJobs.class,158QueuedJobCount.class,159};160161/* it turns out to be inconvenient to store the other categories162* separately because many attributes are in multiple categories.163*/164private static final Class<?>[] otherAttrCats = {165Chromaticity.class,166Copies.class,167Destination.class,168Fidelity.class,169JobName.class,170JobSheets.class,171Media.class, /* have to support this somehow ... */172MediaPrintableArea.class,173OrientationRequested.class,174PageRanges.class,175RequestingUserName.class,176SheetCollate.class,177Sides.class,178};179180private static int MAXCOPIES = 1000;181182private static final MediaSizeName[] mediaSizes = {183MediaSizeName.NA_LETTER,184MediaSizeName.TABLOID,185MediaSizeName.LEDGER,186MediaSizeName.NA_LEGAL,187MediaSizeName.EXECUTIVE,188MediaSizeName.ISO_A3,189MediaSizeName.ISO_A4,190MediaSizeName.ISO_A5,191MediaSizeName.ISO_B4,192MediaSizeName.ISO_B5,193};194195private String printer;196private PrinterName name;197private boolean isInvalid;198199private transient PrintServiceAttributeSet lastSet;200private transient ServiceNotifier notifier = null;201202UnixPrintService(String name) {203if (name == null) {204throw new IllegalArgumentException("null printer name");205}206printer = name;207isInvalid = false;208}209210public void invalidateService() {211isInvalid = true;212}213214public String getName() {215return printer;216}217218private PrinterName getPrinterName() {219if (name == null) {220name = new PrinterName(printer, null);221}222return name;223}224225private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsBSD() {226if (PrintServiceLookupProvider.cmdIndex ==227PrintServiceLookupProvider.UNINITIALIZED) {228229PrintServiceLookupProvider.cmdIndex =230PrintServiceLookupProvider.getBSDCommandIndex();231}232233String command = "/usr/sbin/lpc status " + printer234+ lpcStatusCom[PrintServiceLookupProvider.cmdIndex];235String[] results= PrintServiceLookupProvider.execCmd(command);236237if (results != null && results.length > 0) {238if (PrintServiceLookupProvider.cmdIndex ==239PrintServiceLookupProvider.BSD_LPD_NG) {240if (results[0].startsWith("enabled enabled")) {241return PrinterIsAcceptingJobs.ACCEPTING_JOBS ;242}243} else {244if ((results[1].trim().startsWith("queuing is enabled") &&245results[2].trim().startsWith("printing is enabled")) ||246(results.length >= 4 &&247results[2].trim().startsWith("queuing is enabled") &&248results[3].trim().startsWith("printing is enabled"))) {249return PrinterIsAcceptingJobs.ACCEPTING_JOBS ;250}251}252}253return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS ;254}255256// Filter the list of possible AIX Printers and remove header lines257// and extra lines which have been added for remote printers.258// 'protected' because this method is also used from PrintServiceLookupProvider.259protected static String[] filterPrinterNamesAIX(String[] posPrinters) {260ArrayList<String> printers = new ArrayList<>();261String [] splitPart;262263for(int i = 0; i < posPrinters.length; i++) {264// Remove the header lines265if (posPrinters[i].startsWith("---") ||266posPrinters[i].startsWith("Queue") ||267posPrinters[i].isEmpty()) continue;268269// Check if there is a ":" in the end of the first colomn.270// This means that it is not a valid printer definition.271splitPart = posPrinters[i].split(" ");272if(splitPart.length >= 1 && !splitPart[0].trim().endsWith(":")) {273printers.add(posPrinters[i]);274}275}276277return printers.toArray(new String[printers.size()]);278}279280private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsAIX() {281// On AIX there should not be a blank after '-a'.282String command = "/usr/bin/lpstat -a" + printer;283String[] results= PrintServiceLookupProvider.execCmd(command);284285// Remove headers and bogus entries added by remote printers.286results = filterPrinterNamesAIX(results);287288if (results != null && results.length > 0) {289for (int i = 0; i < results.length; i++) {290if (results[i].contains("READY") ||291results[i].contains("RUNNING")) {292return PrinterIsAcceptingJobs.ACCEPTING_JOBS;293}294}295}296297return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;298299}300301private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {302if (PrintServiceLookupProvider.isBSD()) {303return getPrinterIsAcceptingJobsBSD();304} else if (PrintServiceLookupProvider.isAIX()) {305return getPrinterIsAcceptingJobsAIX();306} else {307return PrinterIsAcceptingJobs.ACCEPTING_JOBS;308}309}310311private PrinterState getPrinterState() {312if (isInvalid) {313return PrinterState.STOPPED;314} else {315return null;316}317}318319private PrinterStateReasons getPrinterStateReasons() {320if (isInvalid) {321PrinterStateReasons psr = new PrinterStateReasons();322psr.put(PrinterStateReason.SHUTDOWN, Severity.ERROR);323return psr;324} else {325return null;326}327}328329private QueuedJobCount getQueuedJobCountBSD() {330if (PrintServiceLookupProvider.cmdIndex ==331PrintServiceLookupProvider.UNINITIALIZED) {332333PrintServiceLookupProvider.cmdIndex =334PrintServiceLookupProvider.getBSDCommandIndex();335}336337int qlen = 0;338String command = "/usr/sbin/lpc status " + printer339+ lpcQueueCom[PrintServiceLookupProvider.cmdIndex];340String[] results = PrintServiceLookupProvider.execCmd(command);341342if (results != null && results.length > 0) {343String queued;344if (PrintServiceLookupProvider.cmdIndex ==345PrintServiceLookupProvider.BSD_LPD_NG) {346queued = results[0];347} else {348queued = results[3].trim();349if (queued.startsWith("no")) {350return new QueuedJobCount(0);351} else {352queued = queued.substring(0, queued.indexOf(' '));353}354}355356try {357qlen = Integer.parseInt(queued);358} catch (NumberFormatException e) {359}360}361362return new QueuedJobCount(qlen);363}364365private QueuedJobCount getQueuedJobCountAIX() {366// On AIX there should not be a blank after '-a'.367String command = "/usr/bin/lpstat -a" + printer;368String[] results= PrintServiceLookupProvider.execCmd(command);369370// Remove headers and bogus entries added by remote printers.371results = filterPrinterNamesAIX(results);372373int qlen = 0;374if (results != null && results.length > 0){375for (int i = 0; i < results.length; i++) {376if (results[i].contains("QUEUED")){377qlen ++;378}379}380}381return new QueuedJobCount(qlen);382}383384private QueuedJobCount getQueuedJobCount() {385if (PrintServiceLookupProvider.isBSD()) {386return getQueuedJobCountBSD();387} else if (PrintServiceLookupProvider.isAIX()) {388return getQueuedJobCountAIX();389} else {390return new QueuedJobCount(0);391}392}393394private PrintServiceAttributeSet getBSDServiceAttributes() {395PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();396attrs.add(getQueuedJobCountBSD());397attrs.add(getPrinterIsAcceptingJobsBSD());398return attrs;399}400401private PrintServiceAttributeSet getAIXServiceAttributes() {402PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();403attrs.add(getQueuedJobCountAIX());404attrs.add(getPrinterIsAcceptingJobsAIX());405return attrs;406}407408private boolean isSupportedCopies(Copies copies) {409int numCopies = copies.getValue();410return (numCopies > 0 && numCopies < MAXCOPIES);411}412413private boolean isSupportedMedia(MediaSizeName msn) {414for (int i=0; i<mediaSizes.length; i++) {415if (msn.equals(mediaSizes[i])) {416return true;417}418}419return false;420}421422public DocPrintJob createPrintJob() {423SecurityManager security = System.getSecurityManager();424if (security != null) {425security.checkPrintJobAccess();426}427return new UnixPrintJob(this);428}429430private PrintServiceAttributeSet getDynamicAttributes() {431if (PrintServiceLookupProvider.isAIX()) {432return getAIXServiceAttributes();433} else {434return getBSDServiceAttributes();435}436}437438public PrintServiceAttributeSet getUpdatedAttributes() {439PrintServiceAttributeSet currSet = getDynamicAttributes();440if (lastSet == null) {441lastSet = currSet;442return AttributeSetUtilities.unmodifiableView(currSet);443} else {444PrintServiceAttributeSet updates =445new HashPrintServiceAttributeSet();446Attribute []attrs = currSet.toArray();447Attribute attr;448for (int i=0; i<attrs.length; i++) {449attr = attrs[i];450if (!lastSet.containsValue(attr)) {451updates.add(attr);452}453}454lastSet = currSet;455return AttributeSetUtilities.unmodifiableView(updates);456}457}458459public void wakeNotifier() {460synchronized (this) {461if (notifier != null) {462notifier.wake();463}464}465}466467public void addPrintServiceAttributeListener(468PrintServiceAttributeListener listener) {469synchronized (this) {470if (listener == null) {471return;472}473if (notifier == null) {474notifier = new ServiceNotifier(this);475}476notifier.addListener(listener);477}478}479480public void removePrintServiceAttributeListener(481PrintServiceAttributeListener listener) {482synchronized (this) {483if (listener == null || notifier == null ) {484return;485}486notifier.removeListener(listener);487if (notifier.isEmpty()) {488notifier.stopNotifier();489notifier = null;490}491}492}493494@SuppressWarnings("unchecked")495public <T extends PrintServiceAttribute>496T getAttribute(Class<T> category)497{498if (category == null) {499throw new NullPointerException("category");500}501if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {502throw new IllegalArgumentException("Not a PrintServiceAttribute");503}504505if (category == PrinterName.class) {506return (T)getPrinterName();507} else if (category == PrinterState.class) {508return (T)getPrinterState();509} else if (category == PrinterStateReasons.class) {510return (T)getPrinterStateReasons();511} else if (category == QueuedJobCount.class) {512return (T)getQueuedJobCount();513} else if (category == PrinterIsAcceptingJobs.class) {514return (T)getPrinterIsAcceptingJobs();515} else {516return null;517}518}519520public PrintServiceAttributeSet getAttributes() {521PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();522attrs.add(getPrinterName());523attrs.add(getPrinterIsAcceptingJobs());524PrinterState prnState = getPrinterState();525if (prnState != null) {526attrs.add(prnState);527}528PrinterStateReasons prnStateReasons = getPrinterStateReasons();529if (prnStateReasons != null) {530attrs.add(prnStateReasons);531}532attrs.add(getQueuedJobCount());533return AttributeSetUtilities.unmodifiableView(attrs);534}535536private void initSupportedDocFlavors() {537String hostEnc = DocFlavor.hostEncoding.toLowerCase(Locale.ENGLISH);538if (!hostEnc.equals("utf-8") && !hostEnc.equals("utf-16") &&539!hostEnc.equals("utf-16be") && !hostEnc.equals("utf-16le") &&540!hostEnc.equals("us-ascii")) {541542int len = supportedDocFlavorsInit.length;543DocFlavor[] flavors =544new DocFlavor[len + supportedHostDocFlavors.length];545// copy host encoding flavors546System.arraycopy(supportedHostDocFlavors, 0, flavors,547len, supportedHostDocFlavors.length);548System.arraycopy(supportedDocFlavorsInit, 0, flavors, 0, len);549550supportedDocFlavors = flavors;551} else {552supportedDocFlavors = supportedDocFlavorsInit;553}554}555556public DocFlavor[] getSupportedDocFlavors() {557if (supportedDocFlavors == null) {558initSupportedDocFlavors();559}560int len = supportedDocFlavors.length;561DocFlavor[] flavors = new DocFlavor[len];562System.arraycopy(supportedDocFlavors, 0, flavors, 0, len);563564return flavors;565}566567public boolean isDocFlavorSupported(DocFlavor flavor) {568if (supportedDocFlavors == null) {569initSupportedDocFlavors();570}571for (int f=0; f<supportedDocFlavors.length; f++) {572if (flavor.equals(supportedDocFlavors[f])) {573return true;574}575}576return false;577}578579public Class<?>[] getSupportedAttributeCategories() {580ArrayList<Class<?>> categList = new ArrayList<>(otherAttrCats.length);581for (Class<?> c : otherAttrCats) {582categList.add(c);583}584if (GraphicsEnvironment.isHeadless() == false) {585categList.add(DialogOwner.class);586categList.add(DialogTypeSelection.class);587}588return categList.toArray(new Class<?>[categList.size()]);589}590591public boolean592isAttributeCategorySupported(Class<? extends Attribute> category)593{594if (category == null) {595throw new NullPointerException("null category");596}597if (!(Attribute.class.isAssignableFrom(category))) {598throw new IllegalArgumentException(category +599" is not an Attribute");600}601602for (int i=0;i<otherAttrCats.length;i++) {603if (category == otherAttrCats[i]) {604return true;605}606}607return false;608}609610/* return defaults for all attributes for which there is a default611* value612*/613public Object614getDefaultAttributeValue(Class<? extends Attribute> category)615{616if (category == null) {617throw new NullPointerException("null category");618}619if (!Attribute.class.isAssignableFrom(category)) {620throw new IllegalArgumentException(category +621" is not an Attribute");622}623624if (!isAttributeCategorySupported(category)) {625return null;626}627628if (category == Copies.class) {629return new Copies(1);630} else if (category == Chromaticity.class) {631return Chromaticity.COLOR;632} else if (category == Destination.class) {633try {634return new Destination((new File("out.ps")).toURI());635} catch (SecurityException se) {636try {637return new Destination(new URI("file:out.ps"));638} catch (URISyntaxException e) {639return null;640}641}642} else if (category == Fidelity.class) {643return Fidelity.FIDELITY_FALSE;644} else if (category == JobName.class) {645return new JobName("Java Printing", null);646} else if (category == JobSheets.class) {647return JobSheets.STANDARD;648} else if (category == Media.class) {649String defaultCountry = Locale.getDefault().getCountry();650if (defaultCountry != null &&651(defaultCountry.isEmpty() ||652defaultCountry.equals(Locale.US.getCountry()) ||653defaultCountry.equals(Locale.CANADA.getCountry()))) {654return MediaSizeName.NA_LETTER;655} else {656return MediaSizeName.ISO_A4;657}658} else if (category == MediaPrintableArea.class) {659String defaultCountry = Locale.getDefault().getCountry();660float iw, ih;661if (defaultCountry != null &&662(defaultCountry.isEmpty() ||663defaultCountry.equals(Locale.US.getCountry()) ||664defaultCountry.equals(Locale.CANADA.getCountry()))) {665iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 0.5f;666ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 0.5f;667} else {668iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 0.5f;669ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 0.5f;670}671return new MediaPrintableArea(0.25f, 0.25f, iw, ih,672MediaPrintableArea.INCH);673} else if (category == OrientationRequested.class) {674return OrientationRequested.PORTRAIT;675} else if (category == PageRanges.class) {676return new PageRanges(1, Integer.MAX_VALUE);677} else if (category == RequestingUserName.class) {678String userName = "";679try {680userName = System.getProperty("user.name", "");681} catch (SecurityException se) {682}683return new RequestingUserName(userName, null);684} else if (category == SheetCollate.class) {685return SheetCollate.UNCOLLATED;686} else if (category == Sides.class) {687return Sides.ONE_SIDED;688} else689return null;690}691692693private boolean isAutoSense(DocFlavor flavor) {694if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||695flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||696flavor.equals(DocFlavor.URL.AUTOSENSE)) {697return true;698}699else {700return false;701}702}703704public Object705getSupportedAttributeValues(Class<? extends Attribute> category,706DocFlavor flavor,707AttributeSet attributes)708{709710if (category == null) {711throw new NullPointerException("null category");712}713if (!Attribute.class.isAssignableFrom(category)) {714throw new IllegalArgumentException(category +715" does not implement Attribute");716}717if (flavor != null) {718if (!isDocFlavorSupported(flavor)) {719throw new IllegalArgumentException(flavor +720" is an unsupported flavor");721} else if (isAutoSense(flavor)) {722return null;723}724}725726if (!isAttributeCategorySupported(category)) {727return null;728}729730if (category == Chromaticity.class) {731if (flavor == null || isServiceFormattedFlavor(flavor)) {732Chromaticity[]arr = new Chromaticity[1];733arr[0] = Chromaticity.COLOR;734return (arr);735} else {736return null;737}738} else if (category == Destination.class) {739try {740return new Destination((new File("out.ps")).toURI());741} catch (SecurityException se) {742try {743return new Destination(new URI("file:out.ps"));744} catch (URISyntaxException e) {745return null;746}747}748} else if (category == JobName.class) {749return new JobName("Java Printing", null);750} else if (category == JobSheets.class) {751JobSheets[] arr = new JobSheets[2];752arr[0] = JobSheets.NONE;753arr[1] = JobSheets.STANDARD;754return arr;755} else if (category == RequestingUserName.class) {756String userName = "";757try {758userName = System.getProperty("user.name", "");759} catch (SecurityException se) {760}761return new RequestingUserName(userName, null);762} else if (category == OrientationRequested.class) {763if (flavor == null || isServiceFormattedFlavor(flavor)) {764OrientationRequested []arr = new OrientationRequested[3];765arr[0] = OrientationRequested.PORTRAIT;766arr[1] = OrientationRequested.LANDSCAPE;767arr[2] = OrientationRequested.REVERSE_LANDSCAPE;768return arr;769} else {770return null;771}772} else if ((category == Copies.class) ||773(category == CopiesSupported.class)) {774if (flavor == null ||775!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||776flavor.equals(DocFlavor.URL.POSTSCRIPT) ||777flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) {778return new CopiesSupported(1, MAXCOPIES);779} else {780return null;781}782} else if (category == Media.class) {783Media []arr = new Media[mediaSizes.length];784System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length);785return arr;786} else if (category == Fidelity.class) {787Fidelity []arr = new Fidelity[2];788arr[0] = Fidelity.FIDELITY_FALSE;789arr[1] = Fidelity.FIDELITY_TRUE;790return arr;791} else if (category == MediaPrintableArea.class) {792/* The code below implements the behaviour that if no Media or793* MediaSize attribute is specified, return an array of794* MediaPrintableArea, one for each supported Media.795* If a MediaSize is specified, return a MPA consistent for that,796* and if a Media is specified locate its MediaSize and return797* its MPA, and if none is found, return an MPA for the default798* Media for this service.799*/800if (attributes == null) {801return getAllPrintableAreas();802}803MediaSize mediaSize = (MediaSize)attributes.get(MediaSize.class);804Media media = (Media)attributes.get(Media.class);805MediaPrintableArea []arr = new MediaPrintableArea[1];806if (mediaSize == null) {807if (media instanceof MediaSizeName) {808MediaSizeName msn = (MediaSizeName)media;809mediaSize = MediaSize.getMediaSizeForName(msn);810if (mediaSize == null) {811/* try to get a size from the default media */812media = (Media)getDefaultAttributeValue(Media.class);813if (media instanceof MediaSizeName) {814msn = (MediaSizeName)media;815mediaSize = MediaSize.getMediaSizeForName(msn);816}817if (mediaSize == null) {818/* shouldn't happen, return a default */819arr[0] = new MediaPrintableArea(0.25f, 0.25f,8208f, 10.5f,821MediaSize.INCH);822return arr;823}824}825} else {826return getAllPrintableAreas();827}828}829/* If reach here MediaSize is non-null */830assert mediaSize != null;831arr[0] = new MediaPrintableArea(0.25f, 0.25f,832mediaSize.getX(MediaSize.INCH)-0.5f,833mediaSize.getY(MediaSize.INCH)-0.5f,834MediaSize.INCH);835return arr;836} else if (category == PageRanges.class) {837if (flavor == null ||838flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||839flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {840PageRanges []arr = new PageRanges[1];841arr[0] = new PageRanges(1, Integer.MAX_VALUE);842return arr;843} else {844return null;845}846} else if (category == SheetCollate.class) {847if (flavor == null ||848flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||849flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {850SheetCollate []arr = new SheetCollate[2];851arr[0] = SheetCollate.UNCOLLATED;852arr[1] = SheetCollate.COLLATED;853return arr;854} else {855return null;856}857} else if (category == Sides.class) {858if (flavor == null ||859flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||860flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {861Sides []arr = new Sides[3];862arr[0] = Sides.ONE_SIDED;863arr[1] = Sides.TWO_SIDED_LONG_EDGE;864arr[2] = Sides.TWO_SIDED_SHORT_EDGE;865return arr;866} else {867return null;868}869} else {870return null;871}872}873874private static MediaPrintableArea[] mpas = null;875private MediaPrintableArea[] getAllPrintableAreas() {876877if (mpas == null) {878Media[] media = (Media[])getSupportedAttributeValues(Media.class,879null, null);880mpas = new MediaPrintableArea[media.length];881for (int i=0; i< mpas.length; i++) {882if (media[i] instanceof MediaSizeName) {883MediaSizeName msn = (MediaSizeName)media[i];884MediaSize mediaSize = MediaSize.getMediaSizeForName(msn);885if (mediaSize == null) {886mpas[i] = (MediaPrintableArea)887getDefaultAttributeValue(MediaPrintableArea.class);888} else {889mpas[i] = new MediaPrintableArea(0.25f, 0.25f,890mediaSize.getX(MediaSize.INCH)-0.5f,891mediaSize.getY(MediaSize.INCH)-0.5f,892MediaSize.INCH);893}894}895}896}897MediaPrintableArea[] mpasCopy = new MediaPrintableArea[mpas.length];898System.arraycopy(mpas, 0, mpasCopy, 0, mpas.length);899return mpasCopy;900}901902/* Is this one of the flavors that this service explicitly903* generates postscript for, and so can control how it is rendered?904*/905private boolean isServiceFormattedFlavor(DocFlavor flavor) {906return907flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||908flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||909flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||910flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||911flavor.equals(DocFlavor.URL.GIF) ||912flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||913flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||914flavor.equals(DocFlavor.URL.JPEG) ||915flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||916flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||917flavor.equals(DocFlavor.URL.PNG);918}919920public boolean isAttributeValueSupported(Attribute attr,921DocFlavor flavor,922AttributeSet attributes) {923if (attr == null) {924throw new NullPointerException("null attribute");925}926if (flavor != null) {927if (!isDocFlavorSupported(flavor)) {928throw new IllegalArgumentException(flavor +929" is an unsupported flavor");930} else if (isAutoSense(flavor)) {931return false;932}933}934Class<? extends Attribute> category = attr.getCategory();935if (!isAttributeCategorySupported(category)) {936return false;937}938else if (attr.getCategory() == Chromaticity.class) {939if (flavor == null || isServiceFormattedFlavor(flavor)) {940return attr == Chromaticity.COLOR;941} else {942return false;943}944}945else if (attr.getCategory() == Copies.class) {946return (flavor == null ||947!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||948flavor.equals(DocFlavor.URL.POSTSCRIPT) ||949flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) &&950isSupportedCopies((Copies)attr);951} else if (attr.getCategory() == Destination.class) {952URI uri = ((Destination)attr).getURI();953if ("file".equals(uri.getScheme()) &&954!uri.getSchemeSpecificPart().isEmpty()) {955return true;956} else {957return false;958}959} else if (attr.getCategory() == Media.class) {960if (attr instanceof MediaSizeName) {961return isSupportedMedia((MediaSizeName)attr);962} else {963return false;964}965} else if (attr.getCategory() == OrientationRequested.class) {966if (attr == OrientationRequested.REVERSE_PORTRAIT ||967(flavor != null) &&968!isServiceFormattedFlavor(flavor)) {969return false;970}971} else if (attr.getCategory() == PageRanges.class) {972if (flavor != null &&973!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||974flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {975return false;976}977} else if (attr.getCategory() == SheetCollate.class) {978if (flavor != null &&979!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||980flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {981return false;982}983} else if (attr.getCategory() == Sides.class) {984if (flavor != null &&985!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||986flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {987return false;988}989} else if (attr.getCategory() == DialogOwner.class) {990DialogOwner owner = (DialogOwner)attr;991// ID not supported on any dialog type on Unix platforms.992if (DialogOwnerAccessor.getID(owner) != 0) {993return false;994}995// UnixPrintService is not used on Mac, so this is996// always some Unix system that does not have CUPS/IPP997// Which means we always use a Swing dialog and we need998// only check if alwaysOnTop is supported by the toolkit.999if (owner.getOwner() != null) {1000return true;1001} else {1002return Toolkit.getDefaultToolkit().isAlwaysOnTopSupported();1003}1004} else if (attr.getCategory() == DialogTypeSelection.class) {1005DialogTypeSelection dts = (DialogTypeSelection)attr;1006return dts == DialogTypeSelection.COMMON;1007}1008return true;1009}10101011public AttributeSet getUnsupportedAttributes(DocFlavor flavor,1012AttributeSet attributes) {10131014if (flavor != null && !isDocFlavorSupported(flavor)) {1015throw new IllegalArgumentException("flavor " + flavor +1016"is not supported");1017}10181019if (attributes == null) {1020return null;1021}10221023Attribute attr;1024AttributeSet unsupp = new HashAttributeSet();1025Attribute []attrs = attributes.toArray();1026for (int i=0; i<attrs.length; i++) {1027try {1028attr = attrs[i];1029if (!isAttributeCategorySupported(attr.getCategory())) {1030unsupp.add(attr);1031} else if (!isAttributeValueSupported(attr, flavor,1032attributes)) {1033unsupp.add(attr);1034}1035} catch (ClassCastException e) {1036}1037}1038if (unsupp.isEmpty()) {1039return null;1040} else {1041return unsupp;1042}1043}10441045public ServiceUIFactory getServiceUIFactory() {1046return null;1047}10481049public String toString() {1050return "Unix Printer : " + getName();1051}10521053public boolean equals(Object obj) {1054return (obj == this ||1055(obj instanceof UnixPrintService &&1056((UnixPrintService)obj).getName().equals(getName())));1057}10581059public int hashCode() {1060return this.getClass().hashCode()+getName().hashCode();1061}10621063public boolean usesClass(Class<?> c) {1064return (c == sun.print.PSPrinterJob.class);1065}10661067}106810691070