??xml version="1.0" encoding="utf-8" standalone="yes"?>
q行l果:
---java.lang.management.OperatingSystemMXBean---
Arch:x86
AvailableProcessors:2
Name:Windows 2000
Version:5.0
---java.lang.management.CompilationMXBean---
TotalCompilationTime:5
Name:HotSpot Client Compiler
---java.lang.management.ClassLoadingMXBean---
LoadedClassCount:431
UnloadedClassCount:0
TotalLoadedClassCount:431
---java.lang.management.MemoryMXBean---
HeapMemoryUsage:init = 0(0K) used = 458288(447K) committed = 2031616(1984K) max = 66650112(65088K)
NonHeapMemoryUsage:init = 29556736(28864K) used = 12541248(12247K) committed = 29851648(29152K) max = 121634816(118784K)
ObjectPendingFinalizationCount:0
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@6ca1c
Name:CodeCacheManager
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@1bf216a
Name:Copy
---java.lang.management.MemoryManagerMXBean---
MemoryPoolNames:[Ljava.lang.String;@12ac982
Name:MarkSweepCompact
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:null
MemoryManagerNames:[Ljava.lang.String;@c20e24
PeakUsage:init = 196608(192K) used = 482048(470K) committed = 491520(480K) max = 33554432(32768K)
Usage:init = 196608(192K) used = 524352(512K) committed = 557056(544K) max = 33554432(32768K)
UsageThreshold:0
UsageThresholdCount:0
Name:Code Cache
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 524288(512K) used = 0(0K) committed = 0(0K) max = 4194304(4096K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@2e7263
PeakUsage:init = 524288(512K) used = 511160(499K) committed = 524288(512K) max = 4194304(4096K)
Usage:init = 524288(512K) used = 521688(509K) committed = 524288(512K) max = 4194304(4096K)
Name:Eden Space
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 65536(64K) used = 0(0K) committed = 0(0K) max = 458752(448K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@157f0dc
PeakUsage:init = 65536(64K) used = 65528(63K) committed = 65536(64K) max = 458752(448K)
Usage:init = 65536(64K) used = 65528(63K) committed = 65536(64K) max = 458752(448K)
Name:Survivor Space
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 1441792(1408K) used = 0(0K) committed = 0(0K) max = 61997056(60544K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@863399
PeakUsage:init = 1441792(1408K) used = 142120(138K) committed = 1441792(1408K) max = 61997056(60544K)
Usage:init = 1441792(1408K) used = 142120(138K) committed = 1441792(1408K) max = 61997056(60544K)
UsageThreshold:0
UsageThresholdCount:0
Name:Tenured Gen
Type:Heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 8388608(8192K) used = 0(0K) committed = 0(0K) max = 67108864(65536K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@a59698
PeakUsage:init = 8388608(8192K) used = 641040(626K) committed = 8388608(8192K) max = 67108864(65536K)
Usage:init = 8388608(8192K) used = 641040(626K) committed = 8388608(8192K) max = 67108864(65536K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 8388608(8192K) used = 0(0K) committed = 0(0K) max = 8388608(8192K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@141d683
PeakUsage:init = 8388608(8192K) used = 5601632(5470K) committed = 8388608(8192K) max = 8388608(8192K)
Usage:init = 8388608(8192K) used = 5601632(5470K) committed = 8388608(8192K) max = 8388608(8192K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen [shared-ro]
Type:Non-heap memory
---java.lang.management.MemoryPoolMXBean---
CollectionUsage:init = 12582912(12288K) used = 0(0K) committed = 0(0K) max = 12582912(12288K)
CollectionUsageThreshold:0
CollectionUsageThresholdCount:0
MemoryManagerNames:[Ljava.lang.String;@16a55fa
PeakUsage:init = 12582912(12288K) used = 5850024(5712K) committed = 12582912(12288K) max = 12582912(12288K)
Usage:init = 12582912(12288K) used = 5850024(5712K) committed = 12582912(12288K) max = 12582912(12288K)
UsageThreshold:0
UsageThresholdCount:0
Name:Perm Gen [shared-rw]
Type:Non-heap memory
]]>
通用串行ȝ(Universal Serial Bus USB)规范的第一个版本发表于 1996q?1月。因为它的低成本、高数据传输率、用容易和灉|性,USB 在计机行业里获得了q泛接受。今天,许多周边讑֤和装|都是通过 USB 接口q接到计机上的。目前,大多C般用途的操作pȝ都提供了?USB 讑֤的支持,q且?C 或?C++ 可以相对Ҏ地开发访问这些外讄应用E序。不q,Java ~程语言在设计上对硬件访问提供的支持很少Q所以编写与 USB 讑֤交互的应用程序是相当困难的?
IBM ?Dan Streetman 最早开始了?Java 语言中提供对 USB 讑֤的访问的努力?001q_他的目通过 Java 规范h(Java Specification RequestQJSR)q程被接受ؓ Java 语言的候选扩展标准。这个项目现在称?JSR-80 q且指定了官方包 javax.usb。同Ӟ?2000q?6月,Mojo Jojo ?David Brownell ?SourceForge 开始了 jUSB 目。这两个目都开发出?Linux 开发h员可以用的包,管它们都还很不完善。这两个目也都开始试囑其他操作pȝ上的 Java 应用E序提供?USB 讑֤的访问,管它们都还没有开发出可以使用的包(参阅 参考资?中有x文中讨论的这两个目及其他项目的资料)?br />
在本文中Q将?jUSB ?JSR-80 目作一个简要介l,不过Q我们首先要看一?USB 协议的具体细节,q样您就可以理解q两个项目是如何?USB 讑֤交互的。我们还提供代码片D以展示如何用这两个目?API 讉K USB 讑֤?USB 介绍
1994q_一个由四个行业伙伴(Compaq、Intel、Microsoft ?NEC)l成的联盟开始制?USB 协议。该协议最初的目的是将 PC 与电话相qƈ提供Ҏ扩展和重新配|的 I/O 接口?996q?1月,发表?USB 规范的第一个版本,1998q?9月发表了后箋版本(版本 1.1)。这个规范允?127台设备同时连接到一Pȝ通信带宽限制?12 Mbps。后来,又有三个成员(Hewlett-Packard、Lucent ?Philips)加入了这个联盟?000q?4月,发表?USB 规范?2.0版本Q它支持高达 480 Mbps 的传输率。今天,USB 在高?视频、图像、储?和全?音频、宽带、麦克风)数据传输应用中v了关键作用。它q各种低速设?键盘、鼠标、游戏外设、虚拟现实外?q接?PC 上?br />
USB 协议有严格的层次l构。在所?USB pȝ中,只有一个主讑֤Q到主计机的的 USB 接口UCؓL?host controller)。主控器有两个标??开放主控器接口(Compaq ?Open Host Controller InterfaceQOHCI)和通用L器接?Intel ?Universal Host Controller InterfaceQUHCI)。这两个标准提供了同L能力Qƈ可用于所有的 USB 讑֤QUHCI 的硬件实现更单一些,但是需要更复杂的设备驱动程?因?CPU 的负h大一??br />
USB 物理互连是分层的星Ş拓朴Q最多有七层。一?hub 是每个星形的中心QUSB L被认为是 root hub。每一D连UK?hub ?USB 讑֤的点对点q接Q后者可以是为系l提供更多附加点的另一?hubQ也可以是一个提供功能的某种讑֤。主Z用主/从协议与 USB 讑֤通信。这U方式解决了包冲H的问题Q但是同时也L了附加的讑֤彼此建立直接通信?br />
所有传输的数据都是׃控器发v的。数据从L向讑֤UCؓ下行(downstream)或者输?out)传输Q数据从讑֤向LUCؓ??upstream)或者输?in)传输。数据传输发生在L?USB 讑֤上特定的端点(endpoint) 之间Q主Z端点之间的数据链接称为管?pipe)?一个给定的 USB 讑֤可以有许多个端点Q主Z讑֤之间数据道的数量与该设备上端点的数量相同。一个管道可以是单向或者是双向的,一个管道中的数据流与所有其他管道中的数据流无关?br />
USB |络中的通信可以使用下面四种数据传输cd中的L一U:
控制传输Q?q些是一些短的数据包Q用于设备控制和配置Q特别是在设备附加到L上时?
扚w传输Q?q些是数量相对大的数据包。像扫描仪或?SCSI 适配器这L讑֤使用q种传输cd?
中断传输Q?q些是定期轮询的数据包。主控器会以特定的间隔自动发Z个中断?
{时传输Q?q些是实时的数据,它们对带宽的要求高于可靠性要求。音频和视频讑֤一般用这U传输类型?
像串行端口一P计算Z每一?USB 端口都由 USB 控制器指定了一个惟一的标识数?端口 ID)。当 USB 讑֤附加?USB 端口上时Q就这?惟一端口 ID 分配l这台设备,q且 USB 控制器会d讑֤描述W。设备描q符包括适用于该讑֤的全局信息、以及设备的配置信息。配|定义了一?USB 讑֤的功能和 I/O 行ؓ。一?USB 讑֤可以有一个或者多个配|,q由它们相应的配|描q符所描述。每一个配|都有一个或者多个接口,它可以视Z个物理通信渠道 Q每一个接口有零个或者多个端点,它可以是数据提供者或者数据消费者,或者同时具有这两种w䆾。接口由接口描述W描qͼ端点qҎq符描述。ƈ且一?USB 讑֤可能q有字符串描q符以提供像厂商名、设备名或者序列号q样的附加信息?br />
正如您所看到的,?USB q样的协议ؓ使用 Java q种q_和硬件无x的语言的开发h员提Z挑战。现在让我们看两个试图解册个问题的目?br />jUSB API
jUSB 目是由 Mojo Jojo ?David Brownell ?2000q?6月创立的。其目标是提供一l免费的、在 Linux q_上访?USB 讑֤?Java API。这?API 是按?Lesser GPL (LGPL)条款发表的,q意味着您可以在专有和免费Y仉目中使用它。这?API 提供了对多个物理 USB 讑֤的多U程讉KQƈ支持本机和远E设备。具有多个接口的讑֤可以同时被多个应用程?或者设备驱动程?所讉KQ其中每一个应用程?或者设备驱动程?都占据一个不同的接口。该 API 支持控制传输、批量传输和中断传输Q不支持{时传输Q因为等时传输用于媒体数?如音频和视频)QJMF API 已经在其他标准设备驱动程序上Ҏ提供了很好的支持(参阅 参考资?。当前,?API 可以在具?Linux 2.4 核心或者以前的 2.2.18 核心?GNU/Linux 版本上工作。因此可支持大多数最新的版本Q例如,?API 可以在没有Q何补丁或者升U的 Red Hat 7.2 ?9.0 上工作?br />
jUSB API 包括以下包:
·usb.core: q个包是 jUSB API 的核心部分。它使得 Java 应用E序可以?USB L讉K USB 讑֤?br />
·usb.linux: q个包包?usb.core.Host 对象?Linux 实现、bootstrapping 支持和其他可以提?Linux USB 支持的类。这个实现通过虚拟 USB 文gpȝ(usbdevfs)讉K USB 讑֤?br />
·usb.windows: q个包包?usb.core.Host 对象?Windows 实现、bootstrapping 支持和其他可以提?Windows USB 支持的类。这个实C然处于非常初U的阶段?br />
·usb.remote: q个包是 usb.core API 的远E版本。它包括一?RMI proxy 和一?daemon 应用E序Q它?Java 应用E序可以讉Kq程计算Z?USB 讑֤?br />
·usb.util: q个包提供了一些有用的实用E序Q可以将 firmware下蝲?USB 讑֤上、将 USB pȝ的内容{储到 XML 中、以及将只有 bulk I/O ?USB 讑֤工具转换成一个套接字(socket)?br />
·usb.devices: q个可选包攉了用 jUSB API 讉K不同 USB 讑֤?Java 代码Q包括柯达数码相机和 Rio 500 MP3 播放器。这?API l过特别~写以简化访问特?USB 讑֤的过E,q且不能用于讉K其他讑֤。这?API 是在 usb.core API 之上构徏的,它们可以工作在所有支?jUSB 的操作系l上?br />
·usb.view: q个可选包提供了基?Swing ?USB 树简单浏览器。它是一个展C?jUSB API 应用的很好的CZE序?
管 usb.core.Host 对象的实现对于不同的操作pȝ是不同的Q但?Java E序员只需要理?usb.core 包就可以?jUSB API 开始应用程序的开发。表 1 列出?usb.core 的接口和c,Java E序员应该熟悉它们:
?1. jUSB 中的接口和类接口 说明 Bus 一l?USB 讑֤q接?Host ? Host 表示h一个或者多?Bus ?USB 控制? c? 说明 Configuration 提供对设备所支持?USB 配置的访问,以及对与该配|关联的接口的访? Descriptor h USB cd的描q符的实体的基类 Device 提供?USB 讑֤的访? DeviceDescriptor 提供?USB 讑֤描述W的讉K EndPoint 提供?USB 端点描述W的讉K、在l定讑֤配置中构造设备数据输入或者输?/td> HostFactory 包含 bootstrapping Ҏ Hub 提供?USB hub 描述W以及一?hub 操作的访? Interface 描述一l端点,q与一个特定设备配|相兌 PortIdentifier ?USB 讑֤提供E_的字W串标识W,以便在操作和故障诊断时?/td>
?jUSB API 讉K一?USB 讑֤的正常过E如下:
·通过?HostFactory 得到 USB Host q行 Bootstrap?br />
·?Host 讉K USB BusQ然后从q个 Bus 讉K USB root hub(?USB Device)?br />
·得到 hub 上可用的 USB 端口数量Q遍历所有端口以扑ֈ正确?Device?br />
·讉K附加到特定端口上?USB Device。可以用一?Device ?PortIdentifier 直接?Host 讉K它,也可以通过?root hub 开始遍?USB Bus 扑ֈ它?br />
·?ControlMessage 与该 Device 直接交互Q或者从?Device 的当?Configuration 中要求一?InterfaceQƈ与该 Interface 上可用的 Endpoint q行 I/O ?
清单 1 展示了如何用 jUSB API 获得 USB pȝ中的内容。这个程序编写ؓ只是查看 root hub 上可用的 USB 讑֤Q但是很Ҏ它改ؓ遍历整个 USB 树。这里的逻辑对应于上q步?1 到步?4?br />
清单 1. ?jUSB API 获得 USB pȝ的内?br />import usb.core.*;
public class ListUSB
{
public static void main(String[] args)
{
try
{
// Bootstrap by getting the USB Host from the HostFactory.
Host host = HostFactory.getHost();
// Obtain a list of the USB buses available on the Host.
Bus[] bus = host.getBusses();
int total_bus = bus.length;
// Traverse through all the USB buses.
for (int i=0; i<total_bus; i++)
{
// Access the root hub on the USB bus and obtain the
// number of USB ports available on the root hub.
Device root = bus[i].getRootHub();
int total_port = root.getNumPorts();
// Traverse through all the USB ports available on the
// root hub. It should be mentioned that the numbering
// starts from 1, not 0.
for (int j=1; j<=total_port; j++)
{
// Obtain the Device connected to the port.
Device device = root.getChild(j);
if (device != null)
{
// USB device available, do something here.
}
}
}
} catch (Exception e)
{
System.out.println(e.getMessage());
}
}
清单 2 展示了在应用E序成功地找C Device 的条件下Q如何与 Interface ?EndPoint q行扚w I/O?q个代码D也可以修改为执行控制或者中?I/O。它对应于上q步?5?br />
清单 2. ?jUSB API 执行扚w I/O if (device != null)
{
// Obtain the current Configuration of the device and the number of
// Interfaces available under the current Configuration.
Configuration config = device.getConfiguration();
int total_interface = config.getNumInterfaces();
// Traverse through the Interfaces
for (int k=0; k<total_interface; k++)
{
// Access the currently Interface and obtain the number of
// endpoints available on the Interface.
Interface itf = config.getInterface(k, 0);
int total_ep = itf.getNumEndpoints();
// Traverse through all the endpoints.
for (int l=0; l<total_ep; l++)
{
// Access the endpoint, and obtain its I/O type.
Endpoint ep = itf.getEndpoint(l);
String io_type = ep.getType();
boolean input = ep.isInput();
// If the endpoint is an input endpoint, obtain its
// InputStream and read in data.
if (input)
{
InputStream in;
in = ep.getInputStream();
// Read in data here
in.close();
}
// If the Endpoint is and output Endpoint, obtain its
// OutputStream and write out data.
else
{
OutputStream out;
out = ep.getOutputStream();
// Write out data here.
out.close();
}
}
}
}
jUSB 目?2000q?6月到 2001q?2月期间非常活跃。该 API 的最新的版本 0.4.4发表?2001q?2?14日。从那以后只提出了很的改进Q原因可能是 IBM 组成功地成Z Java 语言的候选扩展标准。不q,Z jUSB 已经开发出一些第三方应用E序Q包?JPhoto 目(q是一个用 jUSB q接到数码照相机的应用程??jSyncManager 目(q是一个用 jUSB 与?Palm 操作pȝ?PDA 同步的应用程??br />
JSR-80 API (javax.usb)
正如前面提到的,JSR-80 目是由 IBM ?Dan Streetman ?1999q创立的?001q_q个目通过 Java 规范h(JSR)q程被接受ؓ Java 语言的候选扩展标准。这个项目现在称?JSR-80 q且被正式分z了 Java ?javax.usb。这个项目?Common Public License 的许可证形式Qƈ通过 Java Community Process q行开发。这个项目的目标是ؓ Java q_开发一?USB 接口Q可以从M Java 应用E序中完全访?USB pȝ。JSR-80 API 支持 USB 规范所定义的全部四U传输类型。目前,?API ?Linux 实现可以在支?2.4 核心的大多数最?GNU/Linux 版本上工作,?Red Hat 7.2 ?9.0?br />
JSR-80 目包括三个包:javax-usb (javax.usb API)、javax-usb-ri (操作pȝ无关的基准实现的公共部分)以及 javax-usb-ri-linux (Linux q_的基准实玎ͼ它将公共基准实现链接?Linux USB 堆栈)。所有这三个部分都是构成 Linux q_?java.usb API 完整功能所必需的。在该项目的电子邮g列表中可以看到有人正在致力于这?API UL到其他操作系l上(主要?Microsoft Windows)Q但是还没有可以工作的版本发表?br />
管 JSR-80 API 的操作系l无关的实现在不同的操作pȝ上是不同的,但是 Java E序员只需要理?javax.usb 包就可以开始开发应用程序了。表 2 列出?javax.usb 中的接口和类Q?Java E序员应该熟悉它们:
?2. JSR-80 API 中的接口和类接口 说明 UsbConfiguration 表示 USB 讑֤的配|? UsbConfigurationDescriptor USB 配置描述W的接口 UsbDevice USB 讑֤的接?/td> UsbDeviceDescriptor USB 讑֤描述W的接口 UsbEndpoint USB 端点的接? UsbEndpointDescriptor USB 端点描述W的接口 UsbHub USB hub 的接?/td> UsbInterface USB 接口的接? UsbInterfaceDescriptor USB 接口描述W的接口 UsbPipe USB 道的接? UsbPort USB 端口的接? UsbServices javax.usb 实现的接? c? 说明 UsbHostManager javax.usb 的入口点
?JSR-80 API 讉K USB 讑֤的正常过E如下:
·通过?UsbHostManager 得到相应?UsbServices q行 Bootstrap?br />
·通过 UsbServices 讉K root hub。在应用E序?root hub 是一?UsbHub?br />
·获得q接?root hub ?UsbDevices 清单。遍历所有低U?hub 以找到正的 UsbDevice?br />
·用控制消?UsbControlIrp)?UsbDevice 直接交互Q或者从 UsbDevice 的相?UsbConfiguration 中要求一?UsbInterface q与?UsbInterface 上可用的 UsbEndpoint q行 I/O?br />
·如果一?UsbEndpoint 用于q行 I/OQ那么打开与它兌?UsbPipe。通过q个 UsbPipe 可以同步或者异步提交上行数??USB 讑֤C计算?和下行数?从主计算机到 USB 讑֤)?br />
·当应用程序不再需要访问该 UsbDevice Ӟ关闭q个 UsbPipe q攄应的 UsbInterface?
在清?3 中,我们?JSR-80 API 获得 USB pȝ的内宏V这个程序递归地遍?USB pȝ上的所?USB hub q找接到L计算Z的所?USB 讑֤。这D代码对应于上述步骤 1 到步?3?br />
清单 3. ?JSR-80 API 获得 USB pȝ的内?br />import javax.usb.*;
import java.util.List;
public class TraverseUSB
{
public static void main(String argv[])
{
try
{
// Access the system USB services, and access to the root
// hub. Then traverse through the root hub.
UsbServices services = UsbHostManager.getUsbServices();
UsbHub rootHub = services.getRootUsbHub();
traverse(rootHub);
} catch (Exception e) {}
}
public static void traverse(UsbDevice device)
{
if (device.isUsbHub())
{
// This is a USB Hub, traverse through the hub.
List attachedDevices = ((UsbHub) device).getAttachedUsbDevices();
for (int i=0; i<attachedDevices.size(); i++)
{
traverse((UsbDevice) attachedDevices.get(i));
}
}
else
{
// This is a USB function, not a hub.
// Do something.
}
}
}
清单 4 展示了在应用E序成功地找?Device 后,如何?Interface ?EndPoint q行 I/O。这D代码还可以修改行所有四U数据传输类型的 I/O。它对应于上q步?4 到步?6?br />
清单 4. ?JSR-80 API q行 I/O public static void testIO(UsbDevice device)
{
try
{
// Access to the active configuration of the USB device, obtain
// all the interfaces available in that configuration.
UsbConfiguration config = device.getActiveUsbConfiguration();
List totalInterfaces = config.getUsbInterfaces();
// Traverse through all the interfaces, and access the endpoints
// available to that interface for I/O.
for (int i=0; i<totalInterfaces.size(); i++)
{
UsbInterface interf = (UsbInterface) totalInterfaces.get(i);
interf.claim();
List totalEndpoints = interf.getUsbEndpoints();
for (int j=0; j<totalEndpoints.size(); j++)
{
// Access the particular endpoint, determine the direction
// of its data flow, and type of data transfer, and open the
// data pipe for I/O.
UsbEndpoint ep = (UsbEndpoint) totalEndpoints.get(i);
int direction = ep.getDirection();
int type = ep.getType();
UsbPipe pipe = ep.getUsbPipe();
pipe.open();
// Perform I/O through the USB pipe here.
pipe.close();
}
interf.release();
}
} catch (Exception e) {}
}
JSR-80 目从一开始就非常z跃?003q?2月发表了 javax.usb API、RI ?RI ?0.10.0 版本。看hq一版本会提交给 JSR-80 委员会做最l批准。预计正式成?Java 语言的扩展标准后Q其他操作系l上的实C很快出现。Linux 开发者团体看来对 JSR-80 目的兴比 jUSB 目更大Q?Linux q_?javax.usb API 的项目数量在不断地增加?br />
l束?/b>
jUSB API ?JSR-80 API 都ؓ应用E序提供了从q行 Linux 操作pȝ的计机中访?USB 讑֤的能力。JSR-80 API 提供了比 jUSB API 更多的功能,很有可能成ؓ Java 语言的扩展标准。目前,只有 Linux 开发h员可以利?jUSB ?JSR-80 API 的功能。不q,有h正在U极地将q两U?API UL到其他操作系l上。Java 开发h员应该在不久可以在其他操作pȝ上访?USB 讑֤。从现在起就熟悉q些 APIQ当q些目可以在多个^C发挥作用Ӟ您就可以在自q应用E序中加?USB 功能了?br />
]]>
在这文章里Q来自Pro Java Programming (Apress, June 2005)专家Brett Spell解释了如何一步一步的定位打印讑֤Q创建打印工E,创徏一个Doc文档接口的实例来描述你想要打印的数据q且初始化打印。(4500字,2005q??5日)
Java自从问世以来在各斚w发展q速,但是一直以来,打印输出是java最q斚w。事实上Qjava1.0不支持Q何打印功能。Java1.1在java.awt包里包含了一个叫做PrintJob的类Q但是这个类提供的打印功能十分粗p和不可靠。当java1.2问世Q它围绕PrinterJob设计了一个完整独立的打印机制Q叫做java2D printing APIQ,q且在java.awt.print包里定义了一些新的类和接口。这些得基于PrintJob打印机制Q就是AWT printingQ基本荒废,虽然PrintJob从未被抨击而且臛_在这文章里仍然是一个提供技术的cR?br />
在J2SE1.3里当PrintJob的功能扩展到可以通过在java.awt包里的JobAttributes 和PageAttributes两个c设定工E和面的属性时发生了一些额外的改变。随着J2SE1.3的发布,打印功能相应的得C完善Q但是在混合使用q两U完全不同的打印机制的时候仍然存在一些问题。比如,q两U机制用java.awt.Graphicsq个cȝ一个接口来展现打印内容Q意味着所有要打印的东襉K必须用一张图片表C。另外,完善的PrintJob提供了很有限的工E相兛_性的讄Q这两种机制都没有办法通过E序来选择目标打印机?br />
Java打印最大的改变来自于J2SE的发布带来的Java打印服务API。这个第三代Java打印支持接口H破了先前提到的使用javax.print包的PrintService和DocPrintJob接口的局限性。因为新的API是以前两种旧的打印机制定义的功能函数的一个父集,它是目前我们常用的方法ƈ且是q篇文章的焦炏V?br />更深入来?以下的步骤包含了怎么使用q个新的Java打印服务APIQ?br />1.定义打印机,限制那些q回到提供你要实现功能的函数的列表。打印服务实CPrintService接口.
2.通过调用接口中定义的createPrintJob()Ҏ创徏一个打CӞ作ؓDocPrintJob的一个实例?br />
3.创徏一个实现Doc接口的类来描qC惌打印的数?, 你也可以创徏一个PrintRequestAttributeSet的实例来定义你想要的打印选项?br />
4.通过DocPrintJob接口定义的printv()Ҏ来初始化打印Q指定你先前创徏的DocQ指定PrintRequestAttributeSet或者设为空倹{?br />
现在你可以检查每一步ƈ且试着完成它们?br />
定义打印服务
你可以用在PrintServiceLookupcM定义的三U静态方法中的一U来定义。最单的一U就是lookupDefaultPrintService()Q正如它的名字一P它返回一个你默认的打印机Q?br />
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
虽然用这个办法很单也很方便,用它来选择你的打印机意味着用户的打印机一直都支持你的E序所要精传输的数据输出。实际上Q你真正惌的是那种可以处理你想要的数据的类型ƈ且可以支持你要的特征例如颜色或者两Ҏ印。ؓ了从列表中中q回你所要求的特D功能支持的打印机,你可以用剩下两个方法中的lookupPrintServices() 或者lookupMultiDocPrintServices()?br />
lookupPrintServices()Ҏ有两个参敎ͼ一个DocFlavor的实例和实现AttributeSet接口的实例?br />你马上将看到Q你可以使用两者中L一个来限制q回的打印机Q但是lookupPrintServices()允许你指定这两个参数为空倹{如果把两者都设ؓI,那么你得到的q回值将是Q意一个可用的打印机。在q种情况下,你ƈ不需要查看PrintService中定义的ҎQ其中一个getName()Ҏq回了一个字W串Q代表打印机的名字。你可以~译下面的代码来列出你的pȝ现有的打印机Q?br />
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (int i = 0; i < services.length; i++) {
System.out.println(services[i].getName());
}
例如你的pȝ名ؓPrintServerQ下面有Alpha, Beta, 和Gamma 打印?用以上代码可以得C下输?
\PrintServerAlpha
\PrintServerBeta
\PrintServerGamma
现在查看那些你可以传llookupPrintServices()Ҏ的参数来看看如何q回拥有Ҏ功能的打印机?br />
DocFlavor
W一个你可以指定的参数是一个DocFlavorcȝ实例Q它描述了将要打印的数据的类型和数据如何存储。在大部分情况下Qƈ不需要去创徏一个新的实例因为Java包含了很多预先定义的实例Q得你可以用它们来传给lookupPrintServices()。然而,我们q是来看一下DocFlavor的结构和Ҏ来探讨打印服务如何用这个实例?br />
创徏DocFlavor实例需要的两个参数都是字符Ԍ一个是MIME (Multipurpose Internet Mail Extensions)cd另一个是cȝ名字。MIMEcd被用于描q数据类型。例如,你要打印一个gif文gQ你需要用MIMEcd是image/gif的DocFlavor。相cMQ如果你要打印HTML文g里的文本信息要用MIMEcd似text/plain或者text/html?br />MIMEcd描述要打印的数据的cdQ表现的cd表示如何让打印服务得到这些数据。DocFlavor包含了几个静态的内部c,每一个相对应一个表现类和如何装载要打印得数据?br />
?中列Z上面提到的内部类和表现类。注意在SERVICE_FORMATTEDQ一会我会更详细地解释)旁边Q每一个和"binary"或?"character"相对应。事实上Q这些差别是Zؓ的,因ؓ"character"数据cd本n是一U特D的binarycd。这U情况下Q我们说的二q制QbinaryQ数据包括h们可以看懂的字符和一些格式化的字W比如tabsQ换行回车等。当Ӟq些差别很重要,反映出面向字W的表现cdƈ不适合存储二进制数据?br />
例如Q你不会用字W队列或者字W串来保存一个gif文gQ你也不能通过Reader接口来访问它。另一斚wQ因为字W也是一U特D的二进制数据,它完全适合储存文本信息到字节数l里或者通过InputStream或者一个URL来访问它?br />
Table 1. DocFlavor的表现类
上面定义的Q何一个静态内部类相对应一个表现类Q但是请C我说q每一个DocFlavor的实例通过一个表现类和一个MIME来确认要打印的数据的cd?br />要访问这样一个实例,你要通过?d出的内部cR例如,我们假设你要打印一个在|上通过URL讉K的gif文gQ这L话,选择表现cLjavav.net.urlQ对应的在DocFlavor中的静态类是URLcR如果你打开那个内部cȝ文档Q你会发现其实它定义了一pd静态的内部c,每一个对应一U打印机支持的MIMEcd。表2描述了在DocFlavor.URL里的内部cdMIME
Table 2. The DocFlavor.URL inner classes
因ؓ要通过URL打印gif囄Q你可以用一下代码来获得实例
DocFlavor flavor = DocFlavor.URL.GIF;
q个代码创徏了一个DocFlavor实例Q代表类是java.net.URLQMIME是image/gif?br />?列出的了DocFlavor.URL的类Q那么其他六个内部类呢?我们{下来讨Z下SERVICE_FORMATTEDQ这之前Q看看与二进制数据联pȝ所有三U类型(BYTE_ARRAY, INPUT_STREAM, and URL)相关的内部类。例如,如果你把gif储存C一个字节数l里Q那么你可以用以下代码:
DocFlavor flavor = DocFlavor.BYTE_ARRAY.GIF;
正如有三个与二进制类型关联的内部cMP与字W类型相关的另外三个cd在表3?
所以,如果你想打印储存在字W串中的文本数据Q用以下代码Q?br />
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
cMQ如果文本来自于|页上的HTML文档Q用以下代码Q?br />
DocFlavor flavor = DocFlavor.STRING.TEXT_HTML;
选择正确的打印机
q记得我们在开始关于讨论DocFlavor之前关于打印机的那个_支持你想要打印的数据cd的假讑Q这g看v来没有必要。实际上Q你会对l你的打印机所支持的文档类型感到吃惊。例如,刚提到文本类型看hg是最Ҏ支持的,所以,如果你的E序要打C个普通文本或者HTML文本Q你可以随便选择一个打印服务ƈ把它送到打印机那厅R然而大部分打印Z支持Z文本的表现类Q如果你试图向打印机发送它不支持的DocFlavorQ会产生下面的异常:
Exception in thread "main" sun.print.PrintJobFlavorException: invalid flavor
at sun.print.Win32PrintJob.print(Win32PrintJob.java:290)
at PrintTest.main(PrintTest.java:11)
现在你已l知道了如何得到一个DocFlavor的引用而且我们也讨Z选择支持q个flavor的打印机重要性,接下来我来告诉你如何定你用的打印机支持它。我先前说过lookupPrintServices()允许你指定一个DocFlavor作ؓW一个参敎ͼ如果你指定的参数非空Q那么方法会q回相应支持q个的打印机的实例。例如以下代码将q回可以通过URL来打印gif文g的打印机的列表:
DocFlavor flavor = DocFlavor.URL.GIF;
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
另外Q如果你的程序已l获得了打印服务的实例,而你想知道它是否支持另一U特定的flavorQ你可以调用isDocFlavorSupported()Ҏ。在下面的代码里Q将得到一个默认打印机的引用,如果不能打印gif׃出现错误信息Q?br />
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocFlavor flavor = DocFlavor.URL.GIF;
if (!service.isDocFlavorSupported(flavor)) {
System.err.println("The printer does not support the appropriate DocFlavor");
}
AttributeSet
正如你看到的QDocFlavor描述打印数据而且可以用来定打印服务是否支持q种数据。然而,你的E序需要选择一个基于那些支持的元素的打印机。例如,你要打印囄用不同的颜色来描qC同的信息Q你想知道提供的服务是否支持彩色打印Q如果不Q那么要么禁止它使用或者要求提供一个黑白图片?br />
cM彩色打印Q两Ҏ印或者用不同的定位取决于打印机本n的属性,而javax.print.attribute包包含了许多你可以用于描q这些属性的包和接口。其中一个接口是前面提到的lookupPrintServices()中第二个参数AttributeSet。正如你愿,它返回属性的集合Q在调用lookupPrintServices()指定一个不为空的值将q回支持q些属性的打印服务。换句话_如果DocFlavor?AttributeSet都不为空Q那么方法将q回那些q两U属性都支持的打印机
Attribute
AttributeSet 是属性的集合,一个显而易见的问题是如何指定属性的值呢Q?javax.print.attribute包里同时含有一个叫Attribute的接口,你马上可以看到通过调用addҎ来给AttributeSet创徏一个Attribute实例来获得这个集合。在javax.print.attribute.standard包里定义了大量你要用到的接口。在之前Q你可以查看javax.print.attributeq个包里的其他接口?br />
属性模?/b>
目前为止Q我们把属性描q成打印服务的功能,而实际上在java支持的属性中很单的。对应每个属性,java都有相应的模块。只有遵循这些模块属性才有效。在不同的java打印服务位置使用不同的属性,而不是所有的属性在M地方都适用?br />Z更好的理解这个,来看一下javax.print.attribute.standard 包里定义?br />OrientationRequested?ColorSupported接口。创Z个新的打印文档时可以指定OrientationRequested属性和用于打印的定位。ColorSupported在你调用PrintService接口的getAttributesҎ时返回。OrientationRequested是一个你用来传给打印机的属性,而ColorSupported是打印服务用来提供给你关于打印机能力信息的工兗你可以在创建打印文档时把ColorSupported作ؓ属性指定,因ؓ打印机是否支持彩色打印是你的E序不能控制的?br />
接口和?/b>
你第一ơ查看javax.print.attribute包里的接口和cL你也怼感到选择那些列表里的接口和类很麻烦。除了Attribute 和AttributeSet和承AttributeSet的HashAttributeSetQjavax.print.attribute包里?个子接口和类Q列出在?和图1中?br />
Table 4. javax.print.attribute 里定义的接口和类 Figure 1. javax.print.attribute 包的一部分cȝ层次l构.
那么有了Attribute, AttributeSet, ?HashAttributeSetZ么需要用这些不同的接口和承类呢?是因些特D的cL为那些特D的属性量w定做的。比方说Q我提到q当你创建打印文档的时候有个地方可以用的属性例如ColorSupported在那里不能用。当创徏q样的文档,你可以用DocAttributeSet接口Q或者更专业一点,HashDocAttributeSetq个l承的类Q,q个l承cd允许你添加承DocAttributeq个接口的属性。这四种不同的模块如下:
PrintRequest: 初始化打印时传给d的请?
PrintService:由打印服 务q回来描q打印机的功?br />
要知道如何工作,我们来创Z个DocAttributeSet的实例然后ؓAttributeSet讄DocAttributeSet和OrientationRequested属性。HashDocAttributeSet定义了很好的l构Q所有你可以很简便的如下创徏实例Q?br />
DocAttributeSet attrs = new HashDocAttributeSet();
现在你已l创ZAttributeSetQ你可以调用addҎq把它传lAttribute的承实例去。如果你看了OrientationRequestedq个cȝ文档Q你会发现它包含了一pd静态的OrientationRequest实例Q每一个对应一U文档定位方式。要指定你想要的cdQ你所要做的只是按下面的方法传laddҎ一个静态的实例的引用:
DocAttributeSet attrs = new HashDocAttributeSet();
attrs.add(OrientationRequested.PORTRAIT);
ColorSupportedcL一点不同但一样很单,它定义了两种静态实?一个表C支持彩色打印另一个不是。你可以试着增加一个ColorSupported属性到DocAttributeSet去,代码如下Q?br />
DocAttributeSet attrs = new HashDocAttributeSet();
attrs.add(OrientationRequested.PORTRAIT);
attrs.add(ColorSupported.SUPPORTED);
早先提过Q去指定是否支持彩色打印不恰当因不是E序所能控制的内容。换句话_ColorSupportedq个属性放Cpd文档属性中q不合适,所以,q行先前的代码当dColorSupported属性时会抛Z个ClassCastException异常?br />
要学习怎么q行Q记住每一个AttributeSet子接口都有一个相应Attribute子接口和l承子类。当d一个属性时Q承的子类试图把Attribute作ؓ参数l相应的子接口,q样来确保只有当前适当的属性会成功d?br />
q样的话QHashDocAttributeSet 的addҎW一ơ和OrientationRequested的一个实例一赯用,q成功的把它作ؓ一个object传给DocAttribute。因为如?所C,OrientationRequestedl承了那个接口。与之相对应Q传ColorSupported实例的时候因为没有承DocAttribute所以失败了?br />
Figure 2. javax.print.attribute 包的一部分cȝ层次l构
q个例子举例说明Q表4里的四个接口和类l来保证使用正确的属性。注意模块和不同的属性之间有大量的交互,所以很多属性与不止一个模块关联。例如,许多属性承了PrintJobAttribute ?PrintRequestAttribute因ؓ大部分是通过一个相关的打印d获得提供l你的。你可以在初始化时指定它们。D个例子,你可以把它加到PrintRequestAttributeSet中去来指定Q务名Qƈ且在打印的时候通过PrintJobAttributeSet来返回它。因此,JobName属性类同时l承
PrintRequestAttribute ?PrintJobAttribute?br />AttributeSet and HashAttributeSet
你已l知道了Z么会有四个子c,但是AttributeSet接口和HashAttributeSet父类又是什么呢QAttributeSet/HashAttributeSet在你不能定要存储在q个集合中的那些仅仅和一个模块相关的属性时使用。记得我以前提到的lookupPrintServices()Ҏ允许你指定AttributeSet参数来限制返回的打印服务。表面上看来最好指定PrintServiceAttributeSet的实例,但是很多你可能用到的属性ƈ不承PrintServiceAttribute?br />
我们假设你想要让lookupPrintServices()Ҏq回支持彩色打印和风景画打印的打印机。这些属性与ColorSupported和OrientationRequested属性关联,但是h意这些类q不׃n模块Q前者是一个PrintServiceAttribute而OrientationRequested与另外三个模?Doc, PrintRequest,?PrintJob)兌。这意味着不存在单个的AttributeSet接口或类来同时包含ColorSupported和Sides属性?br />
创徏AttributeSet的方法用一个HashAttributeSet实例同时包含一个OrientationRequested ?ColorSupported太简单了。不像它的子c,它ƈ不限制你往上加Ҏ的属性,所以可以用以下代码成功执行Q?br />
AttributeSet attrs = new HashAttributeSet();
attrs.add(ColorSupported.SUPPORTED);
attrs.add(OrientationRequested.LANDSCAPE);
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, attrs);
通过用户界面的打印机选择
此观点而言Q我认ؓ使用的打印机应该由应用程序计划选择。但操作q程中,打印输出内容时往往会显CZ个对话框让用户选择。幸q的是,Java通过使用ServiceUIc(在javax.print包中定义Q中的静态printDialog()Ҏ使得q些操作单化?br />在显C的对话框旁边,仅在调用printDialog()时必L定的参数值如下:
用户可选用的PrintService实例数组?br />默认的PrintService?br />PrintRequestAttributeSet实例。这用来弹出昄的对话框Qƈ在对话框消失之前q回用户所作的M更改?br />要解释这些如何运作,可用下列简单的代码D|昄打印对话Q?br />
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
PrintService svc = PrintServiceLookup.lookupDefaultPrintService();
PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
PrintService selection = ServiceUI.printDialog(
null, 100, 100, services, svc, null, attrs);
q行Ӟ代码产生如图?中所C的对话?br />
Figure 3. The printer dialog
随着代码的说明,从printDialog()Ҏq回的值是一个PrintService实例Q识别用h选的打印机,或在用户取消打印机对话时识别为空。此外,PrintRequestAttributeSet已更新到可通过对话框来反映用户作出的更改,比如要打印的份数?br />通过使用printDialog()ҎQ可让用户选择其输发往的打印机Q提供用户对于专业应用程序的期望功能?br />
q是打印中的一个简单步骤;因ؓ一旦获得PrintService的一个参考,你需要做的就是调用createPrintJob()ҎQ如Q?br />
PrintService service;
.
.
.
DocPrintJob job = service.createPrintJob();
代码中显C,从createPrintJob()q回的值是一个DocPrintJob实例Q可让您控制q监控打印操作的状态。要启动打印Q您会调用DocPrintJob对象的print()ҎQ但是,q之前,您需要定义待打印的文档或选用PrintRequestAttributeSe。您已经知道如何构造ƈ弹出AttributeSetQ这个步骤不再重复,接下来,您将了解定义待打印的文档?br />
定义要打印的文档
接下来这一步是定义要打印的文档Q用一个在javax.print包里的Doc的接口实例来创徏。每一个Doc的实例有两个必须定义的属性和一个可选择的属性:
Object 代表要打印的内容
DocFlavor的一个实例描q数据类?br /> 可选的DocAttributeSet 包含打印时的属?br />
复习Doc接口的文档可以看出javax.print包里包含了一个叫SimpleDoc 的接口的l承Q它的构造函数包含了上面三个参数。要知道如何构徏SimpleDoc 的实例,我们假设你要打印两䆾存在http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif的gif文g拯?br />我们要做的就是构Z个SimpleDoc实例来描q这个文档创Z一个URL来指向图片,q且引用了DocFlavorQƈ把这两个传给SimpleDoc构造函敎ͼ
URL url = new URL(
"http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif");
DocFlavor flavor = DocFlavor.URL.GIF;
SimpleDoc doc = new SimpleDoc(url, flavor, null);
启动打印
打印的最后一个步骤就是调用DocPrintJob?print()ҎQ传递待打印数据的Doc对象Q或选用PrintRequestAttributeSet实例。ؓ单v见,假设默认打印机支持你所需要的flavor和属性,在此情况下要使用下列代码上一个例子提及的gif文g打印两䆾Q?br />
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
DocPrintJob job = service.createPrintJob();
URL url = new URL(
"http://www.apress.com/ApressCorporate/supplement/1/421/bcm.gif ");
DocFlavor flavor = DocFlavor.URL.GIF;
Doc doc = new SimpleDoc(url, flavor, null);
PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
attrs.add(new Copies(2));
job.print(doc, attrs)
;
注意Q一些情况下Q打C同步执行Q这可能会在实际打印完成之前q回对print()的调用?br />
关于作?br />Brett Spell是一个Frito-Lay的高U程序开发者ƈ写了Pro Java Programming 的初始版本?
资源
q是Pro Java Programming, Second Edition, Brett Spell (Apress, June 2005; ISBN: 1590594746):W十章“打印”的一部分 http://www.apress.com/book/bookDisplay.html?bID=421
要得到更多关于java API的文章,点击以下链接
http://www.javaworld.com/channel_content/jw-apis-index.shtml
![]() 图一 JAAS概览 |
LoginContext lc = new LoginContext("MyExample"); try { lc.login(); } catch (LoginException) { // Authentication failed. } // Authentication successful, we can now continue. // We can use the returned Subject if we like. Subject sub = lc.getSubject(); Subject.doAs(sub, new MyPrivilegedAction()); |
Application { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ... }; Application { ModuleClass Flag ModuleOptions; ... }; ... |
Sample { com.sun.security.auth.module.NTLoginModule Rquired debug=true; } |
![]() 图二 JAAS的配|文? |
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; url = (String)options.get("url"); driverClass = (String)options.get("driver"); debug = "true".equalsIgnoreCase((String)options.get("debug")); } |
Example { RdbmsLoginModule required driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://localhost/jaasdb?user=root" debug="true"; }; |
ConsoleCallbackHandler cbh = new ConsoleCallbackHandler(); LoginContext lc = new LoginContext("Example", cbh); lc.login(); |
public boolean login() throws LoginException { if (callbackHandler == null) throw new LoginException("no handler"); NameCallback nameCb = new NameCallback("user: "); PasswordCallback passCb = new PasswordCallback("password: ", true); callbacks = new Callback[] { nameCb, passCb }; callbackHandler.handle(callbacks); String username = nameCb.getName(); String password = new String(passCb.getPassword()); success = rdbmsValidate(username, password); return(true); } |
String user = request.getParameter("user"); String pass = request.getParameter("pass"); PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass); LoginContext lc = new LoginContext("Example", cbh); |
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i Q?callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nameCb = (NameCallback)callbacks[i]; nameCb.setName(user); } else if(callbacks[i] instanceof PasswordCallback) { PasswordCallback passCb = (PasswordCallback)callbacks[i]; passCb.setPassword(pass.toCharArray()); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); } } } } |
Qsystem-property java.security.auth.login.config="/resin/conf/jaas.config"/Q? |
![]() 图一 JAAS概览 |
LoginContext lc = new LoginContext("MyExample"); try { lc.login(); } catch (LoginException) { // Authentication failed. } // Authentication successful, we can now continue. // We can use the returned Subject if we like. Subject sub = lc.getSubject(); Subject.doAs(sub, new MyPrivilegedAction()); |
Application { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ... }; Application { ModuleClass Flag ModuleOptions; ... }; ... |
Sample { com.sun.security.auth.module.NTLoginModule Rquired debug=true; } |
![]() 图二 JAAS的配|文? |
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; url = (String)options.get("url"); driverClass = (String)options.get("driver"); debug = "true".equalsIgnoreCase((String)options.get("debug")); } |
Example { RdbmsLoginModule required driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://localhost/jaasdb?user=root" debug="true"; }; |
ConsoleCallbackHandler cbh = new ConsoleCallbackHandler(); LoginContext lc = new LoginContext("Example", cbh); lc.login(); |
public boolean login() throws LoginException { if (callbackHandler == null) throw new LoginException("no handler"); NameCallback nameCb = new NameCallback("user: "); PasswordCallback passCb = new PasswordCallback("password: ", true); callbacks = new Callback[] { nameCb, passCb }; callbackHandler.handle(callbacks); String username = nameCb.getName(); String password = new String(passCb.getPassword()); success = rdbmsValidate(username, password); return(true); } |
String user = request.getParameter("user"); String pass = request.getParameter("pass"); PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass); LoginContext lc = new LoginContext("Example", cbh); |
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i Q?callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nameCb = (NameCallback)callbacks[i]; nameCb.setName(user); } else if(callbacks[i] instanceof PasswordCallback) { PasswordCallback passCb = (PasswordCallback)callbacks[i]; passCb.setPassword(pass.toCharArray()); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); } } } } |
Qsystem-property java.security.auth.login.config="/resin/conf/jaas.config"/Q? |
![]() 图一 JAAS概览 |
LoginContext lc = new LoginContext("MyExample"); try { lc.login(); } catch (LoginException) { // Authentication failed. } // Authentication successful, we can now continue. // We can use the returned Subject if we like. Subject sub = lc.getSubject(); Subject.doAs(sub, new MyPrivilegedAction()); |
Application { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ... }; Application { ModuleClass Flag ModuleOptions; ... }; ... |
Sample { com.sun.security.auth.module.NTLoginModule Rquired debug=true; } |
![]() 图二 JAAS的配|文? |
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; url = (String)options.get("url"); driverClass = (String)options.get("driver"); debug = "true".equalsIgnoreCase((String)options.get("debug")); } |
Example { RdbmsLoginModule required driver="org.gjt.mm.mysql.Driver" url="jdbc:mysql://localhost/jaasdb?user=root" debug="true"; }; |
ConsoleCallbackHandler cbh = new ConsoleCallbackHandler(); LoginContext lc = new LoginContext("Example", cbh); lc.login(); |
public boolean login() throws LoginException { if (callbackHandler == null) throw new LoginException("no handler"); NameCallback nameCb = new NameCallback("user: "); PasswordCallback passCb = new PasswordCallback("password: ", true); callbacks = new Callback[] { nameCb, passCb }; callbackHandler.handle(callbacks); String username = nameCb.getName(); String password = new String(passCb.getPassword()); success = rdbmsValidate(username, password); return(true); } |
String user = request.getParameter("user"); String pass = request.getParameter("pass"); PassiveCallbackHandler cbh = new PassiveCallbackHandler(user, pass); LoginContext lc = new LoginContext("Example", cbh); |
public void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException { for (int i = 0; i Q?callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nameCb = (NameCallback)callbacks[i]; nameCb.setName(user); } else if(callbacks[i] instanceof PasswordCallback) { PasswordCallback passCb = (PasswordCallback)callbacks[i]; passCb.setPassword(pass.toCharArray()); } else { throw(new UnsupportedCallbackException(callbacks[i], "Callback class not supported")); } } } } |
Qsystem-property java.security.auth.login.config="/resin/conf/jaas.config"/Q? |