Improving the Print Adapter

* Add better namespace support
* Add documentation
* Add test cases (minimal)
* Add functionality
This commit is contained in:
Gunnar Hillert
2012-08-13 16:00:37 -04:00
parent 937d7467d4
commit 255a74ecac
32 changed files with 1198 additions and 445 deletions

View File

@@ -1,70 +1,121 @@
Spring Integration Print Adapter
=================================================
Spring Integration Print Support
================================
Welcome to the Spring Integration Adapter Template. This template is meant as a starting point for new Spring Integration Adapters. This temaplate provides the following
stubbed out components:
## Overview
* Outbound Channel Adapter
* Outbound Gateway
* Inbound Channel Adapter
The *Spring Integration Print* allows you to print payloads using the [Java Print Service][]. As such one *Outbound Channel Adapter* is provided.
# STS issues to be aware of
## Requirements
* [STS-1790](https://issuetracker.springsource.com/browse/STS-1790) - Allow for more flexibility in defining top level packages in the Spring STS Template Wizard
* [STS-2680](https://issuetracker.springsource.com/browse/STS-2680) - New Template Wizard projects aren't categorized on first launch
This module depends by default on Spring Integration 2.2. When using this module, please be aware that printing using [Java Print Service] can be unpredictable depending on the uses platform and the used printer. For some more details, please see:
# FAQ
* http://hillert.blogspot.com/2011/12/java-print-service-frustrations.html
## I need to add AOP Advices to my Adapters
Currently the Print Support has been tested using a *Brother HL-4070CDW* which exhibits several issues such as the inability to execute a print job that prints more than one copy for each page. If you use the Print Module, please report back any compatibility issues with your used printers.
Use FactoryBeans that wrap your adapter. See JPA Adapter for example.
## Dependency Declaration
## More to come...
### Gradle
# Building
dependencies {
compile "org.springframework.integration:spring-integration-print:1.0.0.BUILD-SNAPSHOT"
}
If you encounter out of memory errors during the build, increase available heap and permgen for Gradle:
### Maven
GRADLE_OPTS='-XX:MaxPermSize=1024m -Xmx1024m'
<dependencies>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-print</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
</dependencies>
To build and install jars into your local Maven cache:
## Print Outbound Channel Adapter
./gradlew install
The *Print Outbound Channel Adapter* is implemented using the *PrintMessageHandler* class. It in turn delegates to the *PrintServiceExecutor* class. The *PrintServiceExecutor* is responsible for initializing the Java *[PrintService][]*. As such, you can initialize the *PrintServiceExecutor* with providing a:
To build api Javadoc (results will be in `build/api`):
* Printer Name
* Custom implementation of the *[PrintService][]* interface (Useful for testing)
./gradlew api
If you provide neither a printer name nor an implementation of the *[PrintService][]* interface, then the systems default printer is chosen.
To build reference documentation (results will be in `build/reference`):
The following properties can be set on the *Print Outbound Channel Adapter*:
./gradlew reference
### printJobName
To build complete distribution including `-dist`, `-docs`, and `-schema` zip files (results will be in `build/distributions`)
*Optional* property that let's you specify the name of the print job as it is added to the print queue. Under the covers, this property will create a *javax.print.attribute.standard.JobName* and add it to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
./gradlew dist
### mediaSizeName
# Using SpringSource Tool Suite
*Optional* property that let's you specify the [MediaSizeName][]. Under the covers, this property will add the provided [MediaSizeName][] to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
Gradle projects can be directly imported into STS
### sides
# Using PLain Eclipse
Let's you specify how the pages are are printed to the selected medium, e.g. duplex or one-sided. Under the covers, this property will add the provided [Sides][] instance to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
To generate Eclipse metadata (.classpath and .project files), do the following:
### copies
./gradlew eclipse
Let's you specify an integer value that indicates how many time each print page shall be printed. Under the covers, this property will add a [Copies][] instance to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
Once complete, you may then import the projects into Eclipse as usual:
### mediaTray
*File -> Import -> Existing projects into workspace*
Let's you specify the media tray/bin for the print job. This property can be used instead of providing the *mediaSizeName* property. Under the covers, this property will add the provided [MediaTray][] instance to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
Browse to the *'spring-integration'* root directory. All projects should import
free of errors.
### chromaticity
# Using IntelliJ IDEA
Let's you specify whether you want to do monochrome or color printing. Under the covers, this property will add the provided [Chromaticity][] instance to the respective *PrintRequestAttributeSet*. This property is not used, if not specified (No explicit default value).
To generate IDEA metadata (.iml and .ipr files), do the following:
### docFlavor
./gradlew idea
Let's you specify the [DocFlavor]. If not specified, this property will default to *DocFlavor.STRING.TEXT_PLAIN*.
For more information, please visit the Spring Integration website at:
[http://www.springsource.org/spring-integration](http://www.springsource.org/spring-integration)
**IMPORTANT!** Every property is validated against the to be used [Java Print Service]. Therefore, if the selected [Java Print Service] is not supported, an *IllegalArgumentException* will be thrown.
### Determining you printer capabilities.
In order to get some indication what capabilities are supported by your printer, you may want to too look at the *PrintServiceExecutor*'s *getPrinterInfo()* method. When executed, it returns a list of:
* Supported [DocFlavor][]s
* Supported Attribute Categories
* Supported [Print Attribute][]s
## Namespace Support
*Spring Integration* also provides XML Namespace support for the Print support. Simply add the following Namespace declaration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-print="http://www.springframework.org/schema/integration/print"
xsi:schemaLocation="
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/print http://www.springframework.org/schema/integration/print/spring-integration-print.xsd">
</beans>
An example of declaring a *Print Outbound Channel Adapter* is shown below:
<int-print:outbound-channel-adapter id="printOutboundChannelAdapter"
channel="input"
copies="2"
doc-flavor="java.lang.String"
mime-type="text/plain; charset=utf-8"
sides="DUPLEX"/>
[Java Print Service]: http://docs.oracle.com/javase/6/docs/technotes/guides/jps/index.html
[PrintService]: http://docs.oracle.com/javase/6/docs/api/javax/print/PrintService.html
[Chromaticity]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/standard/Chromaticity.html
[Copies]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/standard/Copies.html
[DocFlavor]: http://docs.oracle.com/javase/6/docs/api/javax/print/DocFlavor.html
[MediaTray]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/standard/MediaTray.html
[Print Attribute]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/Attribute.html
[MediaSizeName]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/standard/MediaSizeName.html
[Sides]: http://docs.oracle.com/javase/6/docs/api/javax/print/attribute/standard/Sides.html

View File

@@ -4,9 +4,6 @@ buildscript {
repositories {
maven { url 'https://repo.springsource.org/plugins-snapshot' }
}
dependencies {
classpath 'org.springframework.build.gradle:docbook-reference-plugin:0.1.5'
}
}
apply plugin: 'java'
@@ -21,9 +18,8 @@ repositories {
maven { url 'http://repo.springsource.org/plugins-release' } // for bundlor
}
// ensure JDK 5 compatibility (GRADLE-18; INT-1578)
sourceCompatibility=1.5
targetCompatibility=1.5
sourceCompatibility=1.6
targetCompatibility=1.6
ext {
aspectjVersion = '1.6.8'
@@ -303,5 +299,5 @@ task dist(dependsOn: assemble) {
task wrapper(type: Wrapper) {
description = 'Generates gradlew[.bat] scripts'
gradleVersion = '1.0-rc-3'
gradleVersion = '1.0'
}

View File

@@ -15,12 +15,17 @@
*/
package org.springframework.integration.print.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.print.outbound.PrintMessageHandler;
import org.springframework.integration.print.support.ChromaticityEnum;
import org.springframework.integration.print.support.MediaSizeNameEnum;
import org.springframework.integration.print.support.MediaTrayEnum;
import org.springframework.integration.print.support.PrintSides;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
@@ -30,7 +35,7 @@ import org.w3c.dom.Element;
* The parser for the Print Outbound Channel Adapter.
*
* @author Gunnar Hillert
* @since 2.2
* @since 1.0
*
*/
public class PrintOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@@ -49,6 +54,16 @@ public class PrintOutboundChannelAdapterParser extends AbstractOutboundChannelAd
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
final BeanDefinitionBuilder printOutboundChannelAdapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(PrintMessageHandler.class);
final BeanDefinitionBuilder printServiceExecutorBuilder = PrintParserUtils.getPrintServiceExecutorBuilder(element, parserContext);
final BeanDefinition printServiceExecutorBeanDefinition = printServiceExecutorBuilder.getBeanDefinition();
final String channelAdapterId = this.resolveId(element, printServiceExecutorBuilder.getRawBeanDefinition(), parserContext);
final String printServiceExecutorBeanName = channelAdapterId + ".jpaExecutor";
parserContext.registerBeanComponent(new BeanComponentDefinition(printServiceExecutorBeanDefinition, printServiceExecutorBeanName));
printOutboundChannelAdapterBuilder.addConstructorArgReference(printServiceExecutorBeanName);
String docFlavor = element.getAttribute("doc-flavor");
String mimeType = element.getAttribute("mime-type");
@@ -62,11 +77,30 @@ public class PrintOutboundChannelAdapterParser extends AbstractOutboundChannelAd
printOutboundChannelAdapterBuilder.addConstructorArgValue(docFlavor);
}
String sides = element.getAttribute("sides");
final String sides = element.getAttribute("sides");
PrintSides printSides = PrintSides.fromString(sides);
if (StringUtils.hasText(sides)) {
final PrintSides printSides = PrintSides.fromString(sides);
printOutboundChannelAdapterBuilder.addPropertyValue("sides", printSides.getSides());
}
printOutboundChannelAdapterBuilder.addPropertyValue("sides", printSides.getSides());
final String mediaSizeName = element.getAttribute("media-size-name");
if (StringUtils.hasText(mediaSizeName)) {
printOutboundChannelAdapterBuilder.addPropertyValue("mediaSizeName", MediaSizeNameEnum.getForString(mediaSizeName));
}
final String mediaTray = element.getAttribute("media-tray");
if (StringUtils.hasText(mediaTray)) {
printOutboundChannelAdapterBuilder.addPropertyValue("mediaTray", MediaTrayEnum.getForString(mediaTray));
}
final String chromaticity = element.getAttribute("chromaticity");
if (StringUtils.hasText(chromaticity)) {
printOutboundChannelAdapterBuilder.addPropertyValue("chromaticity", ChromaticityEnum.getForString(chromaticity));
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(printOutboundChannelAdapterBuilder, element, "copies");

View File

@@ -18,17 +18,17 @@ package org.springframework.integration.print.config.xml;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.print.core.PrintExecutor;
import org.springframework.integration.print.core.PrintServiceExecutor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Contains various utility methods for parsing Print Adapter
* specific namesspace elements as well as for the generation of the the
* respective {@link BeanDefinition}s.
* Contains various utility methods for parsing Print Adapter specific namesspace
* elements and generating the respective {@link BeanDefinition}s.
*
* @author Gunnar Hillert
*
* @since 1.0
*
*/
@@ -40,22 +40,43 @@ public final class PrintParserUtils {
}
/**
* Create a new {@link BeanDefinitionBuilder} for the class {@link PrintExecutor}.
* Initialize the wrapped {@link PrintExecutor} with common properties.
* Create a new {@link BeanDefinitionBuilder} for the class {@link JpaExecutor}.
* Initialize the wrapped {@link JpaExecutor} with common properties.
*
* @param element Must not be null
* @param parserContext Must not be null
* @return The BeanDefinitionBuilder for the PrintExecutor
* @return The BeanDefinitionBuilder for the JpaExecutor
*/
public static BeanDefinitionBuilder getPrintExecutorBuilder(final Element element,
public static BeanDefinitionBuilder getPrintServiceExecutorBuilder(final Element element,
final ParserContext parserContext) {
Assert.notNull(element, "The provided element must not be null.");
Assert.notNull(parserContext, "The provided parserContext must not be null.");
final BeanDefinitionBuilder printExecutorBuilder = BeanDefinitionBuilder.genericBeanDefinition(PrintExecutor.class);
final Object source = parserContext.extractSource(element);
return printExecutorBuilder;
final BeanDefinitionBuilder printServiceExecutorBuilder = BeanDefinitionBuilder.genericBeanDefinition(PrintServiceExecutor.class);
final String printServiceRef = element.getAttribute("print-service-ref");
final String printerName = element.getAttribute("printer-name");
if (StringUtils.hasText(printServiceRef)
&& StringUtils.hasText(printerName)) {
parserContext.getReaderContext().error("Exactly only one of the attributes 'print-service-ref' or " +
"'printer-name' must be be set.", source);
}
if (StringUtils.hasText(printServiceRef)) {
printServiceExecutorBuilder.addConstructorArgReference(printServiceRef);
}
if (StringUtils.hasText(printerName)) {
printServiceExecutorBuilder.addConstructorArgReference(printerName);
}
return printServiceExecutorBuilder;
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.core;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.Message;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
/**
* Bundles common core logic for the Print components.
*
* @author Gunnar Hillert
* @since 1.0
*
*/
public class PrintExecutor implements InitializingBean {
private static final Log logger = LogFactory.getLog(PrintExecutor.class);
private volatile String exampleProperty;
/**
* Constructor.
*/
public PrintExecutor() {}
/**
* Verifies and sets the parameters. E.g. initializes the to be used
*/
public void afterPropertiesSet() {
Assert.hasText(this.exampleProperty, "exampleProperty must not be empty.");
}
/**
* Executes the outbound Print Operation.
*
*/
public Object executeOutboundOperation(final Message<?> message) {
if (logger.isWarnEnabled()) {
logger.warn("Logic not implemented, yet.");
}
return message.getPayload();
}
/**
* Execute the Print operation. Delegates to
* {@link PrintExecutor#poll(Message)}.
*/
public Object poll() {
return poll(null);
}
/**
* Execute a retrieving (polling) Print operation.
*
* @param requestMessage May be null.
* @return The payload object, which may be null.
*/
public Object poll(final Message<?> requestMessage) {
if (logger.isWarnEnabled()) {
logger.warn("Logic not implemented, yet.");
}
return MessageBuilder.fromMessage(requestMessage).build();
}
/**
* Example property to illustrate usage of properties in Spring Integration
* components. Replace with your own logic.
*
* @param exampleProperty Must not be null
*/
public void setExampleProperty(String exampleProperty) {
Assert.hasText(exampleProperty, "exampleProperty must be neither null nor empty");
this.exampleProperty = exampleProperty;
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.core;
import java.util.Arrays;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.print.support.AttributeComparator;
import org.springframework.integration.print.support.DocFlavorComparator;
import org.springframework.integration.print.support.PrintServiceComparator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author Gunnar Hillert
* @since 1.0
*
*/
public final class PrintServiceExecutor {
private final Log logger = LogFactory.getLog(PrintServiceExecutor.class);
private PrintService printService;
public PrintServiceExecutor() {
this("");
}
public PrintServiceExecutor(PrintService printService) {
this.printService = printService;
}
public PrintServiceExecutor(String printerName) {
if (!StringUtils.hasText(printerName)) {
this.printService = PrintServiceLookup.lookupDefaultPrintService();
Assert.notNull(this.printService, "Did not find a the default print service.");
}
else {
PrintService matchingPrintService = null;
for (PrintService printService : PrintServiceExecutor.getAvailablePrinterServices()) {
if (printerName.equalsIgnoreCase(printService.getName())) {
matchingPrintService = printService;
break;
}
}
this.printService = matchingPrintService;
Assert.notNull(this.printService, String.format("Did not find the" +
"print service for printer '%s'.", printerName));
}
if (logger.isInfoEnabled()) {
logger.info("Setting up print service for printer '" + this.printService.getName() + "'.");
}
else if (logger.isDebugEnabled()) {
logger.debug(this.getPrinterInfo());
}
}
public SortedSet<DocFlavor> getDocFlavors() {
final SortedSet<DocFlavor> docFlavors = new TreeSet<DocFlavor>(new DocFlavorComparator());
docFlavors.addAll(Arrays.asList(this.printService.getSupportedDocFlavors()));
return docFlavors;
}
public String getPrinterInfo() {
StringBuilder sb = new StringBuilder();
final SortedSet<DocFlavor> docFlavors = this.getDocFlavors();
final AttributeSet attributes = this.printService.getAttributes();
sb.append("\nPrinter Information\n");
sb.append("==========================================================\n");
sb.append("Name: " + this.printService.getName() + "\n");
sb.append("Supported DocFlavors:\n");
for (DocFlavor docFlavor : docFlavors) {
sb.append(" " + docFlavor + "\n");
}
@SuppressWarnings("unchecked")
Class<? extends Attribute>[] categories = (Class<? extends Attribute>[]) this.printService
.getSupportedAttributeCategories();
sb.append("Supported Categories:\n");
for (Class<?> clazz : categories) {
sb.append(" " + clazz.getName() + "\n");
}
final SortedSet<Attribute> supportedAttributes = new TreeSet<Attribute>(new AttributeComparator());
for (Class<? extends Attribute> clazz : categories) {
for (DocFlavor docFlavor : docFlavors) {
Object value = this.printService.getSupportedAttributeValues(clazz, docFlavor, attributes);
if (value != null) {
if (value instanceof Attribute) {
supportedAttributes.add((Attribute) value);
}
else if (value instanceof Attribute[]) {
supportedAttributes.addAll(Arrays.asList((Attribute[]) value));
}
}
}
}
sb.append("Supported Attributes:\n");
for (Attribute attribute : supportedAttributes) {
sb.append(" " + attribute + "(" + attribute.getCategory().getSimpleName() + ")\n");
}
return sb.toString();
}
public static SortedSet<PrintService> getAvailablePrinterServices() {
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
printServices[0].getName();
SortedSet<PrintService> printServicesList = new TreeSet<PrintService>(new PrintServiceComparator());
printServicesList.addAll(Arrays.asList(printServices));
return printServicesList;
}
public SortedSet<DocFlavor> getDocFlavorsSupportingAttribute(Attribute attribute) {
final SortedSet<DocFlavor> docFlavors = this.getDocFlavors();
final AttributeSet attributes = this.printService.getAttributes();
final SortedSet<DocFlavor> matchedDocFlavors = new TreeSet<DocFlavor>(new DocFlavorComparator());
for (DocFlavor docFlavor : docFlavors) {
final Object value = this.printService.getSupportedAttributeValues(attribute.getCategory(), docFlavor, attributes);
if (value != null) {
matchedDocFlavors.add(docFlavor);
}
}
return matchedDocFlavors;
}
public PrintService getPrintService() {
return printService;
}
}

View File

@@ -1,4 +0,0 @@
/**
* Provides core classes of the Print module.
*/
package org.springframework.integration.print.core;

View File

@@ -16,82 +16,225 @@
package org.springframework.integration.print.outbound;
import java.io.InputStream;
import java.util.Locale;
import javax.print.Doc;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.SimpleDoc;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Chromaticity;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.MediaTray;
import javax.print.attribute.standard.Sides;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.Message;
import org.springframework.integration.handler.AbstractMessageHandler;
import org.springframework.integration.print.core.PrintServiceExecutor;
import org.springframework.integration.print.support.PrintJobMonitor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Simple adapter to support printing of payloads.
* Outbound Adapter that supports printing of payloads.
*
* @author Gunnar Hillert
* @since 2.2
* @since 1.0
*/
public class PrintMessageHandler extends AbstractMessageHandler {
private static final Log LOG = LogFactory.getLog(PrintMessageHandler.class);
private volatile Sides sides = Sides.ONE_SIDED;
private volatile Copies copies = new Copies(1);
private final PrintServiceExecutor printServiceExecutor;
private volatile String printJobName;
private volatile MediaSizeName mediaSizeName;
private volatile Sides sides;
private volatile Copies copies;
private volatile MediaTray mediaTray;
private volatile Chromaticity chromaticity;
private final DocFlavor docFlavor;
public PrintMessageHandler(String mimeType, String className) {
private volatile PrintRequestAttributeSet printRequestAttributeSet = new HashPrintRequestAttributeSet();
public PrintMessageHandler(PrintServiceExecutor printServiceExecutor, DocFlavor docFlavor) {
Assert.notNull(docFlavor, "'docFlavor' must not be null.");
this.docFlavor = docFlavor;
this.printServiceExecutor = printServiceExecutor;
}
public PrintMessageHandler(PrintServiceExecutor printServiceExecutor, String mimeType, String className) {
Assert.hasText(className, "'className' must be neither null nor empty.");
Assert.hasText(mimeType, "'mimeType' must be neither null nor empty.");
this.docFlavor = new DocFlavor(mimeType, className);
this.printServiceExecutor = printServiceExecutor;
}
public PrintMessageHandler() {
this.docFlavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
public PrintMessageHandler(PrintServiceExecutor printServiceExecutor) {
this.docFlavor = DocFlavor.STRING.TEXT_PLAIN;
this.printServiceExecutor = printServiceExecutor;
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
final PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
Assert.notNull(printService, "Did not find a 'printService'.");
if (LOG.isInfoEnabled()) {
LOG.info("Printing to default printer: " + printService.getName());
if (LOG.isDebugEnabled()) {
LOG.debug("Printing using printer '" + this.printServiceExecutor.getPrintService().getName() + "'.");
}
final Doc doc = new SimpleDoc(((String) message.getPayload()).getBytes(), docFlavor, null);
DocAttributeSet das = new HashDocAttributeSet();
das.add(Chromaticity.MONOCHROME);
final PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
Object payload = message.getPayload();
attributes.add(copies);
attributes.add(sides);
final Doc doc = new SimpleDoc(message.getPayload(), docFlavor, das);
final DocPrintJob job = printService.createPrintJob();
job.print(doc, attributes);
final DocPrintJob job = this.printServiceExecutor.getPrintService().createPrintJob();
PrintJobMonitor printJobMonitor = new PrintJobMonitor(job);
job.print(doc, this.printRequestAttributeSet);
printJobMonitor.waitForDone();
if (payload instanceof InputStream) {
((InputStream) payload).close();
}
}
@Override
protected void onInit() throws Exception {
if (this.copies != null) {
//Assert.isTrue(printService.isAttributeValueSupported(this.copies, this.docFlavor, this.printService.getAttributes()),
// "Attribute '" + this.copies.getName() + "' with value '" + this.copies.getValue() + "' is not supported.");
this.printRequestAttributeSet.add(this.copies);
}
if (this.chromaticity != null) {
Assert.isTrue(this.printServiceExecutor.getPrintService().isAttributeValueSupported(this.chromaticity, this.docFlavor, this.printServiceExecutor.getPrintService().getAttributes()),
"Attribute '" + this.chromaticity.getName() + "' with value '" + this.chromaticity.getValue() + "' is not supported.");
this.printRequestAttributeSet.add(this.chromaticity);
}
if (this.mediaSizeName != null) {
Assert.isTrue(this.printServiceExecutor.getPrintService().isAttributeValueSupported(this.mediaSizeName, null, null),
"Attribute '" + this.mediaSizeName.getName()
+ "' with value '" + this.mediaSizeName.getValue() + "' is not supported.");
this.printRequestAttributeSet.add(this.mediaSizeName);
}
if (this.mediaTray != null) {
Assert.isTrue(this.printServiceExecutor.getPrintService().isAttributeValueSupported(this.mediaTray, this.docFlavor, this.printServiceExecutor.getPrintService().getAttributes()),
"Attribute value '" + this.mediaTray + "' is not supported.");
this.printRequestAttributeSet.add(this.mediaTray);
}
if (this.sides!=null) {
Assert.isTrue(this.printServiceExecutor.getPrintService().isAttributeValueSupported(this.sides, this.docFlavor, this.printServiceExecutor.getPrintService().getAttributes()),
"Attribute value '" + this.sides + "' is not supported.");
this.printRequestAttributeSet.add(this.sides);
}
if (StringUtils.hasText(this.printJobName)) {
this.printRequestAttributeSet.add(new JobName(this.printJobName, Locale.getDefault()));
}
super.onInit();
}
/**
* Specifies how the pages are are printed to the selected medium,
* e.g. duplex or one-sided. Under the covers, this property will add the
* provided {@link Sides} instance to the respective {@link PrintRequestAttributeSet}.
*
* This property is not used, if not specified (No explicit default value).
*
* @param sides Must not be null
*/
public void setSides(Sides sides) {
Assert.notNull(sides, "'sides' must not be null");
Assert.notNull(sides, "'sides' must not be null.");
this.sides = sides;
}
/**
* Let<65>s you specify an integer value that indicates how many time each
* print page shall be printed. Under the covers, this property will add a
*
* {@link Copies} instance to the respective {@link PrintRequestAttributeSet}.
* This property is not used, if not specified (No explicit default value).
*
* @param numberOfCopies Must be greater than 0
*/
public void setCopies(int numberOfCopies) {
Assert.isTrue(numberOfCopies > 0, "'copies' must be greater than 0");
Assert.isTrue(numberOfCopies > 0, "'copies' must be greater than 0.");
this.copies = new Copies(numberOfCopies);
}
/**
* Specifies the media tray/bin for the print job. This property can be used
* instead of providing the {@link #mediaSizeName} property. Under the covers,
* this property will add the provided {@link MediaTray} instance to the
* respective {@link PrintRequestAttributeSet}. This property is not used,
* if not specified (No explicit default value).
*
* @param mediaTray Must not be null
*/
public void setMediaTray(MediaTray mediaTray) {
Assert.notNull(mediaTray, "'mediaTray' must not be null.");
this.mediaTray = mediaTray;
}
/**
* Specifies whether you want to do monochrome or color printing. Under the
* covers, this property will add the provided {@link Chromaticity} instance
* to the respective {@link PrintRequestAttributeSet}. This property is not
* used, if not specified (No explicit default value).
*
* @param chromaticity Must not be null.
*/
public void setChromaticity(Chromaticity chromaticity) {
Assert.notNull(chromaticity, "'chromaticity' must not be null.");
this.chromaticity = chromaticity;
}
/**
* Sets the {@link MediaSizeName}. Under the covers, this property will add
* the provided {@link MediaSizeName} to the respective {@link PrintRequestAttributeSet}.
* This property is not used, if not specified (No explicit default value).
*
* @param mediaSizeName Must not be null.
*/
public void setMediaSizeName(MediaSizeName mediaSizeName) {
Assert.notNull(mediaSizeName, "'mediaSizeName' must not be null.");
this.mediaSizeName = mediaSizeName;
}
/**
* Optional property that let<65>s you specify the name of the print job as it
* is added to the print queue. Under the covers, this property will create
* a {@link JobName} instance and add it to the respective {@link PrintRequestAttributeSet}.
* This property is not used, if not specified (No explicit default value).
*
* @param printJobName Must neither be null nor empty.
*/
public void setPrintJobName(String printJobName) {
Assert.hasText(printJobName, "'mediaSizeName' must neither be null nor empty.");
this.printJobName = printJobName;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.support;
import java.util.Comparator;
import javax.print.attribute.Attribute;
/**
* @author Gunnar Hillert
* @since 1.0
*/
public class AttributeComparator implements Comparator<Attribute> {
public int compare(Attribute attribute1, Attribute attribute2) {
int comparison = attribute1.getCategory().getName().compareTo(attribute2.getCategory().getName());
if (comparison == 0) {
return attribute1.toString().compareTo(attribute2.toString());
}
return comparison;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.support;
import javax.print.attribute.standard.Chromaticity;
import org.springframework.util.Assert;
/**
* @author Gunnar Hillert
* @since 1.0
*/
public enum ChromaticityEnum {
COLOR(Chromaticity.COLOR),
MONOCHROME(Chromaticity.MONOCHROME);
private Chromaticity chromaticity;
private ChromaticityEnum(Chromaticity chromaticity) {
this.chromaticity = chromaticity;
}
public Chromaticity getChromaticity() {
return chromaticity;
}
public static Chromaticity getForString(String chromaticityAsString) {
Assert.hasText(chromaticityAsString, "'chromaticityAsString' must neither be null nor empty.");
final ChromaticityEnum[] chromaticityEnumValues = ChromaticityEnum.values();
for (ChromaticityEnum chromaticityEnum : chromaticityEnumValues) {
if (chromaticityEnum.name().equalsIgnoreCase(chromaticityAsString)) {
return chromaticityEnum.getChromaticity();
}
}
throw new IllegalArgumentException("Invalid chromaticity '" + chromaticityAsString
+ "' provided.");
}
}

View File

@@ -13,24 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.print.support;
package org.springframework.integration.print;
import java.util.Comparator;
import javax.print.DocFlavor;
/**
* Print adapter specific message headers.
*
* @author Gunnar Hillert
* @since 1.0
*/
public class PrintHeaders {
public class DocFlavorComparator implements Comparator<DocFlavor> {
private static final String PREFIX = "print_";
public int compare(DocFlavor docFlavor1, DocFlavor docFlavor2) {
public static final String EXAMPLE = PREFIX + "example_";
int comparison = docFlavor1.getMimeType().compareTo(docFlavor2.getMimeType());
/** Noninstantiable utility class */
private PrintHeaders() {
throw new AssertionError();
if (comparison == 0) {
return docFlavor1.getMediaSubtype().compareTo(docFlavor2.getMediaSubtype());
}
return comparison;
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.support;
import javax.print.attribute.standard.MediaSizeName;
import org.springframework.util.Assert;
/**
* @author Gunnar Hillert
* @since 1.0
*/
public enum MediaSizeNameEnum {
ISO_A0(MediaSizeName.ISO_A0),
ISO_A1(MediaSizeName.ISO_A1),
ISO_A2(MediaSizeName.ISO_A2),
ISO_A3(MediaSizeName.ISO_A3),
ISO_A4(MediaSizeName.ISO_A4),
ISO_A5(MediaSizeName.ISO_A5),
ISO_A6(MediaSizeName.ISO_A6),
ISO_A7(MediaSizeName.ISO_A7),
ISO_A8(MediaSizeName.ISO_A8),
ISO_A9(MediaSizeName.ISO_A9),
ISO_A10(MediaSizeName.ISO_A10),
ISO_B0(MediaSizeName.ISO_B0),
ISO_B1(MediaSizeName.ISO_B1),
ISO_B2(MediaSizeName.ISO_B2),
ISO_B3(MediaSizeName.ISO_B3),
ISO_B4(MediaSizeName.ISO_B4),
ISO_B5(MediaSizeName.ISO_B5),
ISO_B6(MediaSizeName.ISO_B6),
ISO_B7(MediaSizeName.ISO_B7),
ISO_B8(MediaSizeName.ISO_B8),
ISO_B9(MediaSizeName.ISO_B9),
ISO_B10(MediaSizeName.ISO_B10),
JIS_B0(MediaSizeName.JIS_B0),
JIS_B1(MediaSizeName.JIS_B1),
JIS_B2(MediaSizeName.JIS_B2),
JIS_B3(MediaSizeName.JIS_B3),
JIS_B4(MediaSizeName.JIS_B4),
JIS_B5(MediaSizeName.JIS_B5),
JIS_B6(MediaSizeName.JIS_B6),
JIS_B7(MediaSizeName.JIS_B7),
JIS_B8(MediaSizeName.JIS_B8),
JIS_B9(MediaSizeName.JIS_B9),
JIS_B10(MediaSizeName.JIS_B10),
ISO_C0(MediaSizeName.ISO_C0),
ISO_C1(MediaSizeName.ISO_C1),
ISO_C2(MediaSizeName.ISO_C2),
ISO_C3(MediaSizeName.ISO_C3),
ISO_C4(MediaSizeName.ISO_C4),
ISO_C5(MediaSizeName.ISO_C5),
ISO_C6(MediaSizeName.ISO_C6),
NA_LETTER(MediaSizeName.NA_LETTER),
NA_LEGAL(MediaSizeName.NA_LEGAL),
LEDGER(MediaSizeName.LEDGER),
TABLOID(MediaSizeName.TABLOID),
INVOICE(MediaSizeName.INVOICE),
FOLIO(MediaSizeName.FOLIO),
QUARTO(MediaSizeName.QUARTO),
JAPANESE_POSTCARD(MediaSizeName.JAPANESE_POSTCARD),
JAPANESE_DOUBLE_POSTCARD(MediaSizeName.JAPANESE_DOUBLE_POSTCARD),
A(MediaSizeName.A),
B(MediaSizeName.B),
C(MediaSizeName.C),
D(MediaSizeName.D),
E(MediaSizeName.E),
ISO_DESIGNATED_LONG(MediaSizeName.ISO_DESIGNATED_LONG),
ITALY_ENVELOPE(MediaSizeName.ITALY_ENVELOPE),
MONARCH_ENVELOPE(MediaSizeName.MONARCH_ENVELOPE),
PERSONAL_ENVELOPE(MediaSizeName.PERSONAL_ENVELOPE),
NA_NUMBER_9_ENVELOPE(MediaSizeName.NA_NUMBER_9_ENVELOPE),
NA_NUMBER_10_ENVELOPE(MediaSizeName.NA_NUMBER_10_ENVELOPE),
NA_NUMBER_11_ENVELOPE(MediaSizeName.NA_NUMBER_11_ENVELOPE),
NA_NUMBER_12_ENVELOPE(MediaSizeName.NA_NUMBER_12_ENVELOPE),
NA_NUMBER_14_ENVELOPE(MediaSizeName.NA_NUMBER_14_ENVELOPE),
NA_6X9_ENVELOPE(MediaSizeName.NA_6X9_ENVELOPE),
NA_7X9_ENVELOPE(MediaSizeName.NA_7X9_ENVELOPE),
NA_9X11_ENVELOPE(MediaSizeName.NA_9X11_ENVELOPE),
NA_9X12_ENVELOPE(MediaSizeName.NA_9X12_ENVELOPE),
NA_10X13_ENVELOPE(MediaSizeName.NA_10X13_ENVELOPE),
NA_10X14_ENVELOPE(MediaSizeName.NA_10X14_ENVELOPE),
NA_10X15_ENVELOPE(MediaSizeName.NA_10X15_ENVELOPE),
NA_5X7(MediaSizeName.NA_5X7),
NA_8X10(MediaSizeName.NA_8X10);
private MediaSizeName mediaSizeName;
private MediaSizeNameEnum(MediaSizeName mediaSizeName) {
this.mediaSizeName = mediaSizeName;
}
public MediaSizeName getMediaSizeName() {
return mediaSizeName;
}
public static MediaSizeName getForString(String mediaSizeNameAsString) {
Assert.hasText(mediaSizeNameAsString, "'mediaSizeNameAsString' must neither be null nor empty.");
final MediaSizeNameEnum[] mediaSizeNameEnumValues = MediaSizeNameEnum.values();
for (MediaSizeNameEnum mediaSizeNameEnum : mediaSizeNameEnumValues) {
if (mediaSizeNameEnum.name().equalsIgnoreCase(mediaSizeNameAsString)) {
return mediaSizeNameEnum.mediaSizeName;
}
}
throw new IllegalArgumentException("Invalid mediaSizeName '" + mediaSizeNameAsString
+ "' provided.");
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.support;
import javax.print.attribute.standard.MediaTray;
import org.springframework.util.Assert;
/**
* @author Gunnar Hillert
* @since 1.0
*/
public enum MediaTrayEnum {
BOTTOM(MediaTray.BOTTOM),
ENVELOPE(MediaTray.ENVELOPE),
LARGE_CAPACITY(MediaTray.LARGE_CAPACITY),
MAIN(MediaTray.MAIN),
MANUAL(MediaTray.MANUAL),
MIDDLE(MediaTray.MIDDLE),
SIDE(MediaTray.SIDE),
TOP(MediaTray.TOP);
private MediaTray mediaTray;
private MediaTrayEnum(MediaTray mediaTray) {
this.mediaTray = mediaTray;
}
public MediaTray getMediaTray() {
return mediaTray;
}
public static MediaTray getForString(String mediaTrayAsString) {
Assert.hasText(mediaTrayAsString, "'mediaTrayAsString' must neither be null nor empty.");
final MediaTrayEnum[] mediaTrayEnumValues = MediaTrayEnum.values();
for (MediaTrayEnum mediaTrayEnum : mediaTrayEnumValues) {
if (mediaTrayEnum.name().equalsIgnoreCase(mediaTrayAsString)) {
return mediaTrayEnum.getMediaTray();
}
}
throw new IllegalArgumentException("Invalid mediaTray '" + mediaTrayAsString
+ "' provided.");
}
}

View File

@@ -15,19 +15,18 @@
*/
package org.springframework.integration.print.support;
import java.util.Comparator;
import javax.print.PrintService;
/**
* Contains utility methods used by the Print components.
*
* @author Gunnar Hillert
* @since 1.0
*
*/
public final class PrintUtils {
public class PrintServiceComparator implements Comparator<PrintService> {
/** Prevent instantiation. */
private PrintUtils() {
throw new AssertionError();
public int compare(PrintService printService1, PrintService printService2) {
return printService1.getName().compareTo(printService2.getName());
}
}

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* 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.
*/
package org.springframework.integration.print.support;
import javax.print.attribute.standard.Sides;

View File

@@ -78,27 +78,58 @@
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="copies" use="optional" type="xsd:integer" default="1">
<xsd:attribute name="printer-name" use="optional" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
The number of copies to print. Defaults to 1 if not set.
If the printer name is not provided the sytem's default printer
is being used if available if available. Otherwise an
exceptions is thrown.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="sides" use="optional" default="ONE_SIDED">
<xsd:attribute name="print-service-ref" use="optional" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Allows you to provide a custom print-service implementation.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="javax.print.PrintService" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="copies" use="optional">
<xsd:annotation>
<xsd:documentation>
The number of copies to print. Uses the default of the printer.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="sides" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defaults to single side if not specified.
Uses the default of the printer.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="sides xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="media-tray" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Uses the default of the printer.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="media-tray xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="doc-flavor" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Defaults to single side if not specified.
See: http://docs.oracle.com/javase/6/docs/api/javax/print/DocFlavor.html
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
@@ -108,6 +139,7 @@
<xsd:attribute name="mime-type" use="optional" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
See: http://docs.oracle.com/javase/6/docs/api/javax/print/DocFlavor.html
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -123,6 +155,13 @@
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="chromaticity">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="MONOCHROME"/>
<xsd:enumeration value="COLOR"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="doc-flavor">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="INPUT_STREAM"/>
@@ -136,4 +175,94 @@
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="media-tray">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="BOTTOM"/>
<xsd:enumeration value="ENVELOPE"/>
<xsd:enumeration value="LARGE_CAPACITY"/>
<xsd:enumeration value="MAIN"/>
<xsd:enumeration value="MANUAL"/>
<xsd:enumeration value="MIDDLE"/>
<xsd:enumeration value="SIDE"/>
<xsd:enumeration value="TOP"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="media-size-name">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="TISO_A0"/>
<xsd:enumeration value="ISO_A1"/>
<xsd:enumeration value="ISO_A2"/>
<xsd:enumeration value="ISO_A3"/>
<xsd:enumeration value="ISO_A4"/>
<xsd:enumeration value="ISO_A5"/>
<xsd:enumeration value="ISO_A6"/>
<xsd:enumeration value="ISO_A7"/>
<xsd:enumeration value="ISO_A8"/>
<xsd:enumeration value="ISO_A9"/>
<xsd:enumeration value="ISO_A10"/>
<xsd:enumeration value="ISO_B0"/>
<xsd:enumeration value="ISO_B1"/>
<xsd:enumeration value="ISO_B2"/>
<xsd:enumeration value="ISO_B3"/>
<xsd:enumeration value="ISO_B4"/>
<xsd:enumeration value="ISO_B5"/>
<xsd:enumeration value="ISO_B6"/>
<xsd:enumeration value="ISO_B7"/>
<xsd:enumeration value="ISO_B8"/>
<xsd:enumeration value="ISO_B9"/>
<xsd:enumeration value="ISO_B10"/>
<xsd:enumeration value="JIS_B0"/>
<xsd:enumeration value="JIS_B1"/>
<xsd:enumeration value="JIS_B2"/>
<xsd:enumeration value="JIS_B3"/>
<xsd:enumeration value="JIS_B4"/>
<xsd:enumeration value="JIS_B5"/>
<xsd:enumeration value="JIS_B6"/>
<xsd:enumeration value="JIS_B7"/>
<xsd:enumeration value="JIS_B8"/>
<xsd:enumeration value="JIS_B9"/>
<xsd:enumeration value="JIS_B10"/>
<xsd:enumeration value="ISO_C0"/>
<xsd:enumeration value="ISO_C1"/>
<xsd:enumeration value="ISO_C2"/>
<xsd:enumeration value="ISO_C3"/>
<xsd:enumeration value="ISO_C4"/>
<xsd:enumeration value="ISO_C5"/>
<xsd:enumeration value="ISO_C6"/>
<xsd:enumeration value="NA_LETTER"/>
<xsd:enumeration value="NA_LEGAL"/>
<xsd:enumeration value="EXECUTIVE"/>
<xsd:enumeration value="LEDGER"/>
<xsd:enumeration value="TABLOID"/>
<xsd:enumeration value="INVOICE"/>
<xsd:enumeration value="FOLIO"/>
<xsd:enumeration value="QUARTO"/>
<xsd:enumeration value="JAPANESE_POSTCARD"/>
<xsd:enumeration value="JAPANESE_DOUBLE_POSTCARD"/>
<xsd:enumeration value="A"/>
<xsd:enumeration value="B"/>
<xsd:enumeration value="C"/>
<xsd:enumeration value="D"/>
<xsd:enumeration value="E"/>
<xsd:enumeration value="ISO_DESIGNATED_LONG"/>
<xsd:enumeration value="ITALY_ENVELOPE"/>
<xsd:enumeration value="MONARCH_ENVELOPE"/>
<xsd:enumeration value="PERSONAL_ENVELOPE"/>
<xsd:enumeration value="NA_NUMBER_9_ENVELOPE"/>
<xsd:enumeration value="NA_NUMBER_10_ENVELOPE"/>
<xsd:enumeration value="NA_NUMBER_11_ENVELOPE"/>
<xsd:enumeration value="NA_NUMBER_12_ENVELOPE"/>
<xsd:enumeration value="NA_NUMBER_14_ENVELOPE"/>
<xsd:enumeration value="NA_6X9_ENVELOPE"/>
<xsd:enumeration value="NA_7X9_ENVELOPE"/>
<xsd:enumeration value="NA_9X11_ENVELOPE"/>
<xsd:enumeration value="NA_9X12_ENVELOPE"/>
<xsd:enumeration value="NA_10X13_ENVELOPE"/>
<xsd:enumeration value="NA_10X14_ENVELOPE"/>
<xsd:enumeration value="NA_10X15_ENVELOPE"/>
<xsd:enumeration value="NA_5X7"/>
<xsd:enumeration value="NA_8X10"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="SIAdapterLowerPrefix"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Print Adapter</title>
<para>
The Spring Integration Print Adapter provides...
</para>
<itemizedlist>
<listitem>
<para><emphasis><link linkend='SIAdapterLowerPrefix-outbound-channel-adapter'>Outbound Channel adapter</link></emphasis></para>
</listitem>
<listitem>
<para><emphasis><link linkend='SIAdapterLowerPrefix-outbound-gateway'>Outbound Gateway</link></emphasis></para>
</listitem>
<listitem>
<para><emphasis><link linkend='SIAdapterLowerPrefix-inbound-channel-adapter'>Inbound Channel Adapter</link></emphasis></para>
</listitem>
</itemizedlist>
<section id="jpa-java-implementation">
<title>Java Implementation</title>
<para>Each of the provided components will use the
<classname>org.springframework.integration.print.core.PrintExecutor</classname>
class...
</para>
</section>
<section id="jpa-common-configuration-attributes">
<title>Common Configuration Attributes</title>
<para>
Certain configuration parameters are shared amongst all Print
components and are described below:
</para>
<para><emphasis role="bold">auto-startup</emphasis></para>
<para>
Lifecycle attribute signaling if this component should
be started during Application Context startup.
Defaults to <code>true</code>.
<emphasis>Optional</emphasis>.
</para>
<para><emphasis role="bold">id</emphasis></para>
<para>
Identifies the underlying Spring bean definition, which
is an instance of either <classname>EventDrivenConsumer</classname>
or <classname>PollingConsumer</classname>.
<emphasis>Optional</emphasis>.
</para>
</section>
<section id="SIAdapterLowerPrefix-outbound-channel-adapter">
<title>Outbound Channel Adapter</title>
<para>
The Print Outbound channel adapter allows you to...
</para>
</section>
<section id="SIAdapterLowerPrefix-outbound-gateway">
<title>Outbound Gateway</title>
<para>
Outbound gateways are similar to outbound channel adapters except that it can also be used to
get a result on the <emphasis>reply channel</emphasis> after performing
the given...
</para>
</section>
<section id="SIAdapterLowerPrefix-inbound-channel-adapter">
<title>Inbound Channel Adapter</title>
<para>
An inbound channel adapter is used to execute...
</para>
</section>
</chapter>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="history"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Change History</title>
</appendix>

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<book xmlns="http://docbook.org/ns/docbook" version="5.0"
xml:id="spring-integration-reference" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink">
<bookinfo>
<title>Spring Integration Print Adapter</title>
<titleabbrev>Print Adapter ${version}</titleabbrev>
<productname>Spring Integration</productname>
<releaseinfo>${version}</releaseinfo>
<!-- TODO: this isn't showing up. -->
<mediaobject>
<imageobject role="fo">
<imagedata fileref="images/logo.png" format="PNG" align="center" />
</imageobject>
<imageobject role="html">
<imagedata fileref="images/logo.png" format="PNG" align="center" />
</imageobject>
</mediaobject>
<!-- END TODO -->
<authorgroup>
<author><firstname>Gunnar Hillert</firstname></author>
</authorgroup>
<legalnotice>
<para>© SpringSource Inc., 2012</para>
</legalnotice>
</bookinfo>
<toc></toc>
<part id="whats-new-part">
<title>What's new?</title>
<partintro id="spring-integration-intro">
<para>
For those who are already familiar with Spring Integration, this
chapter
provides a brief overview of the new features of version 2.2. If you are
interested in the changes and features, that were introduced in
earlier
versions, please take a look at chapter:
<xref linkend="history" />
</para>
</partintro>
<xi:include href="./whats-new.xml" />
</part>
<part id="spring-integration-adapters">
<title>Integration Adapters</title>
<partintro id="spring-integration-adapters">
<para>This section covers the various Channel Adapters and Messaging
Gateways provided
by Spring Integration to support Message-based communication with
external systems.
</para>
</partintro>
<xi:include href="./SIAdapterLowerPrefix.xml" />
</part>
<part id="spring-integration-appendices">
<title>Appendices</title>
<partintro id="spring-integration-adapters">
<para>Advanced Topics and Additional Resources</para>
</partintro>
<xi:include href="./history.xml" />
</part>
</book>

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<appendix xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="resources"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Additional Resources</title>
<section id="resources-home">
<title>Spring Integration Home</title>
<para>
The definitive source of information about Spring Integration is the
<ulink url="http://www.springsource.org/spring-integration">Spring Integration Home</ulink> at
<ulink url="http://www.springsource.org">http://www.springsource.org</ulink>. That site serves as a hub of
information and is the best place to find up-to-date announcements about the project as well as links to
articles, blogs, and new sample applications.
</para>
</section>
</appendix>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="whats-new"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>What's new?</title>
<para>
This chapter provides an overview of the new features and improvements
that have been added to the Print Adapter:
</para>
</chapter>

View File

@@ -1,38 +0,0 @@
package org.springframework.integration.print;
import java.io.FileNotFoundException;
import java.io.InputStream;
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.SimpleDoc;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Sides;
public class PrintTests {
public static void main(String args[]) throws FileNotFoundException, PrintException {
InputStream textStream = PrintTests.class.getResourceAsStream("/print.txt");
DocFlavor myFormat = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc myDoc = new SimpleDoc(textStream, myFormat, null);
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new Copies(1));
aset.add(Sides.ONE_SIDED);
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
System.out.println("Printing to default printer: " + printService.getName());
DocPrintJob job = printService.createPrintJob();
job.print(myDoc, aset);
}
}

View File

@@ -9,14 +9,17 @@
http://www.springframework.org/schema/integration/print http://www.springframework.org/schema/integration/print/spring-integration-print.xsd">
<int:channel id="input"/>
<bean id="printService" class="org.springframework.integration.print.support.MockPrintService"/>
<int-print:outbound-channel-adapter id="printOutboundChannelAdapter"
copies="14"
doc-flavor="java.lang.String"
mime-type="text/plain; charset=utf-16"
sides="DUPLEX"
auto-startup="true"
order="2"
channel="input">
print-service-ref="printService"
copies="14"
doc-flavor="java.lang.String"
mime-type="text/plain; charset=utf-16"
sides="DUPLEX"
auto-startup="true"
order="2"
channel="input">
</int-print:outbound-channel-adapter>
</beans>

View File

@@ -13,22 +13,15 @@
package org.springframework.integration.print.config.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import javax.print.DocFlavor;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Sides;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.print.core.PrintExecutor;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -60,7 +53,6 @@ public class PrintMessageHandlerParserTests {
final Sides sides = TestUtils.getPropertyValue(messageHandler, "sides", Sides.class);
assertEquals(Sides.DUPLEX, sides);
}
}

View File

@@ -1,17 +1,37 @@
package org.springframework.integration.print.outbound;
import org.junit.Ignore;
import java.io.InputStream;
import javax.print.DocFlavor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.integration.print.core.PrintServiceExecutor;
import org.springframework.integration.support.MessageBuilder;
public class PrintMessageHandlerTest {
//@Test
//@Ignore
public void test() {
PrintMessageHandler handler = new PrintMessageHandler();
private static final Log LOG = LogFactory.getLog(PrintMessageHandler.class);
//@Test
public void testPdfPrint() {
PrintServiceExecutor printServiceExecutor = new PrintServiceExecutor();
PrintMessageHandler handler = new PrintMessageHandler(printServiceExecutor, DocFlavor.INPUT_STREAM.AUTOSENSE);
InputStream is = PrintMessageHandlerTest.class.getResourceAsStream("Spring Integration Print Testing.pdf");
handler.setCopies(2);
handler.setPrintJobName("My Spring Integration Print test.");
handler.afterPropertiesSet();
handler.handleMessage(MessageBuilder.withPayload(is).build());
handler.handleMessage(MessageBuilder.withPayload("This is a test".getBytes()).build());
}
@Test
public void testShowSupportedAttributes() {
final PrintServiceExecutor printServiceExecutor = new PrintServiceExecutor();
final String info = printServiceExecutor.getPrinterInfo();
LOG.info(info);
}
}

View File

@@ -1,6 +1,5 @@
package org.springframework.integration.print.outbound;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -0,0 +1,97 @@
package org.springframework.integration.print.support;
import javax.print.DocFlavor;
import javax.print.DocPrintJob;
import javax.print.PrintService;
import javax.print.ServiceUIFactory;
import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.PrintServiceAttribute;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.event.PrintServiceAttributeListener;
public class MockPrintService implements PrintService {
public void addPrintServiceAttributeListener(
PrintServiceAttributeListener listener) {
// TODO Auto-generated method stub
}
public DocPrintJob createPrintJob() {
// TODO Auto-generated method stub
return null;
}
public <T extends PrintServiceAttribute> T getAttribute(Class<T> category) {
// TODO Auto-generated method stub
return null;
}
public PrintServiceAttributeSet getAttributes() {
// TODO Auto-generated method stub
return null;
}
public Object getDefaultAttributeValue(Class<? extends Attribute> category) {
// TODO Auto-generated method stub
return null;
}
public String getName() {
// TODO Auto-generated method stub
return "Mock Printer";
}
public ServiceUIFactory getServiceUIFactory() {
// TODO Auto-generated method stub
return null;
}
public Class<?>[] getSupportedAttributeCategories() {
// TODO Auto-generated method stub
return null;
}
public Object getSupportedAttributeValues(
Class<? extends Attribute> category, DocFlavor flavor,
AttributeSet attributes) {
// TODO Auto-generated method stub
return null;
}
public DocFlavor[] getSupportedDocFlavors() {
// TODO Auto-generated method stub
return null;
}
public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
AttributeSet attributes) {
// TODO Auto-generated method stub
return null;
}
public boolean isAttributeCategorySupported(
Class<? extends Attribute> category) {
// TODO Auto-generated method stub
return false;
}
public boolean isAttributeValueSupported(Attribute attrval,
DocFlavor flavor, AttributeSet attributes) {
// TODO Auto-generated method stub
return true;
}
public boolean isDocFlavorSupported(DocFlavor flavor) {
// TODO Auto-generated method stub
return false;
}
public void removePrintServiceAttributeListener(
PrintServiceAttributeListener listener) {
// TODO Auto-generated method stub
}
}

View File

@@ -0,0 +1,66 @@
package org.springframework.integration.print.support;
import javax.print.DocPrintJob;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class PrintJobMonitor {
private static final Log LOG = LogFactory.getLog(PrintJobMonitor.class);
boolean done = false;
public PrintJobMonitor(DocPrintJob job) {
job.addPrintJobListener(new PrintJobAdapter() {
@Override
public void printJobCanceled(PrintJobEvent arg0) {
if (LOG.isWarnEnabled()) {
LOG.warn("PrintJob Job canceled.");
}
allDone();
}
@Override
public void printJobCompleted(PrintJobEvent printJobEvent) {
if (LOG.isDebugEnabled()) {
LOG.debug("PrintJob Job completed.");
}
allDone();
}
public void printJobFailed(PrintJobEvent pje) {
allDone();
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
if (LOG.isDebugEnabled()) {
LOG.debug("PrintJob Job completed (No More Events).");
}
allDone();
}
void allDone() {
synchronized (PrintJobMonitor.this) {
done = true;
PrintJobMonitor.this.notify();
}
}
});
}
public synchronized void waitForDone() {
try {
while (!done) {
wait();
}
} catch (InterruptedException e) {
}
}
}

View File

@@ -0,0 +1,40 @@
/**
*
*/
package org.springframework.integration.print.support;
import java.util.SortedSet;
import javax.print.PrintService;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.integration.print.core.PrintServiceExecutor;
import org.springframework.util.StringUtils;
/**
* @author ghillert
*
*/
public class PrintUtilsTest {
private static final Logger LOGGER = Logger.getLogger(PrintUtilsTest.class);
private PrintServiceExecutor printServiceExecutor = new PrintServiceExecutor();
/**
* Test method for {@link org.springframework.integration.print.core.PrintServiceExecutor#getAvailablePrinterServices()}.
*/
@Test
public void testGetAvailablePrinterServices() {
SortedSet<PrintService> printers = PrintServiceExecutor.getAvailablePrinterServices();
LOGGER.info("Available Printers: " + StringUtils.collectionToCommaDelimitedString(printers));
}
@Test
public void testGetPrintServiceByName() {
PrintService printService = printServiceExecutor.getPrintService();
LOGGER.info("Default Printer found: " + printService);
}
}

View File

@@ -5,4 +5,4 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.category.org.springframework.integration=WARN
log4j.category.org.springframework.integration.print=INFO
log4j.category.org.springframework.integration.print=DEBUG