ch.ethz.vppserver.ippclient.IppResponse Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cups4j Show documentation
Show all versions of cups4j Show documentation
Java printing library for CUPS/IPP
package ch.ethz.vppserver.ippclient;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
import org.cups4j.ipp.attributes.Attribute;
import org.cups4j.ipp.attributes.AttributeGroup;
import org.cups4j.ipp.attributes.AttributeValue;
import org.cups4j.ipp.attributes.SetOfEnum;
import org.cups4j.ipp.attributes.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Copyright (C) 2008 ITS of ETH Zurich, Switzerland, Sarah Windler Burri
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details. You should have
* received a copy of the GNU Lesser General Public License along with this
* program; if not, see .
*/
public class IppResponse {
private static final Logger LOG = LoggerFactory.getLogger(IppResponse.class);
private final static String CRLF = "\r\n";
// Saved list of elements of 'TAG_LIST_FILENAME' and 'ATTRIBUTE_LIST_FILENAME'
private List _tagList = null;
private List _attributeGroupList = null;
private static final int BYTEBUFFER_CAPACITY = 8192;
// Saved response of printer
private AttributeGroup _attributeGroupResult = null;
private Attribute _attributeResult = null;
private List _result = null;
private static IIppAttributeProvider ippAttributeProvider = null;
// read IPP response in global buffer
ByteBuffer _buf = null;
public IppResponse() {
ippAttributeProvider = IppAttributeProviderFactory.createIppAttributeProvider();
_tagList = ippAttributeProvider.getTagList();
_attributeGroupList = ippAttributeProvider.getAttributeGroupList();
_result = new ArrayList();
_buf = ByteBuffer.allocate(BYTEBUFFER_CAPACITY);
}
/**
*
* @param channel
* @return
* @throws IOException
*/
public IppResult getResponse(SocketChannel channel) throws IOException {
if (channel == null) {
LOG.error("IppResponse.getResponse(): no channel given");
return null;
}
_buf.clear();
_attributeGroupResult = null;
_attributeResult = null;
_result.clear();
IppResult result = new IppResult();
boolean httpResponse = false;
boolean ippHeaderResponse = false;
// be careful: HTTP and IPP could be transmitted in different set of
// buffers.
// see RFC2910, http://www.ietf.org/rfc/rfc2910, page 19
ByteBuffer tmpBuffer = ByteBuffer.allocate(BYTEBUFFER_CAPACITY);
ArrayList bufferList = new ArrayList();
while (channel.read(tmpBuffer) != -1) {
tmpBuffer.flip();
// read HTTP header
if ((!httpResponse) && (tmpBuffer.hasRemaining())) {
_buf = tmpBuffer;
result.setHttpStatusResponse(getHTTPHeader());
httpResponse = true;
}
// read IPP header
if ((!ippHeaderResponse) && (tmpBuffer.hasRemaining())) {
_buf = tmpBuffer;
result.setIppStatusResponse(getIPPHeader());
ippHeaderResponse = true;
}
// read the IPP-answer - this can be large, so take to read all
// information
if (tmpBuffer.hasRemaining()) {
bufferList.add(tmpBuffer);
}
tmpBuffer = ByteBuffer.allocate(BYTEBUFFER_CAPACITY);
}
_buf = concatenateBytebuffers(bufferList);
// read attribute group list with attributes
getAttributeGroupList();
closeAttributeGroup();
result.setAttributeGroupList(_result);
return result;
}
/**
*
* @param channel
* @return
* @throws IOException
*/
public IppResult getResponse(ByteBuffer buffer) throws IOException {
_buf.clear();
_attributeGroupResult = null;
_attributeResult = null;
_result.clear();
IppResult result = new IppResult();
boolean ippHeaderResponse = false;
// be careful: HTTP and IPP could be transmitted in different set of
// buffers.
// see RFC2910, http://www.ietf.org/rfc/rfc2910, page 19
// read IPP header
if ((!ippHeaderResponse) && (buffer.hasRemaining())) {
_buf = buffer;
if (buffer.get(0) > 0x20) {
return parseErrorText();
} else {
result.setIppStatusResponse(getIPPHeader());
ippHeaderResponse = true;
}
}
_buf = buffer;
// read attribute group list with attributes
getAttributeGroupList();
closeAttributeGroup();
result.setAttributeGroupList(_result);
return result;
}
/**
* concatenate nio-ByteBuffers
*
* @param buffers
* ArrayList
* @return ByteBuffer
*/
private ByteBuffer concatenateBytebuffers(ArrayList buffers) {
int n = 0;
for (ByteBuffer b : buffers)
n += b.remaining();
ByteBuffer buf = (n > 0 && buffers.get(0).isDirect()) ? ByteBuffer.allocateDirect(n) : ByteBuffer.allocate(n);
if (n > 0)
buf.order(buffers.get(0).order());
for (ByteBuffer b : buffers)
buf.put(b.duplicate());
buf.flip();
return buf;
}
/**
*
* @return
*/
private String getHTTPHeader() {
String endOf = CRLF + CRLF;
StringBuffer sb = new StringBuffer();
while (sb.indexOf(endOf) == -1) {
int b = _buf.get();
int ival = ((int) b) & 0xff;
char c = (char) ival;
sb.append(c);
}
if (sb.length() != 0) {
return sb.toString();
}
return null;
}
/**
*
* @return
*/
private String getIPPHeader() {
StringBuffer sb = new StringBuffer();
sb.append("Major Version:" + IppUtil.toHexWithMarker(_buf.get()));
sb.append(" Minor Version:" + IppUtil.toHexWithMarker(_buf.get()));
String statusCode = IppUtil.toHexWithMarker(_buf.get()) + IppUtil.toHex(_buf.get());
String statusMessage = getEnumName(statusCode, "status-code");
sb.append(" Request Id:" + _buf.getInt() + "\n");
sb.append("Status Code:" + statusCode + "(" + statusMessage + ")");
if (sb.length() != 0) {
return sb.toString();
}
return null;
}
private IppResult parseErrorText() {
IppResult result = new IppResult();
byte[] buffer = new byte[_buf.capacity() - _buf.position()];
_buf.get(buffer);
String errorText = new String(buffer);
if (errorText.contains("Unauthorized")) {
result.setIppStatusResponse("client-error-not-authorized (0x403)");
} else {
result.setIppStatusResponse("unknown");
}
LOG.warn(errorText);
return result;
}
/**
*
* Note: Global variables _attributeGroupResult
,
* _attributeResult
, _result
are filled by local
* 'tag' methods.
* Decision for this programming solution is based on the structure of IPP tag
* sequences to clarify the attribute structure with its values.
*
*
* @return list of attributes group
*/
private List getAttributeGroupList() {
while (_buf.hasRemaining()) {
byte tag = _buf.get();
switch (tag) {
case 0x00:
setAttributeGroup(tag); // reserved
continue;
case 0x01:
setAttributeGroup(tag); // operation-attributes
continue;
case 0x02:
setAttributeGroup(tag); // job-attributes
continue;
case 0x03:
return _result; // end-attributes
case 0x04:
setAttributeGroup(tag); // printer-attributes
continue;
case 0x05:
setAttributeGroup(tag); // unsupported-attributes
continue;
case 0x06:
setAttributeGroup(tag); // subscription-attributes
continue;
case 0x07:
setAttributeGroup(tag); // event-notification-attributes
continue;
case 0x13:
setNoValueAttribute(tag); // no-value
continue;
case 0x21:
setIntegerAttribute(tag); // integer
continue;
case 0x22:
setBooleanAttribute(tag); // boolean
continue;
case 0x23:
setEnumAttribute(tag); // enumeration
continue;
case 0x30:
setTextAttribute(tag); // octetString;
continue;
case 0x31:
setDateTimeAttribute(tag);// datetime
continue;
case 0x32:
setResolutionAttribute(tag);// resolution
continue;
case 0x33:
setRangeOfIntegerAttribute(tag);// rangeOfInteger
continue;
case 0x35:
setTextWithLanguageAttribute(tag); // textWithLanguage
continue;
case 0x36:
setNameWithLanguageAttribute(tag); // nameWithLanguage
continue;
case 0x41:
setTextAttribute(tag); // textWithoutLanguage
continue;
case 0x42:
setTextAttribute(tag); // nameWithoutLanguage
continue;
case 0x44:
setTextAttribute(tag); // keyword
continue;
case 0x45:
setTextAttribute(tag); // uri
continue;
case 0x46:
setTextAttribute(tag); // uriScheme
continue;
case 0x47:
setTextAttribute(tag); // charset
continue;
case 0x48:
setTextAttribute(tag); // naturalLanguage
continue;
case 0x49:
setTextAttribute(tag); // mimeMediaType
continue;
default:
return _result; // not defined
}
}
return null;
}
/**
*
* @param tag
*/
private void setAttributeGroup(byte tag) {
if (_attributeGroupResult != null) {
if (_attributeResult != null) {
_attributeGroupResult.getAttribute().add(_attributeResult);
}
_result.add(_attributeGroupResult);
}
_attributeResult = null;
_attributeGroupResult = new AttributeGroup();
_attributeGroupResult.setTagName(getTagName(IppUtil.toHexWithMarker(tag)));
}
/**
*
*/
private void closeAttributeGroup() {
if (_attributeGroupResult != null) {
if (_attributeResult != null) {
_attributeGroupResult.getAttribute().add(_attributeResult);
}
_result.add(_attributeGroupResult);
}
_attributeResult = null;
_attributeGroupResult = null;
}
/**
*
* @param tag
*/
private void setTextAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
byte[] dst = new byte[length];
_buf.get(dst);
String value = IppUtil.toString(dst);
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
* TODO: natural-language not considered in reporting
*
* @param tag
*/
private void setTextWithLanguageAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set natural-language and attribute value
if (!_buf.hasRemaining()) {
return;
}
// set tag, tag name, natural-language
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
byte[] dst = new byte[length];
_buf.get(dst);
String value = IppUtil.toString(dst);
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
// set value
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
dst = new byte[length];
_buf.get(dst);
value = IppUtil.toString(dst);
attrValue = new AttributeValue();
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
}
}
}
/**
* TODO: natural-language not considered in reporting
*
* @param tag
*/
private void setNameWithLanguageAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set natural-language and attribute value
if (!_buf.hasRemaining()) {
return;
}
// set tag, tag name, natural-language
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
byte[] dst = new byte[length];
_buf.get(dst);
String value = IppUtil.toString(dst);
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
// set value
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
dst = new byte[length];
_buf.get(dst);
value = IppUtil.toString(dst);
attrValue = new AttributeValue();
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
}
}
}
/**
*
* @param tag
*/
private void setBooleanAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
byte value = _buf.get();
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(IppUtil.toBoolean(value));
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param tag
*/
private void setDateTimeAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
byte[] dst = new byte[length];
_buf.get(dst, 0, length);
String value = IppUtil.toDateTime(dst);
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(value);
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param tag
*/
private void setIntegerAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
int value = _buf.getInt();
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(Integer.toString(value));
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param tag
*/
private void setNoValueAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
}
/**
*
* @param tag
*/
private void setRangeOfIntegerAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
int value1 = _buf.getInt();
int value2 = _buf.getInt();
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(Integer.toString(value1) + "," + Integer.toString(value2));
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param tag
*/
private void setResolutionAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
int value1 = _buf.getInt();
int value2 = _buf.getInt();
byte value3 = _buf.get();
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
attrValue.setValue(Integer.toString(value1) + "," + Integer.toString(value2) + "," + Integer.toString(value3));
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param tag
*/
private void setEnumAttribute(byte tag) {
short length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
setAttributeName(length);
}
// set attribute value
if (!_buf.hasRemaining()) {
return;
}
length = _buf.getShort();
if ((length != 0) && (_buf.remaining() >= length)) {
String hex = IppUtil.toHexWithMarker(tag);
AttributeValue attrValue = new AttributeValue();
attrValue.setTag(hex);
String tagName = getTagName(hex);
attrValue.setTagName(tagName);
int value = _buf.getInt();
if (_attributeResult != null) {
String enumName = getEnumName(value, _attributeResult.getName());
attrValue.setValue(enumName);
} else {
_attributeResult = new Attribute();
_attributeResult.setName("no attribute name given:");
attrValue.setValue(Integer.toString(value));
}
_attributeResult.getAttributeValue().add(attrValue);
}
}
/**
*
* @param length
*/
private void setAttributeName(short length) {
if ((length == 0) || (_buf.remaining() < length)) {
return;
}
byte[] dst = new byte[length];
_buf.get(dst);
String name = IppUtil.toString(dst);
if (_attributeResult != null) {
_attributeGroupResult.getAttribute().add(_attributeResult);
}
_attributeResult = new Attribute();
_attributeResult.setName(name.toString());
}
/**
*
* @param tag
* @return
*/
private String getTagName(String tag) {
if (tag == null) {
LOG.error("IppResponse.getTagName(): no tag given");
return null;
}
int l = _tagList.size();
for (int i = 0; i < l; i++) {
if (tag.equals(_tagList.get(i).getValue())) {
return _tagList.get(i).getName();
}
}
return "no name found for tag:" + tag;
}
/**
*
* @param value
* @param nameOfAttribute
* @return
*/
private String getEnumName(String value, String nameOfAttribute) {
if (value == null) {
LOG.error("IppResponse.getEnumName(String,String): value is null");
return null;
}
if (nameOfAttribute == null) {
LOG.error("IppResponse.getEnumName(String,String): nameOfAttribute is null");
return null;
}
int enumValue = 0;
if (value.contains("0x")) {
value = value.replace("0x", "");
;
enumValue = Integer.parseInt(value, 16);
} else {
enumValue = Integer.parseInt(value, 10);
}
return getEnumName(enumValue, nameOfAttribute);
}
/**
*
* @param value
* @nameOfAttribute
* @return
*/
private String getEnumName(int value, String nameOfAttribute) {
if (nameOfAttribute == null) {
LOG.error("IppResponse.getEnumName(int,String): nameOfAttribute is null");
return null;
}
int l = _attributeGroupList.size();
for (int i = 0; i < l; i++) {
AttributeGroup attributeGroup = _attributeGroupList.get(i);
List attributeList = attributeGroup.getAttribute();
int ll = attributeList.size();
for (int j = 0; j < ll; j++) {
Attribute attribute = attributeList.get(j);
String attributeName = attribute.getName();
if ((attributeName != null) && (attributeName.equals(nameOfAttribute))) {
List attributeValueList = attribute.getAttributeValue();
int lll = attributeValueList.size();
for (int z = 0; z < lll; z++) {
AttributeValue attributeValue = attributeValueList.get(z);
if (attributeValue.getSetOfEnum() != null) {
SetOfEnum setOfEnum = attributeValue.getSetOfEnum();
List enumList = setOfEnum.getEnum();
int llll = enumList.size();
for (int w = 0; w < llll; w++) {
org.cups4j.ipp.attributes.Enum enumEntry = enumList.get(w);
String enumValueString = enumEntry.getValue();
int enumValue = 0;
// some IPP enumerations are in hex, other decimal
// see http://www.iana.org/assignments/ipp-registrations for
// reference
if (enumValueString.contains("0x")) {
enumValueString = enumValueString.replace("0x", "");
;
enumValue = Integer.parseInt(enumValueString, 16);
} else {
enumValue = Integer.parseInt(enumValueString, 10);
}
if (value == enumValue) {
return enumEntry.getName();
}
}
} else {
LOG.error("IPPResponse.getEnumName(): " + "set-of-enum is null for attribute " + attributeName
+ ". Please control " + "the enumeration list in the XML file");
return null;
}
}
}
}
}
return "enum name not found in IANA list: " + value;
}
}