Advanced Java Programming - ITCourseware

118 downloads 747 Views 3MB Size Report
No part of this book may be reproduced or ... ADVANCED JAVA PRoGRAmmiNG ... workbook, including the many students who have offered comments, ...
Advanced Java Programming

Copyright © 2011 by ITCourseware, LLC. All rights reserved. No part of this book may be reproduced or utilized in any form by any means, electronic or mechanical, including photo-copying, recording, or by an information storage retrieval system, without permission in writing from the publisher. Inquiries should be addressed to ITCourseware, LLC., 7245 South Havana Street, Suite 100, Centennial, CO 80112. (303) 3025280. All brand names, product names, and registered trademarks are the property of their respective owners.

Advanced Java Programming Student Workbook

Advanced Java Programming

Advanced Java Programming Contributing Authors: John Crabtree, Julie Johnson, Mike Naseef, Jamie Romero, and Rob Seitz Published by ITCourseware, LLC., 7245 South Havana Street, Suite 100, Centennial, CO 80112 Editors: Danielle Hopkins and Jan Waleri Editorial Staff: Danielle North Special thanks to: Many instructors whose ideas and careful review have contributed to the quality of this workbook, including the many students who have offered comments, suggestions, criticisms, and insights.

Copyright © 2011 by ITCourseware, LLC. All rights reserved. No part of this book may be reproduced or utilized in any form or by any means, electronic or mechanical, including photo-copying, recording, or by an information storage retrieval system, without permission in writing from the publisher. Inquiries should be addressed to ITCourseware, LLC., 7245 South Havana Street, Suite 100, Centennial, Colorado, 80112. (303) 302-5280. All brand names, product names, trademarks, and registered trademarks are the property of their respective owners.

Page ii

Rev 5.1.4

© 2011 ITCourseware, LLC

Advanced Java Programming

Contents Chapter 1 - Course Introduction ............................................................................................................. 11 Course Objectives ............................................................................................................................ 12 Course Overview .............................................................................................................................. 14 Using the Workbook ......................................................................................................................... 15 Suggested References ....................................................................................................................... 16 Chapter 2 - Advanced I/O — Object Serialization .................................................................................. 19 What is Serialization? ........................................................................................................................ 20 Serializable Objects........................................................................................................................... 22 Writing an Object .............................................................................................................................. 24 Reading an Object ............................................................................................................................ 26 Handling Exceptions .......................................................................................................................... 28 Customizing Serialization ................................................................................................................... 30 Controlling Serialization ..................................................................................................................... 32 Versioning ......................................................................................................................................... 34 Labs ................................................................................................................................................. 36 Chapter 3 - Advanced I/O — New I/O .................................................................................................. 39 The java.nio Package ........................................................................................................................ 40 Buffers and Channels......................................................................................................................... 42 Buffer Implementations ...................................................................................................................... 44 Buffer Methods ................................................................................................................................. 46 ByteBuffer Methods .......................................................................................................................... 48 FileChannel ....................................................................................................................................... 50 File Locking ...................................................................................................................................... 52 MappedByteBuffer ........................................................................................................................... 54 Transferring Data Between Channels ................................................................................................. 56 Character Sets .................................................................................................................................. 58 Labs ................................................................................................................................................. 60 Chapter 4 - Reflection ............................................................................................................................. 63 Introduction to Reflection .................................................................................................................. 64 The Class Class ................................................................................................................................ 66 The reflect Package........................................................................................................................... 68 © 2011 ITCourseware, LLC

Rev 5.1.4

Page iii

Advanced Java Programming

Constructors ..................................................................................................................................... 70 Fields ................................................................................................................................................ 72 Methods ........................................................................................................................................... 74 Exception Handling and Reflection .................................................................................................... 76 JavaBeans ......................................................................................................................................... 78 Dynamic Programming ...................................................................................................................... 80 Labs ................................................................................................................................................. 82 Chapter 5 - Advanced JDBC .................................................................................................................. 85 JDBC SQL Escape Syntax ............................................................................................................... 86 The execute() Method ....................................................................................................................... 88 Batch Updates .................................................................................................................................. 90 Updatable Result Sets ....................................................................................................................... 92 Large Objects ................................................................................................................................... 94 Working with Savepoints ................................................................................................................... 96 RowSets ........................................................................................................................................... 98 CachedRowSet ............................................................................................................................... 100 DataSources ................................................................................................................................... 102 Labs ............................................................................................................................................... 104 Chapter 6 - Networking with Sockets ................................................................................................... 107 Clients and Servers ......................................................................................................................... 108 Ports, Addresses, and Protocols ..................................................................................................... 110 The Socket Class ............................................................................................................................ 112 Communication Using I/O ............................................................................................................... 114 Servers ........................................................................................................................................... 116 The ServerSocket Class .................................................................................................................. 118 Concurrent Servers ......................................................................................................................... 120 The URL Class ............................................................................................................................... 122 The URLConnection Class .............................................................................................................. 124 Labs ............................................................................................................................................... 126 Chapter 7 - Remote Method Invocation ................................................................................................ 129 Distributed Applications .................................................................................................................. 130 Stubs .............................................................................................................................................. 132 Steps to Create a Remote Object ................................................................................................... 134 An RMI Client ................................................................................................................................ 136 An RMI Server ............................................................................................................................... 138 RMI Classes and Interfaces ............................................................................................................ 140 Class Distribution ............................................................................................................................ 142 Page iv

Rev 5.1.4

© 2011 ITCourseware, LLC

Advanced Java Programming

RMI Utilities ................................................................................................................................... 144 Parameter Passing and Serialization ................................................................................................. 146 Labs ............................................................................................................................................... 148 Chapter 8 - Advanced RMI .................................................................................................................. 151 Client Callbacks .............................................................................................................................. 152 Dynamic Class Loading ................................................................................................................... 154 Activation........................................................................................................................................ 156 Activatable Objects......................................................................................................................... 158 Registering Activatable Objects ....................................................................................................... 160 Security and Activation .................................................................................................................... 162 JNDI and RMI Registry .................................................................................................................. 164 RMI-IIOP ...................................................................................................................................... 166 Labs ............................................................................................................................................... 168 Chapter 9 - Managing Security Policies ................................................................................................. 171 Untrusted Code .............................................................................................................................. 172 Security Managers .......................................................................................................................... 174 The Java Security Model ................................................................................................................. 176 Policy Entries .................................................................................................................................. 178 Policy Files...................................................................................................................................... 180 Using the Policy Tool....................................................................................................................... 182 Securing Applets ............................................................................................................................. 184 Securing Applications ...................................................................................................................... 186 Labs ............................................................................................................................................... 188 Chapter 10 - Keys, Signatures, and Certificates .................................................................................... 191 Jar Files .......................................................................................................................................... 192 Data Security Concerns .................................................................................................................. 194 Message Digests ............................................................................................................................. 196 Digital Signatures ............................................................................................................................. 198 Using keytool .................................................................................................................................. 200 Using jarsigner ................................................................................................................................ 202 Certificates ...................................................................................................................................... 204 Certificate Chains ............................................................................................................................ 206 Managing Keys and Certificates ...................................................................................................... 208 Security Policies for Signed Code ................................................................................................... 210 Java Cryptography Architecture ...................................................................................................... 212 Labs ............................................................................................................................................... 214 © 2011 ITCourseware, LLC

Rev 5.1.4

Page v

Advanced Java Programming

Chapter 11 - Encryption with the javax.crypto Package ........................................................................ 217 Cryptography Concepts .................................................................................................................. 218 Encryption Keys ............................................................................................................................. 220 Cipher Algorithms ........................................................................................................................... 222 Modes and Padding Schemes ......................................................................................................... 224 The Cipher Class ............................................................................................................................ 226 Encrypting and Decrypting Data ...................................................................................................... 228 Cipher Output Streams ................................................................................................................... 230 Cipher Input Stream ........................................................................................................................ 232 Encryption Using Password Ciphers ................................................................................................ 234 Exchanging Encrypted Keys ............................................................................................................ 236 Sealed Objects ............................................................................................................................... 238 Labs ............................................................................................................................................... 240 Chapter 12 - Java Authentication and Authorization Service (JAAS) ..................................................... 243 Authentication and Authorization ..................................................................................................... 244 JAAS Overview .............................................................................................................................. 246 LoginContext .................................................................................................................................. 248 Subjects, Principals, and PrivilegedActions ...................................................................................... 250 Authentication with the NTLoginModule ......................................................................................... 252 Defining Permissions in Policy Files ................................................................................................. 254 KeyStoreLoginModule ................................................................................................................... 256 Callbacks ........................................................................................................................................ 258 NameCallback and PasswordCallback ........................................................................................... 260 The Policy Class ............................................................................................................................. 262 Labs ............................................................................................................................................... 264 Chapter 13 - Java Naming and Directory Interface (JNDI) ................................................................... 267 Naming and Directory Services ....................................................................................................... 268 Namespaces and Contexts .............................................................................................................. 270 Naming Operations ......................................................................................................................... 272 Bindings .......................................................................................................................................... 274 Attributes ........................................................................................................................................ 276 Directory Operations....................................................................................................................... 278 DNS Lookups with JNDI ............................................................................................................... 280 JNDI in J2EE .................................................................................................................................. 282 Labs ............................................................................................................................................... 284

Page vi

Rev 5.1.4

© 2011 ITCourseware, LLC

Advanced Java Programming

Chapter 14 - Processing XML with Java — JAXP ............................................................................... 287 The Java API for XML Processing .................................................................................................. 288 Introduction to SAX Parsing ........................................................................................................... 290 SAXParser and JAXP .................................................................................................................... 292 SAX Event Methods ....................................................................................................................... 294 Introduction to DOM ...................................................................................................................... 296 Parsing DOM with JAXP ................................................................................................................ 298 The DOM API ................................................................................................................................ 300 Validation ........................................................................................................................................ 302 Transformation ................................................................................................................................ 304 Labs ............................................................................................................................................... 306 Chapter 15 - Native Methods ............................................................................................................... 309 Overview of Java Native Methods and JNI ..................................................................................... 310 How to Create and Use Native Methods ........................................................................................ 312 Native Method Declaration ............................................................................................................. 314 Using javah ..................................................................................................................................... 316 Creating the Implementation Code .................................................................................................. 318 Compilation .................................................................................................................................... 320 Distribution...................................................................................................................................... 322 Using the Native Methods ............................................................................................................... 324 JNI ................................................................................................................................................. 326 Passing Arguments .......................................................................................................................... 328 Calling Java Methods in Native Code .............................................................................................. 330 JNI Signatures ................................................................................................................................ 332 Labs ............................................................................................................................................... 334 Chapter 16 - Java Design Patterns — Creational Patterns ..................................................................... 337 What Are Design Patterns? ............................................................................................................. 338 What Are Creational Patterns? ........................................................................................................ 340 Singleton — Introduction ................................................................................................................ 342 Singleton — Implementation ............................................................................................................ 344 Singleton — When to Use? ............................................................................................................. 346 Factory Method — Introduction ..................................................................................................... 348 Factory Method — Implementation ................................................................................................ 350 Factory Method — When to Use? .................................................................................................. 352 Builder — Introduction ................................................................................................................... 354 Builder — Implementation ............................................................................................................... 356 Builder — When to Use? ................................................................................................................ 358 Labs ............................................................................................................................................... 360 © 2011 ITCourseware, LLC

Rev 5.1.4

Page vii

Advanced Java Programming

Chapter 17 - Java Design Patterns — Structural Patterns ...................................................................... 363 What Are Structural Patterns? ......................................................................................................... 364 Façade — Introduction ................................................................................................................... 366 Façade — Implementation .............................................................................................................. 368 Façade — When to Use? ............................................................................................................... 370 Adapter — Introduction .................................................................................................................. 372 Adapter — Implementation ............................................................................................................. 374 Adapter — When to Use? .............................................................................................................. 376 Composite — Introduction .............................................................................................................. 378 Composite — Implementation ......................................................................................................... 380 Composite — When to Use? .......................................................................................................... 382 Labs ............................................................................................................................................... 384 Chapter 18 - Java Design Patterns — Behavioral Patterns .................................................................... 387 What Are Behavioral Patterns?........................................................................................................ 388 Template — Introduction ................................................................................................................ 390 Template — Implementation ............................................................................................................ 392 Template — When to Use? ............................................................................................................. 394 State — Introduction....................................................................................................................... 396 State — Implementation .................................................................................................................. 398 State — When to Use? ................................................................................................................... 400 Observer — Introduction ................................................................................................................ 402 Observer — Implementation ........................................................................................................... 404 Observer — When to Use? ............................................................................................................ 406 Labs ............................................................................................................................................... 408 Appendix A - JDBC SQL Programming ................................................................................................ 411 Error Checking and the SQLException Class .................................................................................. 412 The SQLWarning Class ................................................................................................................... 414 JDBC Types ................................................................................................................................... 416 Executing SQL Queries ................................................................................................................... 418 ResultSetMetaData ......................................................................................................................... 420 Executing SQL Updates .................................................................................................................. 422 Using a PreparedStatement ............................................................................................................. 424 Parameterized Statements ............................................................................................................... 426 Stored Procedures .......................................................................................................................... 428 Transaction Management ................................................................................................................. 430 Labs ............................................................................................................................................... 432

Page viii

Rev 5.1.4

© 2011 ITCourseware, LLC

Advanced Java Programming

Appendix B - Eclipse ............................................................................................................................ 435 Introduction to Eclipse .................................................................................................................... 436 Installing Eclipse ............................................................................................................................. 438 Running Eclipse for the First Time .................................................................................................... 440 Editors, Views, and Perspectives ..................................................................................................... 442 Setting up a Project ......................................................................................................................... 444 Creating a New Java Application .................................................................................................... 446 Running a Java Application .............................................................................................................. 448 Debugging a Java Application .......................................................................................................... 450 Shortcut Key Sequences ................................................................................................................. 452 More Shortcut Key Sequences ....................................................................................................... 454 Setting the Classpath ....................................................................................................................... 456 Importing Existing Java Code into Eclipse ....................................................................................... 458 Solutions ............................................................................................................................................... 461 Index..................................................................................................................................................... 583

© 2011 ITCourseware, LLC

Rev 5.1.4

Page ix

Advanced Java Programming

Page x

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 1

Course Introduction

Chapter 1 - Course Introduction

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 11

Advanced Java Programming

Course Objectives ”

Store and retrieve a serialized Java object.

”

Use buffers and channels from Java's New I/O packages.

”

Use reflection classes to examine objects and classes at runtime.

”

Write Java programs that use advanced features of JDBC to interact with a relational database.

”

Create client/server Java applications using Remote Method Invocation (RMI).

”

Use activation and dynamic class loading within your RMI applications.

”

Use Java's security features and utilities.

”

Encrypt data with the javax.crypto package.

”

Authenticate and authorize clients with the Java Authentication and Authorization Service (JAAS).

”

Bind and lookup objects in a naming service using the Java Naming and Directory Interface (JNDI).

”

Access XML content with the Java API for XML Processing (JAXP).

”

Integrate legacy C/C++ code into your Java programs using the Java Native Interface (JNI).

”

Implement common creational, structural, and behavioral design patterns in Java.

Page 12

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 1

© 2011 ITCourseware, LLC

Course Introduction

Rev 5.1.4

Page 13

Advanced Java Programming

Course Overview ”

Audience: This course is designed for Java programmers who wish to develop applications taking advantage of advanced packages and features of the Java language.

”

Prerequisites: Java Programming. Experience writing applications in Java.

”

Classroom Environment:

Page 14

¾

One Java development environment per student.

¾

DBMS Server.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 1

Course Introduction

Using the Workbook This workbook design is based on a page-pair, consisting of a Topic page and a Support page. When you lay the workbook open flat, the Topic page is on the left and the Support page is on the right. The Topic page contains the points to be discussed in class. The Support page has code examples, diagrams, screen shots and additional information. Hands On sections provide opportunities for practical application of key concepts. Try It and Investigate sections help direct individual discovery. In addition, there is an index for quick look-up. Printed lab solutions are in the back of the book as well as on-line if you need a little help. The Support page has additional information, examples and suggestions.

The Topic page provides the main topics for classroom discussion.

Java Servlets

Chapter 2

Code examples are in a fixed font and shaded. The Add an init() method to your Today servlet that initializes a on-line bornOn date, then print the bornOn dateis listed file name along with the current date: above the shaded area.

The Servlet Life Cycle 

Hands On:

The servlet container controls the life cycle of the servlet. 

When the first request is received, the container loads the servlet class and calls the init() method.

Today.java

Topics are organized into  For every request, the container uses a separate thread to call service() first (”), secondthe(¾) andmethod. third (ƒ)level Whenpoints. the servlet is unloaded, the container calls the destroy()

... public class Today extends GenericServlet { private Date bornOn; public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { ... // Write the document out.println("This servlet was born on " + bornOn.toString()); out.println("It is now " + today.toString()); } public void init() { bornOn = new Date(); The init() method is } called when the servlet is }

method.  

Servlet Basics

As with Java’s finalize() method, don’t count on this being called.

Override one of the init() methods for one-time initializations, instead of using a constructor.

Callout boxes point out important parts of the example code.

loaded into the container.



The simplest form takes no parameters.



If you need to know container-specific configuration information, use the other version.

public void init() {...}

public void init(ServletConfig config) {...



Whenever you use the ServletConfig approach, always call the superclass method, which performs additional initializations. super.init(config);

Page 16

Rev 2.0.0

Screen shots show examples of what you should see in class.

© 2002 ITCourseware, LLC

© 2002 ITCourseware, LLC

Pages are numbered sequentially throughout the book, making lookup easy.

© 2011 ITCourseware, LLC

Rev 5.1.4

Rev 2.0.0

Page 17

Page 15

Advanced Java Programming

Suggested References Fisher, Maydene, Jonathan Bruce, and Jon Ellis. 2003. JDBC API Tutorial and Reference: Universal Data Access for the Java2 Platform, Third Edition. Addison-Wesley, Reading, MA. ISBN 0321173848. Flanagan, David. 2005. Java in a Nutshell, Fifth Edition. O'Reilly & Associates, Sebastopol, CA. ISBN 0596007736. Freeman, Elizabeth, et al. 2004. Head First Design Patterns. O'Reilly & Associates, Sebastopol, CA. ISBN 0596007124. Gamma, Erich, et al. 1995. Design Patterns. Addison-Wesley, Reading, MA. ISBN 0201633612. Gordon, Rob. 1998. Essential JNI: Java Native Interface. Prentice Hall, Upper Saddle River, NJ. ISBN 0136798950. Harold, Elliotte Rusty. 2004. Java Network Programming, Third Edition. O'Reilly & Associates, Sebastopol, CA. ISBN 0596007213. Hitchens, Ron. 2002. Java NIO. O'Reilly & Associates, Sebastopol, CA. ISBN 0596002882. Horstmann, Cay S. and Gary Cornell. 2004. Core Java 2, Volume II: Advanced Features, Seventh Edition. Prentice Hall, Upper Saddle River, NJ. ISBN 0131118269. Oaks, Scott. 2001. Java Security, Second Edition. O'Reilly & Associates, Sebastopol, CA. ISBN 0596001576. http://www.oracle.com/technetwork/java/index.html

Page 16

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 1

© 2011 ITCourseware, LLC

Course Introduction

Rev 5.1.4

Page 17

Advanced Java Programming

Page 18

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

Chapter 2 - Advanced I/O — Object Serialization

Objectives

© 2011 ITCourseware, LLC

”

Save and retrieve objects.

”

Send an object across a network connection.

”

Customize the serialization process.

”

Handle exceptions thrown during the serialization process.

”

Support compatibility between versions of a Serializable class.

Rev 5.1.4

Page 19

Advanced Java Programming

What is Serialization? ”

Serializing, or marshalling, an object converts it to a "stream of data." ¾

”

A serialized object contains the information necessary to deserialize, or unmarshal, the object.

The ObjectOutputStream and ObjectInputStream classes are used to write and read objects on any type of existing I/O stream. ¾

To write a serialized object to a file, create an ObjectOutputStream from a FileOutputStream. ƒ

¾

To write a serialized object to another Java program, retrieve the OutputStream from a Socket and create the ObjectOutputStream from that. ƒ

¾

The other Java program will re-create the object when reading it.

To write a serialized object to a byte array, create a ByteArrayOutputStream from a byte[] and wrap an ObjectOutputStream around it. ƒ

Page 20

The data in the file is in a proprietary Java format, so it will be difficult for you to read it.

This array could then be stored in a DBMS.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

birthDate:Date value = 08/05/1930

title:String

name:String

value = "astronaut"

value = "Neil Armstrong"

astronaut:Person id = 1

Serialization

¬ b \t v n g e j 201 Þ m a

í ÿ

\0 005 s r \0 006 P e r s o T 235 ê h 002 \0 004 I \0 002 i b i r t h D a t e t \0 020 a / u t i l / D a t e ; a m e t \0 022 L j a v a / / S t r i n g ; L \0 005 t q \0 ~ \0 002 x p \0 \0 \0 001 s a v a . u t i l . D a t 001 K Y t 031 003 \0 \0 x p w \b r ¯ - 200 x t \0 016 N e i l s t r o n g t \0 \t A s t u t

© 2011 ITCourseware, LLC

Rev 5.1.4

n d

E L

ý \0

L

j a \0 004 a n t l \0 016 h j ÿ ÿ þ A r r o n L l i r e

Page 21

Advanced Java Programming

Serializable Objects ”

A serializable object must be an instance of a class that implements java.io.Serializable (or java.io.Externalizable).

”

java.io.Serializable defines an interface with no methods. package java.io; public interface Serializable {}

¾ ”

The serialization mechanism uses reflection to construct the Serializable objects. ¾

Page 22

Implementing the interface simply marks your class for special treatment by the Virtual Machine.

If the superclass of a Serializable class is not Serializable, it must have a no-argument constructor. ƒ

The serialization mechanism uses this constructor to initialize the fields of the non-serializable superclass(es) of the object.

ƒ

If the superclass does not have a no-argument constructor, you can use the Externalizable interface to work around this constraint.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

This Person class is an example of a Serializable class. The toString() and equals() methods are included to compare original objects with restored objects. Person.java ... public class Person implements Serializable { private String name; private String title; private Date birthDate; private int id; public Person() { } public Person(String nm, String ti, String shortBirthDate, int i) { name = nm; title = ti; id = i; try { SimpleDateFormat df = new SimpleDateFormat("M/d/yyyy"); birthDate = df.parse(shortBirthDate); } catch (ParseException e) { System.err.println("Parsing error: " + shortBirthDate); birthDate = new Date(); } } public boolean equals(Object obj) { if (! (obj instanceof Person)) { return false; } Person p = (Person) obj; return name.equals(p.name) && title.equals(p.title) && birthDate.equals(p.birthDate) && id == p.id; } public String toString() { SimpleDateFormat df = new SimpleDateFormat("MMM d, yyyy"); return title + " " + name + " born " + df.format(birthDate) + " id " + id; } ... } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 23

Advanced Java Programming

Writing an Object ”

ObjectOutputStream's writeObject() method serializes (marshals) an object. ¾

The marshalled object contains structural information necessary to reconstruct the object.

”

Build an ObjectOutputStream from any OutputStream.

”

Marshalling an object involves dissecting the object into its component elements. ¾

If the object has already been written to this ObjectOutputStream, only a handle is written. ƒ

¾

This protects against recursive relationships and preserves shared references.

An ObjectStreamClass identifying the class of the object is written first. ƒ

This includes the name and serialVersionUID of the class.

¾

Primitive fields are written to the stream.

¾

Reference fields are serialized recursively.

¾

static fields will not be serialized. ƒ

¾

Only data specific to the instance is written.

transient fields will not be serialized.

”

Since reference data (object members) must also be sent, they must implement Serializable.

”

Transmitting an object will expose private data members.

Page 24

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

The writeObject() method takes an Object, not a Serializable. This means that attempting to write a nonserializable object will not result in a compiler error, but in a NotSerializableException, which will be caught in the IOException catch, but will not be very descriptive. WriteObj.java import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class WriteObj public static void Person armstrong "08/05/1930",

{ main(String args[]) { = new Person("Neil Armstrong", "Astronaut", 1);

ObjectOutputStream out = null; try { out = new ObjectOutputStream( new FileOutputStream("astronaut.ser")); out.writeObject(armstrong); System.out.println("Wrote \"" + armstrong + "\" to file"); } catch (IOException e) { System.err.println("Error writing object: " + e.getMessage()); } finally { try { out.close(); } catch (IOException e) { System.err.println(e.getMessage()); } } } }

Try It: Compile and run WriteObj.java. You can look at the resulting astronaut.ser file and see if you recognize any of the data.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 25

Advanced Java Programming

Reading an Object ”

ObjectInputStream's readObject() method deserializes (unmarshals) an object.

”

Build an ObjectInputStream from any InputStream. ¾

”

The readObject() method returns a java.lang.Object. ¾

”

Creating an ObjectInputStream from a stream which does not contain a serialized object will result in a StreamCorruptedException.

Downcast the object to the appropriate class, making sure to catch the ClassCastException which may result.

Unmarshalling an object involves assembling the object from its component elements. ¾

If the object has been read from the stream already, then a reference to the existing object is returned.

¾

First, the ObjectStreamClass is read. ƒ

¾

The no-argument constructor of the first non-serializable superclass is called.

¾

Primitive data members are set directly from the stream. ƒ

¾

Page 26

This is then used to load the class and verify the version.

No Serializable class constructor is called and field initializers are also ignored.

Reference data members are deserialized recursively.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

ReadObj.java import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class ReadObj { public static void main(String args[]) { ObjectInputStream in = null; try { in = new ObjectInputStream( new FileInputStream("astronaut.ser")); Person p = (Person) in.readObject(); System.out.println(p); } catch (ClassCastException e) { System.err.println("Error casting object to a Person"); } catch (ClassNotFoundException e) { System.err.println("Class not found"); StreamCorruptedException } extends IOException. catch (IOException e) { System.err.println("Error reading object: " + e.getMessage()); } finally { try { in.close(); } catch (IOException e) { System.err.println(e.getMessage()); } } } }

Try It: Compile and run ReadObj.java to load the person.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 27

Advanced Java Programming

Handling Exceptions ”

Attempting to serialize an object containing data that is not Serializable will result in a NotSerializableException.

”

Any IOException generated during an attempt to write an object to an ObjectOutputStream will be copied to the OutputStream in addition to being thrown.

”

The application reading serialized objects is responsible for handling any exceptions discovered in the InputStream.

”

The readObject() method throws a ClassNotFoundException if the VM can't find the object's .class file. ¾

Page 28

This happens even if you don't downcast the object.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

BadBatchProcessor.java ... public class BadBatchProcessor implements Runnable, Serializable { private ArrayList jobs; private ListIterator iterator; public BadBatchProcessor(ArrayList jobs) { this.jobs = jobs; The ListIterator implementation iterator = jobs.listIterator(); returned is not Serializable. } ... public static void main(String args[]) { BadBatchProcessor processor = null; File serialFile = new File("batch_processor_bad.ser"); if (serialFile.canRead()) { ObjectInputStream in = null; try { in = new ObjectInputStream(new FileInputStream(serialFile)); processor = (BadBatchProcessor)in.readObject(); System.err.println("Found previous batch processor : " + processor); This will catch the exception thrown } when reading the bad serialized object. catch (IOException ioex) { System.err.println("Error occurred reading " + serialFile + ": " + ioex); System.exit(1); } catch (ClassNotFoundException cnfex) { System.err.println("Class " + cnfex.getMessage() + " not found while unmarshalling " + serialFile); System.exit(2); } ... } }

While serializing the BadBatchProcessor, an Exception will be thrown due to the non-serializable ListIterator. Try It: Run BadBatchProcessor once to create the serialized object with the Exception. Then run it again to see what happens when the object is read.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 29

Advanced Java Programming

Customizing Serialization ”

Serializing an object also serializes the data members of the object.

”

Use the transient modifier to specify that a data member should not be serialized. ¾

”

The transient data will not be initialized when the object is read.

Serialization behavior can be altered by defining the readObject() and writeObject() methods in the class to be serialized. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException private void writeObject(ObjectOutputStream out) throws IOException

¾

Implementing writeObject() and readObject() allows the class to preand post-process the serialization process, usually handling static or transient data members.

¾

ObjectOutputStream provides defaultWriteObject() to serialize the object. ƒ

¾

ObjectInputStream provides defaultReadObject() to deserialize the object. ƒ

Page 30

This method can only be called from writeObject() to write the Serializable portion of the object.

This method can only be called from readObject() to read the Serializable portion of the object.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

Use the transient modifier either for data which is temporary, such as mouse coordinates, or for data which cannot be successfully serialized. While the Serializable interface does not require any implementation, it is the developer's responsibility to ensure that the class and all of its data members are, in fact, Serializable. Failure will result in a runtime exception. BatchProcessor.java ... public class BatchProcessor implements Runnable, Serializable { private ArrayList jobs; private transient ListIterator iterator; Since the ListIterator public BatchProcessor(ArrayList jobs) { this.jobs = jobs; iterator = jobs.listIterator(); }

is not Serializable, declare it transient.

public void run() { while (iterator.hasNext() && ! Thread.interrupted()) { Runnable job = iterator.next(); job.run(); Deserialize the non} transient fields first. } ... private void readObject(ObjectInputStream in) Read the index stored throws IOException, ClassNotFoundException { at serialization and get in.defaultReadObject(); an Iterator to continue // get a list iterator to start at the next job where we left off. int firstJob = in.readInt(); iterator = jobs.listIterator(firstJob); }

}

Serialize the nonprivate void writeObject(ObjectOutputStream out) transient fields first. throws IOException { out.defaultWriteObject(); // store the index of the next job for use at deserialization out.writeInt(iterator.nextIndex()); } Store the index of the next ... job for use at deserialization.

Try It: BatchProcessor has a main() method. The first time you run it, it creates a new batch of test jobs and runs for a couple of seconds. Each time you run it after that it will continue where it left off.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 31

Advanced Java Programming

Controlling Serialization ”

Classes that need to completely control the serialization process can implement java.io.Externalizable, which extends Serializable.

”

Externalizable declares two methods, readExternal() and writeExternal().

”

This interface completely replaces the default serialization behavior for assembling and disassembling the component elements. ¾

An Externalizable class must provide a no-argument constructor which is invoked before readExternal().

¾

The readExternal() and writeExternal() methods must explicitly read and write any data necessary to reconstruct the object. ƒ

”

Page 32

This includes fields from the class and all its superclasses.

¾

readObject() and writeObject() will not be called on the class or any superclass, and defaultReadObject() and defaultWriteObject() are not available.

¾

The ObjectStreamClass and internal handle are used in the same way as they are for Serializable classes.

Use Externalizable when you need more control than readObject() and writeObject() provide. ¾

Coordinating with the default serialization may be tedious; it might be easier to use Externalizable.

¾

An Externalizable object can override the serialization behavior of its superclass.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

Customer is a subclass of Person, so it inherits Person's serialization behavior. For privacy, we want to leave the personal information out of the serialized objects. The easiest way to do this without changing Person is to use Externalizable. Customer.java ... public class Customer extends Person implements Externalizable { private int accountNumber; // required no-argument constructor for Externalizable mechanism public Customer() { Here we must define appropriate // provide a dummy birth date defaults for the fields we will not be // Person can't handle null serializing. For most, null will suffice. setBirthDate(new Date()); } public Customer(int accountNumber, String name, String title, String birthDate, int id) { super(name, title, birthDate, id); this.accountNumber = accountNumber; } // read Person.id and Customer.accountNumber public void readExternal(ObjectInput in) throws IOException { setId(in.readInt()); All other fields for Person have accountNumber = in.readInt(); been defaulted by Customer's } no-argument constructor. // write Person.id and Customer.accountNumber, we don't want to // expose the other fields of Person on the output stream. public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(getId()); The only data we write out.writeInt(accountNumber); from Person is the id. } ... }

Try It: Test Customer with WriteCust and ReadCust.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 33

Advanced Java Programming

Versioning ”

Every Serializable class contains a serialVersionUID. ¾

By default, this long value is calculated from the name and signature of the class and its fields and methods using the Secure Hash Algorithm.

¾

You can provide your own public static final long serialVersionUID for backward compatibility. ƒ

”

You must ensure that the changes are both forwards and backwards compatible. ¾

Adding, removing, or modifying methods is compatible, though you must consider your business logic.

¾

Adding fields is compatible.

¾

ƒ

The new class must handle default values for fields missing from old objects.

ƒ

The old class will ignore the unknown fields in new objects.

Removing fields is incompatible. ƒ

¾

Page 34

Use the serialver utility (before you change the class) to find out the old version ID: serialver Person.

The old class might rely on non-default values from the fields missing in new objects.

You may need to use readObject() and writeObject() to ensure compatibility.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

Advanced I/O — Object Serialization

Person.java.new ... public class Person implements Serializable { public static final long serialVersionUID = 5043296006500641384L; private String name; private String title; private Date birthDate; private int id; private String quote = "Be respectful to your superiors, if you have any. - Mark Twain"; ... public String toString() { SimpleDateFormat df = new SimpleDateFormat("MMM d, yyyy"); StringBuilder result = new StringBuilder(); result.append(title).append(" ").append(name); result.append(" born ").append(df.format(birthDate)); result.append(" id ").append(id); if (quote == null) { result.append(" old class version: no quote specified"); } Here we handle objects serialized else { under the old version of the class. result.append(" quote "); result.append('"').append(quote).append('"'); } return result.toString(); } ... }

Try It: Make sure you have already run WriteObj with the original version of Person. Make a backup copy of Person.java, then copy Person.java.new to Person.java. Compile Person.java, then run ReadObj to view the old serialized object with the new class. Now run WriteObj to create a new serialized object. Restore Person.java from the backup, then compile it and run ReadObj to view the new object with the old class.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 35

Advanced Java Programming

Labs Write an Employee class with appropriate fields, including a hireDate. Write a Department class which has an Employee for the manager. Write an application which creates a Department object and writes it to a file. (Hint: Use SimpleDateFormat to create a hire date.) (Solution: Employee.java, Department.java, WriteDept.java) Write an application that reads a Department object from a file and displays it. (Solution: ReadDept.java) Modify the solution to to read from a file that doesn't contain a serialized object. (Solution: ReadJunk.java, junk.txt) In the next set of exercises you will modify your Employee class to create a new version. You should save a copy of Employee.java and dept.ser before continuing. Run serialver on the Employee class and copy the value into a new serialVersionUID field in your Employee class. Then, add a new Date field, departmentStartDate, to Employee. Do not modify toString() to include this field yet. In your constructor(s), default the departmentStartDate to the hireDate. Make sure your new class works with the serialized objects you created in ; you should still be able to display the object using ReadDept. (Solution: Employee.java.4) Use SimpleDateFormat to include the departmentStartDate in the toString() method. What happens when you run ReadDept? (Solution: Employee.java.5, explanation5.txt) Fix your Employee class using readObject so that if the departmentStartDate was missing in the serialized object, it would default to hireDate. Verify that this works with ReadDept. (Solution: Employee.java.6) Modify your application that writes the department so that it uses the new Employee class with a non-default departmentStartDate. After creating the new serialized object, restore the original version of Employee and verify that you can read the new serialized object with the old class. (Solution: WriteDept7.java)

Page 36

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 2

© 2011 ITCourseware, LLC

Advanced I/O — Object Serialization

Rev 5.1.4

Page 37

Advanced Java Programming

Page 38

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 3

Advanced I/O — New I/O

Chapter 3 - Advanced I/O — New I/O

Objectives ”

Describe the classes and interfaces in the java.nio package.

”

Store data within a Buffer.

”

Map a file onto memory with a MappedByteBuffer.

”

Connect I/O objects together with Channels.

”

Use the FileChannel object to lock files.

”

Translate characters to byte sequences using Charset implementations.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 39

Advanced Java Programming

The java.nio Package ”

”

”

”

The traditional I/O classes in the java.io package are easy to use, but they are not very efficient and do not take advantage of services that most operating systems provide. ¾

Sun introduced the New I/O library (NIO) with JDK version 1.4 to address those concerns.

¾

The old java.io library was rewritten to take advantage of some of the new features.

The new I/O library reads and writes data in blocks, instead of the byte or character streams of the java.io package. ¾

Blocks of data are managed in buffers.

¾

Developers read and write data to the buffer, instead of directly to the stream.

¾

The java.nio package contains a buffer class for each of the primitive Java types.

Channels handle reading and writing to the output device. ¾

The java.nio.channels package contains channel classes and interfaces.

¾

It also contains selector classes, which are used to multiplex channels.

Charsets encode and decode data from an I/O device to Java unicode characters. ¾

Page 40

The java.nio.charset package contains charset, decoder, and encoder classes.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 3

© 2011 ITCourseware, LLC

Advanced I/O — New I/O

Rev 5.1.4

Page 41

Advanced Java Programming

Buffers and Channels ”

”

In the NIO model, buffers and channels work together to read and write to I/O devices. ¾

You read and write data to a buffer, instead of directly to the channel.

¾

You then pass the buffer to the channel, which reads or writes it to the device.

To read from a file, first get a java.nio.channels.FileChannel object from a RandomAccessFile, FileInputStream, or FileOutputStream. RandomAccessFile raf = new RandomAccessFile(fname, "rw"); FileChannel fc = raf.getChannel();

”

Then allocate a buffer to handle the data from the channel: ByteBuffer buf = ByteBuffer.allocate(1024);

¾ ”

Allocate buffers in integer multiples of the device's default page size, usually 512 bytes.

If you want to read from the file, call the read() method on the channel, passing the buffer: int count = fc.read(buf);

¾

To get the data from buffer, flip it, then use the get() method: byte[] bytes = new byte[count]; buf.flip(); buf.get(bytes);

”

Page 42

If you want to write to the file, fill the buffer, flip it, and then call the channel's write() method. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 3

Advanced I/O — New I/O

NIORead.java import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class NIORead { public static void main(String[] args) { try { String fileName = "access_log"; RandomAccessFile raf = new RandomAccessFile(fileName, "rw"); FileChannel fc = raf.getChannel(); ByteBuffer buf = ByteBuffer.allocate(1024); byte[] bytes = null; Read from the channel int count=-1; while ((count = fc.read(buf)) != -1) { bytes = new byte[count]; buf.flip(); Get the data buf.get(bytes); from the buffer. for (byte b: bytes) { System.out.print((char) b); } buf.clear(); }

into the buffer until the end of file is indicated by a -1 return value.

// write to file buf.put("Hello".getBytes()); buf.flip(); fc.write(buf); System.out.println("Wrote string \"Hello\" to access_log."); fc.close(); } catch (Exception e) { e.printStackTrace(); } } }

Try It: Compile and run NIORead.java to use buffers and channels to read a file.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 43

Advanced Java Programming

Buffer Implementations ”

The java.nio package contains several buffer classes. ¾

”

The basic class, Buffer, is the superclass for implementations for various types of data. ¾

”

”

It defines the way a buffer keeps track of its internal positioning.

The most commonly-used subclass is ByteBuffer, which stores its data as a byte[]. ¾

”

All of the buffer classes in java.nio are abstract, and must be implemented by a service provider.

It provides methods for getting or putting each of the primitive Java types except boolean.

There are six other buffer classes, one for each of the primitive Java types (except boolean). ¾

Each TypeBuffer class provides get() and put() methods that work with its type.

¾

The CharBuffer class also has a put() method that takes a String parameter.

Because most I/O devices work with bytes, channels can only read or write a ByteBuffer. ¾

To use a buffer of another type, get a view into the ByteBuffer: ByteBuffer bbuf = ByteBuffer.allocate(16); DoubleBuffer dbuf = bbuf.asDoubleBuffer();

¾ Page 44

Both buffers are sharing the same storage, so be careful. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 3

Advanced I/O — New I/O

java.nio Buffer

ByteBuffer

CharBuffer

DoubleBuffer

FloatBuffer

IntBuffer

LongBuffer

ShortBuffer

DoubleWrite.java ... public class DoubleWrite { public static void main(String[] args) { try { String fileName = "constants"; FileOutputStream fout = new FileOutputStream(fileName); FileChannel fc = fout.getChannel(); ByteBuffer bbuf = ByteBuffer.allocate(16); DoubleBuffer dbuf = bbuf.asDoubleBuffer(); Write pi and e to file. dbuf.put(Math.PI); dbuf.put(Math.E); dbuf.flip(); fc.write(bbuf); System.out.println("Wrote math constants to constants file."); fc.close();

dbuf.clear(); FileInputStream fin = new FileInputStream(fileName); fc = fin.getChannel(); fc.read(bbuf); bbuf.flip(); Read pi and e from file. double pi = dbuf.get(); double e = dbuf.get(); fc.close(); System.out.println("pi = " + pi + " e = " + e); } catch (Exception e) { e.printStackTrace(); } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 45

Advanced Java Programming

Buffer Methods ”

”

”

java.nio.Buffer defines methods that are related to the position, limit, and capacity of the buffer. ¾

The capacity is defined when the buffer is allocated and is the amount of data the buffer can hold.

¾

The position is where any reading or writing operations will occur.

¾

The limit is one more than maximum position that contains valid data or to which you can write data.

¾

0 = 3) { System.out.print("Name: " + t.nextToken()); System.out.print(" Position: " + t.nextToken()); double salary = Double.parseDouble(t.nextToken()); System.out.println(" Salary: " + nf.format(salary)); totalSalary += salary; } } } ... return new Double(totalSalary); } }

Hands On: Compile ShowSalaries.java and SalariesAction.java. Because these classes require different permissions, we need to put them in different codebases. We could either do that by putting them in different directories, or by putting them in different JARs. There is a manifest file in the chapter directory that specifies the main class and class path for the ShowSalaries application, so let's create JARs. First create the application JAR: jar cvfm salaries.jar salaries.mf ShowSalaries.class. Then create the library JAR: jar cvf sa.jar SalariesAction.class. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 251

Advanced Java Programming

Authentication with the NTLoginModule ”

JAAS uses pluggable modules to authenticate a user. ¾

The JDK comes with four: NTLoginModule, KeyStoreLoginModule, Krb5LoginModule, and JNDILoginModule. ƒ

¾

Krb5LoginModule uses Kerberos protocols for authentication.

You can also get third-party login modules or write your own.

”

The NTLoginModule allows your Java program to take advantage of the user's Windows identity, so they do not have to login separately to your application.

”

Specify the com.sun.security.auth.module.NTLoginModule class and control flag in your login config file: NTJAAS { com.sun.security.auth.module.NTLoginModule required }

”

When you create your LoginContext, you do not have to specify a Callback, because the user has already logged in.

”

When you retrieve the Subject, you can see the various identities of the user by iterating through the Set of Principals.

Page 252

¾

The NTUserPrincipal contains the user name.

¾

The NTDomainPrincipal contains the domain name, the workgroup name, or the machine name, depending on what the user logged in to.

¾

NTSidUserPrincipal, NTSidDomainPrincipal, NTSidGroupPrincipal, and NTSidPrimaryGroupPrincipal contain the Windows security identifier of the user ID, domain, groups, and primary group, respectively. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

NTJAAS.java import import import import

java.security.Principal; java.util.Set; javax.security.auth.Subject; javax.security.auth.login.LoginContext;

public class NTJAAS { public static void main(String[] args) { LoginContext context = null; Subject subject = null; try { context = new LoginContext("NTJAAS"); context.login(); subject = context.getSubject(); Set principals = subject.getPrincipals(); for (Principal p : principals) { System.out.println("Principal type: " + p.getClass().getName() + " name: " + p.getName()); } } catch (Exception e) { e.printStackTrace(); } } }

login.conf NTJAAS { com.sun.security.auth.module.NTLoginModule required; }; ...

all.policy grant codeBase "file:///./-" { permission java.security.AllPermission; }

Try It: If you are on a Windows system, this program will show you the user identities. Compile NTJAAS.java. When you run it, you need to install a SecurityManager, and specify a policy file and login configuration file: java -Djava.security.manager -Djava.security.policy=all.policy -Djava.security.auth.login.config=login.conf NTJAAS Make a note of your NTUserPrincipal name — you will use it later. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 253

Advanced Java Programming

Defining Permissions in Policy Files ”

JAAS authorization is based on the same permissions, defined in the same policy files, that are used in code access security. ¾

”

A JAAS program is divided in (at least) two parts: the main code and the privileged action. ¾

”

Each part has different permission requirements, so your policy file will need (at least) two codeBase entries.

The main code requires AuthPermission "createLoginContext.", AuthPermission "doAs", and whatever permissions the privileged action requires. ¾

”

Users are authorized to access secured resources, such as files or sockets, not sections of code.

Often, the main code is granted AllPermission to simplify things.

The privileged action requires permission for whatever secured resource the user needs to access. ¾

The privileged action policy also specifies the principal type and name of who can access the resource.

grant codeBase "file:///C:/advj2se/ch12/sa.jar", principal com.sun.security.auth.NTUserPrincipal "student" { permission java.io.FilePermission "salaries.txt", "read"; };

Page 254

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

Hands On: Start policytool. If you have a .java.policy in your user directory, that will automatically be loaded. Select FileÆNew. Select the Add Policy Entry button. For the CodeBase, enter file:///C:/advj2se/ch12/ salaries.jar. Select the Add Permission button. In the Permission dropdown list, select AuthPermission. For the Target, select doAs. Press OK. Select Add Permission again. For the Permission select AuthPermission. For the Target, select createLoginContext.. In the text box to the right, replace with Salaries. Press OK.

Select Add Permission a third time. For the Permission select FilePermission. For the Target, enter salaries.txt. For the Action, select read. Press OK. Press Done to complete this policy entry. Select Add Policy Entry. For the CodeBase, enter file:///C:/advj2se/ch12/sa.jar. Select the Add Principal button. For Principal Type, select NTUserPrincipal. For the Principal Name, enter your user name from the NTJAAS example. Press OK. Select Add Permission. For the Permission select FilePermission. For the Target, enter salaries.txt. For the Action, select read. Press OK. Press Done. Select the FileÆSave As menu option, and save this as salaries.policy in your current chapter directory. Note: The CodeBase URLs require an absolute path for a .jar file. If your current chapter directory is something else, adjust the CodeBase appropriately. Try It: You can now run the ShowSalaries program: java -Djava.security.manager -Djava.security.policy=salaries.policy -Djava.security.auth.login.config=login.conf -jar salaries.jar

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 255

Advanced Java Programming

KeyStoreLoginModule ”

com.sun.security.auth.module.KeyStoreLoginModule allows you to authenticate users with certificates from a keystore. ¾

”

By default, it uses the .keystore file in the user directory and the default keystore protocol, but you can specify others in the login config file.

KeyStoreLoginModule allows several options in the login config file entry: com.sun.security.auth.module.KeyStoreLoginModule option=value, option2=value2...;

¾

Page 256

required

Possible options include: ƒ

keyStoreURL: the location of the keystore.

ƒ

keyStoreType: the keystore type.

ƒ

keyStoreProvider: the keystore provider.

ƒ

keyStoreAlias: the alias for the certificate to log in as; if not provided, a callback is sent to the application.

ƒ

keyStorePasswordURL: the location of the password for the keystore; if not provided, a callback is sent to the application.

ƒ

privateKeyPasswordURL: the location of the password for the key; if not provided, a callback is sent to the application; if not provided there, it defaults to the keystore password.

ƒ

protected: set to true if the keystore uses a separate authentication path.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

login.conf ... CallbackSample { com.sun.security.auth.module.KeyStoreLoginModule required; };

Hands On: The example program that we're going to run in a couple of pages requires a certificate in your keystore. If you have already created one, you need to find out the X.500 distinguished name, which includes the user's name, organization, city, state, and country. To find the distinguished name, edit the ShowCert.java program in this chapter directory, replacing the alias, keystore file location, and keystore password with your values. Then compile and run the program, making a note of the Certificate subject string. If you do not have a keystore or a certificate, run keytool -genkey -alias yourname. Enter the requested information, then compile and run ShowCert.java as discussed above. Now, run policytool. Select FileÆNew. Select the Add Policy Entry button. For the CodeBase, enter file:///C:/advj2se/ch12/callback.jar. Select the Add Permission button. In the Permission dropdown list, select AllPermission. Press OK. Press Done to complete this policy entry. Select Add Policy Entry. For the CodeBase, enter file:///C:/advj2se/ch12/sa.jar. Select the Add Principal button. For Principal Type, select X500Principal. For the Principal Name, enter the Certificate subject string from the ShowCert program. Press OK. Select Add Permission. For the Permission select FilePermission. For the Target, enter salaries.txt. For the Action, select read. Press OK. Press Done. Select the FileÆSave As menu option, and save this as callback.policy in your current chapter directory. Note: The CodeBase URLs require an absolute path for a .jar file. If your current chapter directory is something else, adjust the CodeBase appropriately.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 257

Advanced Java Programming

Callbacks ”

”

Callbacks are the mechanism that the LoginModule uses to get information about the user from the application. ¾

They can also provide information from the LoginModule to the user.

¾

NTLoginModule and UnixLoginModule don't use Callbacks, because the user is logged in through the system.

When you call login() on the LoginContext, the LoginContext calls login() on the LoginModule specified in the login configuration file. ¾

The LoginModule's login() method creates an array of Callback objects, one for each piece of information the module requires to authenticate a user. ƒ

¾ ”

For example, the LoginModule may create two Callbacks, one to retrieve the user name and one to retrieve the user password.

The LoginModule then calls the CallbackHandler's handle() method, passing the Callback array.

A CallbackHandler is an object that handles Callbacks. ¾

Define a class that implements javax.security.auth.callback.CallbackHandler, instantiate it, and pass it to the LoginContext constructor.

¾

Your class needs to define a single method, handle(), which is passed an array of Callback objects. public void handle(Callback[] callbacks)

¾ Page 258

Within the method, iterate through the Callback[], prompting the user for the requested information. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

Application main()

Callback Handler prompt for name prompt for password

user

handle(callbacks)

JAAS login() LoginContext

login()

LoginModule new

NameCallback

© 2011 ITCourseware, LLC

new

PasswordCallback

Rev 5.1.4

Page 259

Advanced Java Programming

NameCallback and PasswordCallback ”

”

”

Page 260

There are many types of callbacks, and they all implement the Callback interface. ¾

Each one is used to retrieve or display a specific type of information to the user.

¾

If your CallbackHandler does not handle a specific type of Callback, throw an UnsupportedCallback exception.

NameCallback is used to get the username from the application. ¾

Your CallbackHandler should display the return value from the getPrompt() method to prompt the user for their name.

¾

After the user enters their name, call setName() to add it to the NameCallback object.

¾

The LoginModule will call getName() to retrieve the name to be authenticated.

PasswordCallback is used to get the user's password. ¾

As with the NameCallback, your handler should display the return value from the getPrompt() method.

¾

The PasswordCallback also has an isEchoOn() method, telling you whether you should echo the password to the user as they type it.

¾

After the user enters their password, add it to the PasswordCallback with the setPassword() method.

¾

The LoginModule will call getPassword() to retrieve the password.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

LoginHandler.java ... public class LoginHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback cb : callbacks) { if (cb instanceof NameCallback) { NameCallback ncb = (NameCallback) cb; System.out.print(ncb.getPrompt() + " "); BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String name = in.readLine(); ncb.setName(name); } else if (cb instanceof PasswordCallback) { PasswordCallback pcb = (PasswordCallback) cb; System.out.print(pcb.getPrompt() + " "); BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String password = in.readLine(); pcb.setPassword(password.toCharArray()); Handlers for TextOutputCallback } and ConfirmationCallback used by ... KeyStoreLoginModule. else { throw new UnsupportedCallbackException(cb); } } } }

CallbackSample.java ... lc = new LoginContext("CallbackSample", new LoginHandler()); ...

CallbackSample is very similar to ShowSalaries, the only difference being we pass a LoginHandler to the LoginContext constructor. Try It: Compile LoginHandler.java and CallbackSample.java. This program uses the SalariesAction from a previous example, so you should already have compiled that and packaged it in a .jar. Create your application .jar file: jar cvfm callback.jar callback.mf LoginHandler.class CallbackSample.class Run the program: java -Djava.security.manager -Djava.security.policy=callback.policy -Djava.security.auth.login.config=login.conf -jar callback.jar © 2011 ITCourseware, LLC

Rev 5.1.4

Page 261

Advanced Java Programming

The Policy Class ”

The java.security.Policy class provides an interface into the policies defined in the policy files. ¾

You can use this class to work with standard policies as well as JAAS policies.

¾

Prior to Java 1.4, there was a separate javax.security.auth.Policy class for JAAS policies. ƒ

”

Get the current Policy with the static Policy.getPolicy() method. ¾

”

Page 262

javax.security.auth.Policy is deprecated in version 1.4.

Policy is an abstract class, so you are actually getting an instance of a subclass.

Retrieve the permissions from the Policy with the getPermissions() method. ¾

This returns a PermissionCollection, which allows you to add() a new Permission, iterate through the Permissions, and find out if a Permission is included with the implies() method.

¾

You will need to pass either a ProtectionDomain or a CodeSource to the getPermissions() method. ƒ

Create a CodeSource with a URL specifying the codebase, and either an array of Certificates or CodeSigners.

ƒ

Create a ProtectionDomain with a CodeSource and a PermissionsCollection.

ƒ

You can optionally include a ClassLoader and a Principal[].

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

Java Authentication and Authorization Service

ShowPolicies.java ... public class ShowPolicies { public static void main(String[] args) { LoginContext lc = null; try { lc = new LoginContext("Salaries"); lc.login(); Subject subject = lc.getSubject(); Principal[] principals = subject.getPrincipals().toArray(new Principal[0]); URL url = new URL("file:///"); CodeSource cs = new CodeSource(url, new Certificate[0]); ProtectionDomain pd = new ProtectionDomain(cs, null, ShowPolicies.class.getClassLoader(), principals); Policy policy = Policy.getPolicy(); PermissionCollection pc = policy.getPermissions(pd); Enumeration e = pc.elements(); while (e.hasMoreElements()) { Permission p = e.nextElement(); System.out.println("Permission: " + p); } lc.logout(); } ... } }

policy.policy grant codeBase "file:///./-" { permission javax.security.auth.AuthPermission "doAs"; permission javax.security.auth.AuthPermission "createLoginContext.Salaries"; permission java.io.FilePermission "salaries.txt", "read"; permission java.security.SecurityPermission "getPolicy"; };

Try It: Compile and run ShowPolicies.java with the policy.policy file: java -Djava.security.manager -Djava.security.policy=policy.policy -Djava.security.auth.login.config=login.conf ShowPolicies Try running the program with all.policy: java -Djava.security.manager -Djava.security.policy=all.policy -Djava.security.auth.login.config=login.conf ShowPolicies © 2011 ITCourseware, LLC

Rev 5.1.4

Page 263

Advanced Java Programming

Labs …

What is required to convert the NTJAAS.java example to use the KeyStoreLoginModule? Go ahead and do it to see what the X500Principal looks like. (Solution: KSJAAS.java, KSJAAS.txt, ksjaas.bat, kslogin.conf)

†

In this chapter directory there is a sample login module called EgLoginModule. It uses a NameCallback and a PasswordCallback to authenticate a user, then adds an EgPrincipal to the Subject. Write a callback handler to handle the callbacks from EgLoginModule. (Solution: EgLoginHandler.java)

‡

Change the CallbackSample.java program from this chapter directory to use your callback handler from †. Create a login config file for your program that uses jaas.EgLoginModule. (Solutions: EgCallback.java, eglogin.conf)

ˆ

Compile your source code from † and ‡, as well as EgLoginModule.java and EgPrincipal.java. Using callback.mf as a sample, create a manifest for your .jar file, then package the four class files you just compiled in a .jar with your manifest. (Solution: egbuild.bat, egcallback.mf)

‰

Create a policy file that grants AllPermission to your .jar file from ˆ and java.io.FilePermission "salaries.txt", "read" to sa.jar. Because policytool does not know about EgPrincipal, you will need to edit the policy file manually. The users are defined in the users file in the chapter directory, which is a standard Java properties file. (Solution: egcallback.policy)

Š

Run your program, entering the appropriate user name and password from the users file. (Solution: egrun.bat)

Page 264

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 12

© 2011 ITCourseware, LLC

Java Authentication and Authorization Service

Rev 5.1.4

Page 265

Advanced Java Programming

Page 266

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

Chapter 13 - Java Naming and Directory Interface (JNDI)

Objectives ”

Describe the purpose of a naming and directory service, and list several examples.

”

Use a service provider to connect to a naming service.

”

Look up objects using JNDI.

”

Manipulate name-to-object bindings.

”

Search a directory service.

”

Use JNDI to integrate Java applications with naming and directory services.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 267

Advanced Java Programming

Naming and Directory Services ”

”

A naming service associates names with objects. ¾

Directly, as a name bound to an actual remote Java object in RMI.

¾

Indirectly, as a hostname bound to a remote host's IP address.

A directory is a naming system that allows objects to have attributes. ¾

”

”

Attributes describe the object bound to a name.

There are many systems providing naming and directory services: ¾

LDAP: A subset of X.500; general-purpose directory service.

¾

NIS: Centralized directory of usernames and other information.

¾

RMI Registry: Binding of names to Java objects.

¾

File Systems: Hierarchical mapping of filenames to file contents.

¾

DNS: Distributed, hierarchical database of hostname-to-IP-address mappings.

¾

Windows Registry: Application and system settings.

¾

CORBA Naming Service: Centralized repository of name-to-object mappings for objects written in various languages.

JNDI uses service providers which interface with these and other systems.

Page 268

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

The JDK version 5.0 ships with: ƒ ƒ ƒ ƒ

LDAP service provider CORBA Naming Service RMI registry service provider DNS service provider

In some of the examples in this chapter we will use JNDI to access the RMI Registry. For most basic RMI applications, you would probably use the java.rmi.Naming or java.rmi.registry.Registry classes instead of JNDI to access a registry. Using JNDI can provide some additional flexibility with regards to configuration, but more interesting is the ability of a client application to dynamically use a completely different service, such as an LDAP directory, to locate remote objects. This strategy is especially useful for generic applications such as frameworks. Setup: To run the examples that use RMI in this chapter, you will first need to start the RMI Registry, then run the server application to create some remote objects. Compile the source files, then execute the following commands, each in their own window (make sure you run these in the directory with the class files or otherwise set an appropriate classpath): rmiregistry java Server

Note: The examples for directory services require access to LDAP and DNS services. If your firewall allows access to such services, then you should be able to access the public services used in the sample code. There are lists of some public services you can also try in public_ldap_servers.txt and public_dns_servers.txt, both extracted from internet searches.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 269

Advanced Java Programming

Namespaces and Contexts ”

”

”

JNDI gives you a common set of tools for dealing with naming and directory services, including: ¾

Direct lookup by name.

¾

Searching.

¾

Binding a name to an object, within the context of the service you're using.

To use a service, you must: 1.

Choose a service provider class for the service.

2.

Establish an initial context for your application within that service.

The initial context is your starting point in the service. ¾

”

Think of your current working directory within a file system.

To establish the initial context, use the InitialContext constructor. ¾

You can pass it a Hashtable to select the service provider and to provide other necessary information.

Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); env.put(Context.PROVIDER_URL, "rmi:///"); InitialContext ctx = new InitialContext(env);

Page 270

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

The InitialContext constructors will also look at the system properties or applet parameters, if appropriate, and then at the file jndi.properties (located anywhere in the classpath) for the properties needed to define and initialize the context. This provides a convenient, standardized mechanism for applications to allow the end-user to configure the application to use an arbitrary naming service. java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory java.naming.provider.url=rmi:///

Given the above jndi.properties file, the client code could create an InitialContext using the noargument constructor. InitialContext ctx = new InitialContext();

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 271

Advanced Java Programming

Naming Operations ”

To look up an object, use the Context.lookup() method. ¾

lookup() returns an Object, which you can cast to the type of object you are looking up. AccountFactory fact = (AccountFactory)ctx.lookup("bank1.accounts");

”

To list the contents of your context, use Context.list(). ¾

list() returns a NamingEnumeration, which you can traverse as you would any enumeration.

¾

Its values are NameClassPair objects.

NamingEnumeration objectList = ctx.list(""); NameClassPair item = null; while (objectList.hasMore()) { item = objectList.next(); }

ƒ

You can use the name in a lookup: Object o = ctx.lookup(item.getName());

”

The name passed into these methods can also be a full URL, potentially referring to a separate context or even a different service provider. NamingEnumeration stoogesOrg = ctx.list("ldap://ldap.yo-linux.com/o=stooges");

Page 272

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

Lister.java import import import import import import

javax.naming.InitialContext; javax.naming.Context; javax.naming.NamingEnumeration; javax.naming.NameClassPair; javax.naming.NamingException; java.util.Hashtable;

public class Lister { public static void main(String args[]) { String name = ""; if (args.length > 0) { name = args[0]; } Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); env.put(Context.PROVIDER_URL, "rmi:///"); try { InitialContext ctx = new InitialContext(env); NamingEnumeration list = ctx.list(name); while (list.hasMore()) { NameClassPair ncp = list.next(); System.out.println(ncp.getName()); } } catch (NamingException ne) { System.err.println(ne); } } }

Try It: Run Lister without parameters to list the names bound in the RMI Registry. Try passing a full URL to Lister.java to list a directory service: java Lister ldap://ldap.uas.alaska.edu

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 273

Advanced Java Programming

Bindings ”

You can create, replace, delete, or rename a binding using Context methods. ¾

bind() creates a new binding. ctx.bind("NewObject", newObject);

¾

rebind() replaces the object bound to a name. ctx.rebind("NewObject", otherObject);

¾

rename() replaces the name bound to an object. ctx.rename("NewObject", "OtherObject");

¾

unbind() removes a binding. ctx.unbind("OtherObject");

”

These methods may throw javax.naming.OperationNotSupportedException if the service provider does not support creating or modifying bindings. ¾

Page 274

This exception is also thrown if the type of the object is not supported by the service provider.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

A binding is the association of a name with an object. Managing name-to-object bindings is the purpose of a naming system. The Binding class represents a binding as a String (the name) and an Object (the object). A Binding also includes the class name of the bound object. A NameClassPair encapsulates a bound name and just the class name of the bound object without a reference to the object. For example, when using the RMI context service provider, the name will be an arbitrary name bound to the object by the server, the class name will be java.lang.Object, and the object will be an instance of the generated stub class which implements the remote interface and is connected to the remote object. Note that the class name is not particularly useful to an RMI application; you will need to examine the object itself to determine its class.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 275

Advanced Java Programming

Attributes ”

”

An attribute consists of a name and a list of values. ¾

The name is just a string.

¾

The values can be of any type.

The Attributes interface provides access to all of an object's attributes. Attributes attlist = ctx.getAttributes(objname);

”

The Attribute interface provides access to attribute values. Attribute att = attlist.get(attrname);

”

The attribute value list is either ordered or unordered. ¾

For ordered lists, you can retrieve a value by index. Object val = att.get(index);

¾

Page 276

For unordered attribute lists, getAll() retrieves an enumeration.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 13

Java Naming and Directory Interface (JNDI)

DirLookup.java ... public class DirLookup { public static void main(String args[]) { ... try { InitialDirContext ctx = new InitialDirContext(env); NamingEnumeration= 0; i--, j++) { graphic = string[i]; value = graphic - 48; ... } for (i = 0; i < numberDigits; i++){ total += digits[i]; } if (total % 10 == 0){ return total; } else { return 0; } } ...

CCCheck.c is the new code used to call the legacy code. CCCheck.c #include "CCCheck.h" #include #include "LegacyCCCheck.h"

These are the two parameters defined in the Java method.

JNIEXPORT jint JNICALL Java_CCCheck_validCC (JNIEnv *env, jobject obj, jstring ccNumber, jint count) { char cardNumber[40]; /* Convert Java String to C char array for reference */ const char *str = (*env)->GetStringUTFChars(env, ccNumber, NULL); int valid = 0; strcpy(cardNumber, str); valid = ccCheck(cardNumber, count); (*env)->ReleaseStringUTFChars(env, ccNumber, str); return valid; } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 319

Advanced Java Programming

Compilation ”

Use your preferred native compiler to build a shared library file from your implementation code. ¾

Use the appropriate compiler option for creating a shared library.

¾

The compiler's include path must have the standard and the platformspecific Java include directories.

¾

For many UNIX C compilers, the command-line switch to create a shared object library is -G. ƒ

For the GNU gcc compiler, it is -shared.

On UNIX/Linux: JAVA_HOME=/opt/j2sdk_nb/j2sdk1.5.0_03 export JAVA_HOME gcc -shared -o CCCheck.so -I$JAVA_HOME/include -I$JAVA_HOME/include/linux \ nativeCCCheck.c

Page 320

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

Hands On: On Windows: JAVA_HOME=c:\Program Files\java\jdk1.5.0_03

In Visual Studio 6.0: 1. Create a Win32 Dynamic-Link Library project. 2. Under the Tools menu, click on Options. 3. On the Options window, click on the Directories tab. 4. Be sure that the show directories for box says Include files. 5. Add a new entry under Directories referencing the %JAVA_HOME%\include directory. 6. Add another directory for the %JAVA_HOME%\include\Win32 directory. 7. Click OK in the Options box. 8. In the File View window, right click on the project name, and choose to Add Files to Project. 9. In the File window, select CCCheck.c, CCCheck.h and LegacyCCCheck.h to insert them into the project. 10. Click on ProjectÆSettingsÆLink. 11. Change the Category to Input. 12. In the object/library modules box add LegacyCCCheck.lib to the list. 13. Manually copy LegacyCCCheck.lib into your Project directory. 14. Choose BuildÆBuild Solution to build the DLL. 15. Copy the DLL from the Project/Debug directory to your chapter directory. In Visual Studio .NET: 1. On the File Menu, click NewÆProject. 2. In the New Project window, select Visual C++ Projects. Underneath Templates, select Win32 Project. 3. In the Name text field, enter CCCheck and press OK. 4. In the Win32 Application Wizard window, click on Application Settings and make the Application Type DLL and check Empty Project. Press Finish. 5. Click on ProjectÆProperties. In the Property Pages windows, click on LinkerÆInput. 6. In the Additional Dependencies box, add LegacyCCCheck.lib. Click OK. 7. Under the Tools menu, click on OptionsÆProjectsÆVC++ directories. 8. In the Show directories for box, select Include files. 9. Add a new entry referencing the %JAVA_HOME%\include directory. 10. Add another directory for the %JAVA_HOME%\include\Win32 directory. 11. Click OK on the Options box. 12. In the Solution Explorer window, right click on the project name, click AddÆAdd Existing Item. 13. In the Add Existing Item window, select CCCheck.c, CCCheck.h and LegacyCCCheck.h to insert them into the project. 14. Manually copy LegacyCCCheck.lib into your Project directory. 15. Choose BuildÆBuild Solution to build the DLL. 16. Copy the DLL from the Project/Debug directory to your chapter directory. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 321

Advanced Java Programming

Distribution ”

The shared library containing compiled native method implementation must be available to the VM. ¾

”

The path to the shared library file must be known to the VM — for example, listed in the PATH on Windows, or in LD_LIBRARY_PATH or LD_RUN_PATH on UNIX.

You can instead specify on the command-line where Java will look for the library by setting the java.library.path system property. ¾

The following command example will look for the library in the current directory: java -Djava.library.path=. CCCheckTest

Page 322

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

Hands On: On UNIX/Linux: LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. export LD_LIBRARY_PATH

On Windows: PATH=%PATH%;.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 323

Advanced Java Programming

Using the Native Methods ”

Simply instantiate an object of the wrapper class and call its methods normally.

Page 324

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

CCCheckTest.java public class CCCheckTest { public static void main (String args[]) { int valid = 0; String testNumber = "12344"; CCCheck checker = new CCCheck(); valid = checker.validCC(testNumber, testNumber.length()); System.out.println("Number " + testNumber + " is " + valid); testNumber = "12341"; valid = checker.validCC(testNumber,testNumber.length()); System.out.println("Number " + testNumber + " is " + valid); } }

CCCheck.java public class CCCheck { public native int validCC(String ccNumber, int digitCount); static { System.loadLibrary("CCCheck"); } }

Hands On: Compile and run CCCheckTest.java: javac CCCheckTest.java java CCCheckTest

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 325

Advanced Java Programming

JNI ”

The JNI specification defines an implementation-independent way of integrating Java with native code.

”

The JNI defines native types that map to Java primitives, references, and objects.

”

The JNI provides C functions for: ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ ƒ

”

Version Information Class Operations Exceptions Global and Local References Object Operations Accessing Fields of Objects Calling Instance Methods Accessing Static Fields and Methods String and Array Operations

Each native method call starts with a pointer to the JNI program interface, which is a list of function pointers to standard JNI functions. (JNIEnv *env, jobject obj ...)

¾

For example, in C you can retrieve the current version number with the following call to the GetVersion() function: jint v = (*env)->GetVersion(env);

¾

The C++ the syntax would be slightly simpler: jint v = env->GetVersion();

Page 326

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

The jni.h file provides java compatible types for use in native C code when passing information between C and Java. Primitive Type s — Pas s e d By Value Java Type boole an byte

JNI Type jboole an jbyte

De s cription 8- bit unsigned 8- bit signed

C Type uns igne d char char

char abort int

jchar js hort jint

16- bit unsigned uns igne d s hort 16- bit signed s hort 32- bit signed long

long float double void

jlong jfloat jdouble jvoid

64- bit signed 32- bit 64- bit

long long float double void

Re fe re nce Type s JNI Type Hie rarchy Java Type jobje ct Any Java Object jclas s java.lang.Clas s js tring java.lang.String jthrowable java.lang.Throwable jarray Java arrays jbyte aray byte [] jchararray char[] js hortarray s hort[] jintarray int[] jlongarray long[] jfloatarray float[] jdouble array double [] jboole anarray boole an[] jobje ctarray Any Object array

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 327

Advanced Java Programming

Passing Arguments ”

Parameters you declare for native methods in your wrapper class will be declared as JNI types by javah.

”

Primitive types are passed by value.

”

Java objects, including arrays and Strings, are passed by reference. ¾

”

All references passed to native methods, or returned by JNI functions called in the native method, are local to the native method.

Strings require some special handling in C. ¾

To convert a jstring (String object) to a C char array: 1.

Pass the jstring to GetStringUTFChars() storing the result in a const char *.

2.

The function returns a C character array.

const char * GetStringUTFChars(JNIEnv *, jstring, jboolean *)

3.

Call ReleaseStringUTFChars() when you have finished with the string, to prevent a memory leak in your native code.

void ReleaseStringUTFChars(JNIEnv *, jstring, const char *)

¾

To create a jstring from a C char array: 1.

Pass a char * to NewStringUTF().

jstring NewStringUTF(JNIEnv *, const char *);

2. Page 328

NewStringUTF() returns a jstring. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

CCCheckTest.java public class CCCheckTest { public static void main (String args[]) { int valid = 0; String testNumber = "12344"; CCCheck checker = new CCCheck(); valid = checker.validCC(testNumber, testNumber.length()); ... } }

CCCheck.java public class CCCheck { public native int validCC(String ccNumber, int digitCount); static { System.loadLibrary("CCCheck"); } }

CCCheck.c #include "CCCheck.h" #include #include "LegacyCCCheck.h" JNIEXPORT jint JNICALL Java_CCCheck_validCC (JNIEnv *env, jobject obj, jstring ccNumber, jint count) { char cardNumber[40]; /* Convert Java String to C char array for reference */ const char *str = (*env)->GetStringUTFChars(env, ccNumber, NULL); int valid = 0; Boolean to flag whether to make local copy of jstring. strcpy(cardNumber, str); valid = ccCheck(cardNumber, count); (*env)->ReleaseStringUTFChars(env, ccNumber, str); return valid; }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 329

Advanced Java Programming

Calling Java Methods in Native Code ”

To call methods of the native method's wrapper class, or of a Java object passed to a native method: ¾

Obtain the jclass associated with the Java object: jclass jc = (*env)->GetObjectClass(env,obj);

ƒ

You can also load the jclass class name: jclass jc = (*env)->FindClass(env,"MyJavaClass");

¾

Obtain an objects method ID using the class, method name, and signature: jmethodID mid = (*env)->GetMethodID (env, jc, "callBackMethod", "(I)V");

ƒ ¾

You can obtain a method ID for a static method using GetStaticMethod().

Call the method, using the appropriate JNI CallTypeMethod() function where Type is the method's return type. (*env)->CallVoidMethod(env, obj, mid, 4);

”

You can use the NewGlobalRef() function to create global references to jobjects, enabling them to be passed between functions. jobject jo = (*env)->NewGlobalRef(env,obj);

Page 330

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

StockBroker.java public class StockBroker implements StockListener { int brokerID; public StockBroker(int id) { brokerID = id; } public void tradeNotification(String sym, int shares) { System.out.print("Broker " + brokerID + " : " ); System.out.println(shares + " shares of " + sym + " were traded"); } }

StockMarketEngine.c #include #include "StockMarketEngine.h" jobject listener[10]; int lCount = 0; JNIEXPORT void JNICALL Java_StockMarketEngine_addStockListener (JNIEnv * env, jobject obj, jobject javaStockListener) { listener[lCount] = (*env)->NewGlobalRef(env,javaStockListener); lCount ++; } JNIEXPORT void JNICALL Java_StockMarketEngine_startEngine (JNIEnv * env, jobject obj) { jstring js; jclass jc; jmethodID mid; char * stockSymbol[10] = {"bh","itc","ms","y"}; int x,y; for (x = 0; x < 4; x++) { for (y=0; y < lCount; y++) { js = (*env)->NewStringUTF(env, stockSymbol[y]); jc = (*env)->GetObjectClass(env,listener[y]); mid = (* env)->GetMethodID (env, jc,"tradeNotification","(Ljava/lang/String;I)V"); (*env)->CallVoidMethod(env,listener[y],mid,js,x*100); (*env)->ReleaseStringUTFChars(env,js,stockSymbol[y]); } } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 331

Advanced Java Programming

JNI Signatures ”

Signatures consisting of the name and the parameter configuration identify unique entry points and specify return types. public native int validCC(java.lang.String, int); Signature: (Ljava/lang/String;I)I

¾

The first part of the signature is the entry point name.

¾

The first part of the parameter signature ( ) is the parameter list, followed by the return type.

”

Primitive types are abbreviated with standard abbreviation letters.

”

Non-primitives specify the Java-qualified type using Lclass and ending with ;. ¾

This example defines an entry that receives a String object and returns a String result. (Ljava/lang/String;)Ljava/lang/String;

”

You can use javap to determine the method signature of a Java method.

Page 332

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

Native Methods

Method Signatures:

(argtypes)returntype

Type abbrev. V Z B C S I J F D Lclass; [type

Java types void boolean byte char short int long float double Class class (fully-qualified) type array

javap -s CCCheck Compiled from "CCCheck.java" public class CCCheck extends java.lang.Object{ public CCCheck(); Signature: ()V public native int validCC(java.lang.String, int); Signature: (Ljava/lang/String;I)I static {}; Signature: ()V }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 333

Advanced Java Programming

Labs …

We have an emergency help notification system installed that pages a System Administrator when attention is needed. It needs a message and an ID (pager number as a character string). The files LegacyPager.c and LegacyPager.h contain the pageThem() function. Create and test a wrapper function to invoke the pager mechanism. (Solution: Pager.java, PagerTest.java, Pager.c)

†

Add a who() method to the Pager class to return your name as a character string when who() receives an ID. To return a string, you will need to create a String object to return using the followingline: return (*env)->NewStringUTF(env, cCharArray);

(Solution: Pager2.java, PagerTest2.java, Pager2.c)

Page 334

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 15

© 2011 ITCourseware, LLC

Native Methods

Rev 5.1.4

Page 335

Advanced Java Programming

Page 336

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Chapter 16 - Java Design Patterns — Creational Patterns

Objectives ”

Understand the need for Design Patterns.

”

Describe the purpose of Creational Patterns.

”

Implement the Singleton, Factory Method, and Builder patterns.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 337

Advanced Java Programming

What Are Design Patterns? ”

”

”

Page 338

A design pattern is a description of a collaboration of objects that are used to solve a general design problem in a particular context. ¾

These patterns have been used countless times by programmers in many different situations and applications.

¾

Design patterns are not created, they are discovered.

The use of design patterns has many advantages. ¾

They capture the expertise of many developers and make it available to all.

¾

A system that uses known patterns will be easier to understand and modify.

¾

They provide a common vocabulary for developers.

¾

Design patterns assist in avoiding the duplication of code.

¾

They facilitate the restructuring of a system, whether the system was originally built with patterns or not.

While patterns are published in styles that vary, all include the following important features: ¾

Name: A lot of effort is put into creating good pattern names.

¾

Problem: Describes when to apply the design pattern.

¾

Solution: A description of the objects and relationships involved.

¾

Consequences: The results and trade-offs involved in applying the pattern.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Some Background The pattern concept was co-opted from the architect Christopher Alexander. While his writings (A Pattern Language: Towns, Buildings, Construction and The Timeless Way of Building, 1977) described the patterns used in buildings, the central idea of reusing solutions to common problems can be applied in many areas. Ward Cunningham and Kent Beck published a paper entitled "Using Pattern Languages for ObjectOriented Programs" at the OOPSLA-87 conference, in which they described how patterns could be applied to user-interface design. Design Patterns, by Gamma, Helm, Vlissides, and Johnson (Gang of Four or GoF) was published in 1995 and has become the top-selling computer book of all time. The 23 patterns found in that book are still the cornerstone of the most recent design pattern books. The 23 GoF patterns are divided into three groups: Creational Structural Behavioral

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 339

Advanced Java Programming

What Are Creational Patterns? ”

”

Creational patterns encapsulate the process of instantiating objects and allow that process to change without affecting the rest of the system. ¾

Client code only needs to know about the exposed interfaces or abstract base classes.

¾

The concrete implementation of those abstractions can be changed without affecting the rest of the system.

Creational patterns come in two flavors: class creational and object creational. ¾

¾

Page 340

Class creational patterns use inheritance. ƒ

If a new instantiation process is needed, simply create a new derived class.

ƒ

Client code, which references an interface or abstract base class, is not affected by the addition of a new creation process.

Object creational patterns use composition. ƒ

Composition is more flexible than inheritance.

ƒ

Client code works with an object that implements an interface.

ƒ

The concrete creational process used by the system can be changed at runtime when composition is used.

ƒ

Since the interface has no implementation, there are no compiletime dependencies to worry about.

ƒ

A new implementation may even be received over the network.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Creator

Client

ConcreteCreator1

ConcreteCreator2

UML class diagram of a class-creational pattern.

«interface» Creator

Client

ConcreteCreator1

ConcreteCreator2

UML class diagram of a object-creational pattern.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 341

Advanced Java Programming

Singleton — Introduction ”

”

”

Page 342

The singleton pattern ensures that a class has only one instance. ¾

You may need a system-wide counter.

¾

You may need to control access to scarce resources like a database connection.

¾

It may be more efficient to allow only a single object of a class to be created and used.

A mechanism to access to this object must be provided. ¾

A simple solution would be to allow some "global" to hold the reference to this single object.

¾

Access to this object also needs to be controlled.

¾

In Java, the best solution is to make the class responsible for creating this single instance and controlling access to it.

The exact number of instances available may be changed as well. ¾

It is easy to change the singleton class to allow two or three objects instead of just one.

¾

This technique could be used to create a simple object pool.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

© 2011 ITCourseware, LLC

Java Design Patterns — Creational Patterns

Rev 5.1.4

Page 343

Advanced Java Programming

Singleton — Implementation ”

The key to this pattern is encapsulating the object creation process so that the class itself has full control. ¾

Eliminate the default constructor by explicitly declaring one.

¾

Make access to that constructor available only within the class by marking it as private. private MyConnection() ...

¾

Provide a static method that client code can use to access the singleton instead of using a constructor. public static MyConnection getInstance() ...

¾

”

The implementation of the getInstance() method demonstrates lazy instantiation, in which the singleton is created the first time it is requested.

There are several issues to be aware of: ¾

The singleton instance must be static.

¾

Concurrency issues should be carefully considered.

¾

Since Java does not allow us to override static methods, extending a singleton class is not recommended. ƒ

¾

Page 344

Instead of subclassing, the singleton pattern could be used in conjunction with another creational pattern.

If your singleton class extends a Cloneable class, be sure to override the clone() method to prevent client code from cloning your singleton. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

MyConnection.java import java.sql.Connection; import java.sql.DriverManager; public class MyConnection { private Connection connection; private static MyConnection theInstance; private MyConnection() { try { String driverClass = "org.apache.derby.jdbc.ClientDriver"; String url = "jdbc:derby://localhost:1527/j2se"; String username = null; String password = null; Class.forName(driverClass); connection = DriverManager.getConnection(url, username, password); } catch (Exception e) { System.err.println(e); } } public static synchronized MyConnection getInstance() { if (theInstance == null) { theInstance = new MyConnection(); } return theInstance; } public synchronized Connection getConnection() { return connection; } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 345

Advanced Java Programming

Singleton — When to Use? ”

Anytime the number of instances of a class should be limited and access to those objects should to be controlled, the singleton pattern should be used. ¾

Use when only one object should ever be created. ƒ ƒ ƒ ƒ ƒ ƒ

¾

Use when only a few objects should be created. ƒ ƒ ƒ

”

A database connection pool A set of worker processes used to handle incoming requests An application-scope object that has backup copies

There may be situations where an instance may become stale. ¾

Page 346

A counter A database connection An application-wide log file A print spooler A window manager A class that controls access to a JNDI server

In this case, the static accessor method could be implemented to periodically refresh this object.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Java uses a singleton to represent the environment in which an application is running. To access this singleton you call the static getRuntime() method defined within the Runtime class. This class uses an older naming convention for the static singleton instance method: getClassname(). The method name getInstance is more common today. Several classes in the java.awt and java.nio packages also use the singleton pattern.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 347

Advanced Java Programming

Factory Method — Introduction ”

”

”

Page 348

Use the factory method pattern when you need to separate the object creation logic from the rest of the application. ¾

The application may need to reference an abstract class that defers object creation to one of several subclasses.

¾

A subclass has the knowledge required to create concrete products that the application refers to generically via an interface or abstract base class.

¾

A framework is an example of such an application.

The factory method pattern provides flexibility over instantiating objects directly. ¾

The factory method in the base class could be abstract or a default implementation could be provided.

¾

New products can be supported by simply creating a new concrete creator that overrides or implements the base factory method.

This pattern can be used to connect parallel class hierarchies. ¾

The product hierarchy and the creator hierarchy could have matching subclasses.

¾

Alternatively, one concrete creator could know how to create most products, but special cases could be handled by other creator subclasses.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

«interface» Product

Client

Creator factoryMethod()

«create» ConcreteCreator

ConcreteProduct

factoryMethod()

Product.java public interface Product { public void whatAmI(); }

MyProduct.java public class MyProduct implements Product { public void whatAmI() { System.out.println("I'm a MyProduct"); } }

OtherProduct.java public class OtherProduct implements Product { public void whatAmI() { System.out.println("I'm an OtherProduct"); } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 349

Advanced Java Programming

Factory Method — Implementation ”

There are two primary implementations of this pattern. ¾

In the first, the factory method in the base class is abstract. ƒ

¾

”

”

The second style provides a default factory method in the base class. ƒ

Subclasses may choose to override this factory method.

ƒ

The base class could also be marked as abstract, forcing subclasses to be used even though the factory method was implemented in the base class.

Factory methods can also accept parameters. ¾

The parameter could indicate which concrete product to create.

¾

Creator subclasses are rarely used in this case.

Factories implemented in Java often use other means to determine which concrete product to create. ¾

Property files are commonly used. ƒ

¾

Page 350

This option is used when there is no reasonable default implementation of the factory method.

A property value could be a product classname that can be used to dynamically instantiate an object via reflection.

Values from a database or JNDI server could be used as well.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

DynamicFactory.java ... public class DynamicFactory { private static final String DEFAULT = "MyProduct"; Factory method. public Product createProduct() { String product = getProductName(); Product p = null; try { Class clazz = Class.forName(product); p = (Product) clazz.newInstance(); } ... return p; } private String getProductName() { Properties p = new Properties(); String productToCreate = DEFAULT; try { Get product name FileInputStream inputStream = new from .properties file. FileInputStream("product.properties"); if (inputStream != null) { p.load(inputStream); productToCreate = p.getProperty("product"); } } catch (IOException ignore) { }

return productToCreate; } public static void main(String[] args) { DynamicFactory df = new DynamicFactory(); Product p = df.createProduct(); ... } }

product.properties product=OtherProduct

Try It: Compile DynamicFactory.java as well as Product.java, MyProduct.java and OtherProduct.java. Run DynamicFactory. Delete product.properties and run it again.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 351

Advanced Java Programming

Factory Method — When to Use? ”

Anytime a system can be made more flexible by separating object creation from object use, think of using a factory.

”

If new subclasses within a hierarchy are expected to be added in the future, the use of a factory method can insulate the rest of the application from this churn.

”

Page 352

¾

This is a common driving force in the application of design patterns: separate the things that change from those that do not.

¾

The client application will not need to be changed if the impact of the addition of a new subclass can be isolated to the factory method.

Creational patterns often complement each other. ¾

Be aware of opportunities to leverage the use of several cooperating patterns.

¾

This also applies across all three pattern types (Creational, Structural, and Behavioral).

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

EJBHome interfaces contain create() methods, which are factory methods used to create Enterprise JavaBeans. The java.net.URLStreamHandlerFactory is an interface that can be used to pass a concrete creator with a factory method to a URL. The URL will then use this factory method to create a stream protocol handler.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 353

Advanced Java Programming

Builder — Introduction ”

”

If you need to create a variety of complex objects, the builder pattern can separate the construction process from the rest of your code. ¾

An abstract builder class describes the methods required to build the individual parts of the complex object.

¾

Concrete builders implement those methods, encapsulating the construction details and the resulting data representation (e.g., a flatfile, an XML file, etc.).

¾

A director class is used to control the construction sequence and provide the content to the builder.

The client application communicates with the director and a concrete builder. ¾

The client creates a concrete builder. ƒ

Page 354

The builder base class often provides a static method to return a concrete derived class.

¾

The builder is given to the director, which uses the builder within its internal algorithm.

¾

The director has the content for the complex object, or knows how to get it.

¾

Finally, the client asks the director for the complex object.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Builder

c: Client

getInstance(param)

new

cb

cb: ConcreteBuilder new(cb)

d: Director build()

buildPartA(x) buildPartB(y) buildPartC(z) getProduct() complexProduct complexProduct

UML sequence diagram of the Builder pattern.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 355

Advanced Java Programming

Builder — Implementation ”

”

Page 356

There are several options for creating the concrete builders. ¾

The client can instantiate a builder itself.

¾

The client can ask the builder base class for a concrete builder based on an input parameter.

¾

A factory method could be used instead.

The mechanism used to return the complex object may vary. ¾

The client could ask the director for the object explicitly.

¾

The construction method could return the object as the return argument.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

Director

«create»

-builder

Builder Client

-file:File

+Director(Builder)

+getInstance(format)

+construct():File

+buildPartA() +buildPartB() +buildPartC() +getFile()

«interface» File

FlatFileBuilder

XMLFileBuilder

+buildPartA()

+buildPartA()

+buildPartB()

+buildPartB()

+buildPartC()

+buildPartC()

«create» XMLFile

FlatFile

«create»

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 357

Advanced Java Programming

Builder — When to Use? ”

When you have an algorithm that controls the object creation process you should investigate the possible application of the builder pattern. ¾

”

The algorithm should be separable from the details of the process.

There should be at least two complex product types or the strong possibility that new types will be added. ¾

The different complex product types may have a common base class or may be so different that it does not make sense to factor out a superclass. ƒ

¾ ”

Sometimes data is simply appended to the complex object (e.g., the document conversion program).

The builder pattern may be used to create a complex collaboration of objects. ¾

Entire GUI screens can be created via builders.

¾

The composite pattern is often used to represent complex objects. ƒ

Page 358

For example, the builder pattern could be used to convert an RTF document to ASCII, PDF, XML, etc.

Look for opportunities to use these patterns together.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

Java Design Patterns — Creational Patterns

The builder pattern is used by the java.security.cert package in the creation of certificate chains.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 359

Advanced Java Programming

Labs …

Run the HumanResourcesApp that is located in the chapter directory. It is designed to handle incoming requests via separate threads (like a servlet) and create a unique employee id for each request. It does not work correctly. Fix it by applying the appropriate pattern. (Solutions: IdGenerator2.java, HumanResourcesApp2.java)

†

Modify your code from … to allow your program to create ids that start from zero (like in

…) or start from a number that is read from a property file. Hint: Use the factory method pattern to use one of two singletons based on the existence of the property file. (Solutions: IdGeneratorFactory.java, SimpleIdGenerator.java, Configuration.java, FileIdGenerator.java, HumanResourcesApp3.java, IdGenerator3.java, hrapp.properties)

‡

Page 360

Run BuilderWannabe from the chapter directory and investigate the code. Refactor this class to a pattern. emember that refactoring is taking code that works and changing it so that it is better organized with respect to readability and maintenence without changing the behavior. (Solutions: BuilderClient.java, Director.java, Builder.java, PropertyBuilder.java, FlatFileBuilder.java, OutputFile.java, PropertyFile.java, FlatFile.java)

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 16

© 2011 ITCourseware, LLC

Java Design Patterns — Creational Patterns

Rev 5.1.4

Page 361

Advanced Java Programming

Page 362

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

Chapter 17 - Java Design Patterns — Structural Patterns

Objectives ”

Describe the purpose of Structural Patterns.

”

Implement the Façade pattern to provide a simple interface to a subsystem.

”

Use the Adapter pattern to convert from one interface to another.

”

Create hierarchical designs with the Composite pattern.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 363

Advanced Java Programming

What Are Structural Patterns? ”

Structural patterns deal with building larger structures by combining classes and objects.

”

There are two types of structural patterns: class and object. ¾

¾

Page 364

Structural class patterns are centered on the use of inheritance. ƒ

Abstract classes or interfaces are typically defined at the root of the structure.

ƒ

Their basis in inheritance allows these patterns to take advantage of polymorphism.

ƒ

The drawback to this model is that the structure is set at compile time.

Structural object patterns compose their structures at runtime. ƒ

You gain flexibility by allowing the structure to dynamically change.

ƒ

As new functionality is needed, these patterns can adapt without affecting other code.

ƒ

Favoring composition over inheritance is a common goal throughout many patterns.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

© 2011 ITCourseware, LLC

Java Design Patterns — Structural Patterns

Rev 5.1.4

Page 365

Advanced Java Programming

Façade — Introduction ”

Complex applications are often composed of multiple smaller subsystems. ¾

”

Within each subsystem, you define public classes with public methods that are accessible to other subsystems. ƒ

This leads to high coupling between subsystems.

ƒ

If you change the public interface defined by a class in one subsystem, that change can cascade to other dependent subsystems.

The façade pattern allows you to create a single, simple interface to an entire subsystem. ¾

Your clients can use the façade if they want an easy-to-use, unified way of accessing the most common functionality of the subsystem. ƒ

¾

You can still allow for bypassing the façade for those clients that would like to continue communicating directly with the underlying classes. ƒ

Page 366

The façade hides the details and complexity of the subsystem.

This allows you to expose advanced functionality not available through the façade.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

Client

Façade subsystem classes

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 367

Advanced Java Programming

Façade — Implementation ”

”

Implementing the façade pattern in Java involves creating an additional public class for each façade you intend to develop. ¾

Within that class, define public methods for the functionality that you intend to expose.

¾

Your method implementation can: ƒ

Forward or delegate requests to the underlying subsystem methods without modification.

ƒ

Add extra functionality, such as logging or auditing.

ƒ

Translate calls that have been exposed in the simple façade interface to the more complex signatures of the underlying methods.

ƒ

Simplify the interface to clients by giving a series of subsystem method calls a single, course-grained entry point.

If your subsystem is made up of a single package, you can take advantage of Java's package access control when building your façade. ¾

You should mark the façade and its methods as public.

¾

Any methods and classes that should not be available to external clients should use package or private access control rather than public. ƒ

”

Page 368

If you choose to allow expert users to bypass the façade, then mark those classes and methods as public, as well.

You should use the singleton pattern to handle object creation, because you will typically only need one façade instance per subsystem.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

IOFacade.java import java.io.*; public class IOFacade { ... public void writeToTextFile(String filename, String text) throws IOException { PrintWriter out = null; boolean append = true; try { File file = new File(filename); out = new PrintWriter(new BufferedWriter( new FileWriter(file, append))); out.println(text); } catch (IOException e) { log(e); throw e; } finally { out.close(); }

This façade simplifies the process of writing to a text or binary file.

} public void writeToBinaryFile(String filename, byte[] bytes) throws IOException { BufferedOutputStream out = null; boolean append = true; try { File file = new File(filename); out = new BufferedOutputStream( new FileOutputStream(file, append)); out.write(bytes); } catch (IOException e) { log(e); throw e; } finally { ... } } ... } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 369

Advanced Java Programming

Façade — When to Use? ”

”

Use the façade pattern if you want to expose an easy-to-understand interface to clients of your subsystem, rather than requiring them to understand the details of each public class within it. ¾

The façade is the application programming interface (API) for your subsystem.

¾

It allows you to present a complex system in a simple way. Not all clients will need all of the functionality.

ƒ

A method in the façade can invoke multiple methods on the subsystem.

Use the façade pattern to decouple the class implementations from their external clients. ¾

Page 370

ƒ

Changes to the underlying code will not impact external clients that use the façade.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

FacadeClient.java public class FacadeClient { public static void main(String[] args) { IOFacade facade = IOFacade.getInstance(); String text = "To be, or not to be: that is the question"; byte[] bytes = {70, 65, 67, 65, 68, 69, 1, 1, 1}; This client uses the façade to simplify writing to a file.

try { facade.writeToTextFile("string.txt", text); facade.writeToBinaryFile("bytes.bin", bytes); } catch (Exception e) { System.err.println(e); } } }

AdvancedClient.java public class AdvancedClient { public static void main(String[] args) { String s = "To sleep: perchance to dream: ay, there's the rub;\n"; insertTextInFile("hamlet.txt", s, 395); } This client bypasses the

private static void insertTextInFile(String filename, façade because it needs String textToInsert, int position) { advanced functionality that the façade does not expose.

RandomAccessFile rac = null; try { rac = new RandomAccessFile(new File(filename), "rw"); int currentFileLength = (int)rac.length(); int numCharsInRestOfFile = currentFileLength - position; byte[] savedText = new byte[numCharsInRestOfFile]; rac.seek(position); rac.readFully(savedText); rac.seek(position); rac.writeBytes(textToInsert); rac.writeBytes(new String(savedText)); ... }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 371

Advanced Java Programming

Adapter — Introduction ”

When incorporating an existing class into an application, you must decide how to merge the existing class' interface with the interface that you would have used if you were writing the code from scratch. ¾

¾

You may be tempted to modify your design to embrace the existing class' interface. ƒ

Client code would be tightly coupled to the existing class.

ƒ

Method signatures could be awkward, because you've made your new code backwards compatible with the existing class' interface.

If you have access to the source code, you could modify the existing class to more closely match the new design. ƒ

¾ ”

Page 372

The existing class may have legacy clients that would be affected.

You can use the adapter pattern to leverage a design that has been used thousands of times to address this exact dilemma.

The adapter pattern allows you to convert a class' interface into an interface that is more compatible with your design. ¾

An adapter serves as a translator, receiving requests from clients and forwarding them on to the existing class, the adaptee.

¾

With the adapter in place, neither the client class nor the existing class would need to be modified.

¾

The adapter also serves as a wrapper; it allows you to swap the adaptee without affecting the client.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

There are two types of adapters: object adapters and class adapters. With object adapters, an adaptee instance is stored within the adapter. Whenever a method is invoked on the adapter, it delegates the request to the adaptee. The client typically references a parent interface (or abstract class) that the adapter implements (or extends) to decouple the client from the adapter and allow for polymorphism. With a class adapter, the adapter inherits from both the adaptee and the target that the client references. Any calls to the adapter method are forwarded directly to the corresponding method within the adaptee. In the diagram below, the Target represents the interface that the Client interacts with, but the Adapter relies on the Adaptee to provide the actual implementation.

Client

«interface» Target request()

Adaptee

Adapter request()

specificRequest() public void request() { adaptee.specificRequest(); }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 373

Advanced Java Programming

Adapter — Implementation ”

Implementing the object adapter pattern in Java involves two classes and one interface. ¾

Create an interface that defines the method(s) that the client expects to call.

¾

Implement the interface in your adapter class.

¾

Page 374

ƒ

Initialize a reference to the adaptee in the adapter's constructor.

ƒ

Delegate each interface method call to the corresponding adaptee's method.

ƒ

Your adapter can also add additional methods that aren't available in the adaptee.

The adaptee class remains unchanged.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

AdapterClient

Java Design Patterns — Structural Patterns

«interface» java.util.Collection

main() add() addAll() clear() contains() containsAll() isEmpty() iterator() ...

GenericArray

GenericArrayAdapter adaptee:GenericArray add() addAll() clear() contains() containsAll() isEmpty() iterator() ...

addElement() indexOfObject() getArray() getElement() getLength() getSize() removeElement() removeAllElement()

GenericArrayAdapter.java ... public class GenericArrayAdapter implements Collection { private GenericArray adaptee; public GenericArrayAdapter() { adaptee = new GenericArray(); } public GenericArrayAdapter(int initialSize) { adaptee = new GenericArray(initialSize); } public boolean add(E o) { adaptee.addElement(o); return true; } ... public void clear() { adaptee.removeAllElements(); } ...

The adapter translates calls to the adaptee.

} © 2011 ITCourseware, LLC

Rev 5.1.4

Page 375

Advanced Java Programming

Adapter — When to Use? ”

Use the adapter pattern any time you want to convert from one interface to another. ¾

”

Use the object adapter pattern if you would like to dynamically substitute the adaptee. ¾

”

Page 376

The adapter will translate an incompatible interface in an existing class to a domain-specific interface.

The adaptee reference that is contained by the adapter can actually refer to any children of the adaptee, as well.

The adapter pattern can be confused with the façade pattern, because both provide wrapping behavior, but the intent of each pattern is different: ¾

A façade defines a simple interface for a subsystem.

¾

An adapter converts one interface to another.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

GenericArray.java public class GenericArray { private T[] array; private int currentIndex = 0; private int initialSize = 0; public GenericArray() { this(1000); } public GenericArray(int size) { initialSize = size; array = getNewArray(initialSize); }

The GenericArray is our "legacy" class that serves as the adaptee. It does not implement Collection.

public void addElement(T element) { array[currentIndex++] = element; } ... public void removeAllElements() { array = getNewArray(initialSize); currentIndex = 0; } ... }

AdapterClient.java ... The adapter public class AdapterClient { makes our public static void main(String[] args) { GenericArray Collection c1 = new ArrayList(); compatible with populateCollection(c1); Collection. printCollection(c1); Collection c2 = new GenericArrayAdapter(); populateCollection(c2); printCollection(c2); } private static void populateCollection(Collection c) { c.add("Class " + c.getClass().toString()); c.add("HashCode " + c.hashCode()); } private static void printCollection(Collection c) { Iterator it = c.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 377

Advanced Java Programming

Composite — Introduction ”

Complex application designs sometimes yield part-whole relationships that are implemented as tree structures. ¾

”

Clients interacting with the tree structure would benefit if they could treat branch and leaf nodes identically. ¾

”

Otherwise, client code would have to use conditional statements to determine what kind of object they are currently traversing and treat it accordingly.

The composite pattern allows you to represent part-whole relationships as tree structures, where clients work with nodes of the tree identically. ¾

¾

Page 378

XML DOM trees are typical examples.

The pattern consists of component, leaf, and composite classes. ƒ

The component class defines the common interface that clients interact with.

ƒ

Each leaf instance inherits from component and represents a node in the tree without children.

ƒ

The composite also inherits from component and is responsible for storing child components.

Your client code only depends on the component's interface. ƒ

Any additional leaf or composites added to the tree will not affect the client code.

ƒ

Your client code should not know or care if it is dealing with a leaf or a composite at any time. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

The class diagram below illustrates the fact that the client always interacts with the base Component class. Component

CompositeClient main()

operation() add(Component) remove(Component) getChild(int)

Leaf

Composite

operation()

operation() add(Component) remove(Component) getChild(int)

This object diagram shows how the composite pattern manifests itself at runtime: :Client

:Composite

:Leaf

:Leaf

© 2011 ITCourseware, LLC

:Composite

:Leaf

Rev 5.1.4

:Leaf

:Leaf

Page 379

Advanced Java Programming

Composite — Implementation ”

”

You should implement the component as an abstract class where each method defines default behavior. ¾

Code each method so it throws an exception that identifies it as an unsupported method.

¾

Alternatively, the methods could provide no-op implementations.

Your composite's primary responsibility is to support addition, removal, and retrieval of child nodes. ¾

Extend the component and override the appropriate methods to support this behavior. ƒ

¾ ”

Use the default implementations in component to return an "unsupported" exception to the client if one of these methods is invoked.

You can define an extra field and methods within the component to manage a reference to its parent. ¾

Page 380

Also override any other methods to recursively call the same methods on the stored child nodes.

The leaf is only responsible for defining the non-child-related methods. ¾

”

Store children in an appropriate data structure, such as an ArrayList.

This can make traversal and cleanup easier.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

CompositeClient

ArithmeticComponent

main()

evaluate() add(ArithmeticComponent) remove(ArithmeticComponent) getChild(int)

Operand

Operator children:ArrayList operator:String

op:int evaluate()

evaluate() add(Component) remove(Component) getChild(int)

ArithmeticComponent.java

Each method in the component public abstract class ArithmeticComponent { class throws an public void add(ArithmeticComponent component) { UnsupportedOperationException. throw new UnsupportedOperationException(); } public void remove(ArithmeticComponent component) { throw new UnsupportedOperationException(); } public ArithmeticComponent getChild(int i) { throw new UnsupportedOperationException(); } public int evaluate() { throw new UnsupportedOperationException(); } }

Note: The methods in the component class deal with maintaining child nodes and exposing the logic that each leaf defines. These two distinct responsibilities make the component class less cohesive than most designers would like. In fact, defining methods in a parent class that are not applicable to a child class is also typically considered bad design. The composite pattern accepts this practice in the name of transparency. Clients work with leaves and composites without needing to understand which type they are working with at the expense of safety. A client may try to add a child to a leaf and get a runtime exception.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 381

Advanced Java Programming

Composite — When to Use? ”

Use the composite pattern whenever you need to define a part-whole tree structure where clients access the leaves and branches of the tree in the same way. ¾

”

The parent component class defines methods that are visible to clients and inherited by child leafs and composites.

The Java libraries contain multiple examples of composites: ¾

¾

¾

AWT uses the composite pattern to model the user interface component hierarchy. ƒ

Components, such as Buttons and TextAreas, make up leaf nodes, while other Components (Containers), such as Panels and Frames, are composites.

ƒ

When a Frame is asked to display itself, it recursively asks its children to do the same.

The Document Object Model (DOM) API defined in the org.w3c.dom package also uses the composite pattern. ƒ

Nodes such as Text and Attr serve as leaf nodes, while Elements and Documents are composites.

ƒ

The getChildNodes() method defined in Node returns all children of a composite and an empty NodeList for a leaf.

The Java Naming and Directory Interface (JNDI) API defined in the javax.naming package is another example of the composite pattern. ƒ

Page 382

A Context serves as the composite and a Binding represents a leaf.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

Java Design Patterns — Structural Patterns

Operand.java public class Operand extends ArithmeticComponent { private int op; ... public int evaluate() { return op; } }

This is a leaf class.

Operator.java ... public class Operator extends ArithmeticComponent { private ArrayList children; private String operator;

This is a composite class.

public Operator(String operator) { this.operator = operator; children = new ArrayList(); } public void add(ArithmeticComponent component) { children.add(component); Composites store } children in an ... internal list. public int evaluate() { int result = 0; boolean firstChild = true; Iterator it = children.iterator(); while (it.hasNext()) { ArithmeticComponent comp = it.next(); if (firstChild == true) { result = comp.evaluate(); firstChild = false; continue; } if (operator.equals("+")) result += comp.evaluate(); ...

Composites typically use recursion.

} return result; } }

Try It: Compile and run CompositeClient.java to test out the composite design pattern implementation. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 383

Advanced Java Programming

Labs …

Modify IOFacade.java to write out an object using object serialization in addition to writing text and binary files. (Solution: IOFacade2.java)

†

Test the new functionality you added in …. (Solution: FacadeClient2.java)

‡

GenericArrayAdapter.java is incomplete. It throws an UnsupportedOperationException if a client calls the remove() or removeAll() methods. Add the proper functionality to both methods using GenericArray as the adaptee. (Solution: GenericArrayAdapter2.java)

ˆ

Test the remove() and removeAll() methods that you added in ‡. (Solution: AdapterClient2.java)

‰

Add print functionality to the composite example that was covered in the chapter so that the actual expression to evaluate can be displayed to the screen. (Solutions: ArithmeticComponent2.java, Operator2.java, Operand2.java)

Š

Write an application that tests the print() method you added in ‰. (Solution: CompositeClient2.java)

Page 384

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 17

© 2011 ITCourseware, LLC

Java Design Patterns — Structural Patterns

Rev 5.1.4

Page 385

Advanced Java Programming

Page 386

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

Chapter 18 - Java Design Patterns — Behavioral Patterns

Objectives ”

Describe the purpose of Behavioral Patterns.

”

Use the Template Method pattern to define the major steps of an algorithm in a superclass and allow subclasses to implement some or all of the steps.

”

Convert a UML state diagram into Java code using the State pattern.

”

Use the Observer pattern to keep multiple display objects consistent with the underlying data that they are presenting.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 387

Advanced Java Programming

What Are Behavioral Patterns? ”

”

Page 388

Behavioral patterns deal with distributing responsibilities among the objects in your system. ¾

They are concerned with how objects communicate with each other and encapsulate flow control.

¾

As their name implies, they deal with the behavior of your system, not the structure or creation.

Just like creational and structural patterns, behavioral patterns come in two varieties: class behavioral and object behavioral. ¾

Class behavioral patterns use inheritance to model flow control.

¾

Object behavioral patterns use composition to spread behavioral responsibility between objects.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

© 2011 ITCourseware, LLC

Java Design Patterns — Behavioral Patterns

Rev 5.1.4

Page 389

Advanced Java Programming

Template — Introduction ”

Most algorithms are made up of a series of individual steps, where each step defines a portion of the algorithm. ¾

”

”

Page 390

The algorithm can be defined in a class, where each step is embedded within a method.

When you have multiple similar algorithms that contain the same series of steps in the same order, but one or more of the individual steps has to be implemented differently, you have several implementation choices: ¾

Rookie programmers would duplicate the common code across two classes.

¾

Structured programmers might implement the algorithm with an if or a switch statement that controls when to invoke each of the steps that vary.

¾

Object-oriented programmers may recognize an opportunity to use inheritance to extract the common functionality into a superclass and place the code that varies into subclasses.

¾

Enlightened OO developers with knowledge of design patterns (you!) would see this as the perfect opportunity to apply the template method design pattern.

The template method pattern defines a framework for an algorithm in a superclass and defers to subclasses to vary one or more steps of the algorithm. ¾

Use a template method in the superclass (which contains calls to each of the methods that make up the algorithm) to define the order of the steps.

¾

Define each step as a method in the superclass.

¾

You can substitute a new implementation for some or all of the superclass methods by overriding them in a subclass. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

When using this pattern, a client will call the template method that is inherited from the superclass. The template method will invoke methods in the superclass and subclass as necessary. The subclass methods do not call the superclass methods unless they've been called first. Even then, the call would be through the implicit super reference. This model is often referred to as the Hollywood principle: "Don't call us, we'll call you." The diagram below uses the term "primitive method" to identify those methods which make up the individual steps of the algorithm and whose implementation is deferred to a subclass.

AbstractClass public void templateMethod { primitiveMethod1(); concreteMethod() primitiveMethod2(); }

templateMethod() primitiveMethod1() primitiveMethod2() concreteMethod()

ConcreteClass primitiveMethod1() primitiveMethod2()

© 2011 ITCourseware, LLC

ConcreteClass2 primitiveMethod1() primitiveMethod2()

Rev 5.1.4

Page 391

Advanced Java Programming

Template — Implementation ”

To implement this pattern, you should declare an abstract class with methods for each step in the algorithm. ¾

Mark each method as abstract if its implementation will be deferred to the subclass. ƒ

¾

Implement methods that contain common, or default, functionality in the superclass; these methods are called concrete methods.

¾

You can also provide hook methods in the superclass. ƒ

¾ ”

Each method should be protected: clients should access the template method, not the individual primitive and concrete methods.

Your template method will call the algorithm methods in the appropriate order.

Create one or more subclasses that override any abstract methods, providing concrete implementations. ¾

Page 392

A hook is a concrete method with an empty implementation that can optionally be overridden in a subclass whose algorithm requires it.

You should write the template method as a public, final member of the superclass. ¾

”

These methods are often referred to as primitive methods.

You can also override hook methods if you would like.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

DatabaseAccessTemplate.java import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement;

template method

public abstract class DatabaseAccessTemplate { public void executeSQL(String driverClass, String url, String sql, String username, String password) { Connection conn = null; Statement stmt = null; try { conn = createConnection(driverClass, url, username, password); stmt = createStatement(conn); runStatement(stmt, sql); processResults(); } catch (Exception e) { System.err.println(e); } finally { cleanup(stmt, conn); primitive method } } protected abstract void runStatement(Statement stmt, String sql) throws Exception; hook method protected void processResults() throws Exception { } protected Connection createConnection(String driverClass, String url, String user, String pw) throws Exception { Class.forName(driverClass); Connection conn = DriverManager.getConnection(url, user, pw); return conn; } protected Statement createStatement(Connection c) throws Exception { Statement stmt = c.createStatement(); return stmt; } protected final void cleanup(Statement stmt, Connection conn) { try { stmt.close(); concrete methods conn.close(); } catch (Exception e) { System.out.println(e); } } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 393

Advanced Java Programming

Template — When to Use? ”

Use the template method pattern when you want to define the constant parts of an algorithm once in a superclass and allow the parts that vary to be defined by subclasses. ¾

The parts that vary are embedded in primitive methods and hooks. ƒ

Use hooks to define optional behavior.

”

This pattern makes sense when you want control of the order of an algorithm, providing opportunities for overriding certain parts.

”

The template method pattern can be created as a result of refactoring.

”

Page 394

¾

You may find situations where many classes have the same behavior.

¾

Refactor the commonality into a superclass using the template method pattern.

¾

Keep the differences in the subclasses by overriding the primitive methods.

The Java libraries use the template method in applets: ¾

When you write an applet, you extend the java.applet.Applet class.

¾

You override the init(), start(), and stop() methods to provide the applet's implementation.

¾

The template method is defined within Applet itself and guarantees that it will call init() first, then start(), then stop().

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

TemplateClient.java public class TemplateClient { public static void main(String[] args) { String driverClass = "org.apache.derby.jdbc.ClientDriver"; String url = "jdbc:derby://localhost:1527/j2se"; String username = null; String password = null; DatabaseAccessTemplate db = new DML(); String sql = "UPDATE Employee SET lastname='Smith' WHERE id=9883"; db.executeSQL(driverClass, url, sql, username, password); } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 395

Advanced Java Programming

State — Introduction ”

The term state is typically defined as an object's awareness of its attributes. ¾

Designers model the state that affects an object's behavior with a state machine. power button press power button press key press Active Standby Hibernate Shutdown

standby hibernate

shutdown

”

¾

In the above state machine, a computer can be in one of four different states, as identified by the rounded rectangles.

¾

The arrows represent state transitions.

You may choose to implement your state machine with a series of conditional statements. ¾

”

The state pattern defines a mechanism that objects use to change their behavior based on changes to the state of the system. ¾

Page 396

When you add an additional state or transition, the change will propagate throughout each of the conditionals.

The object will refer to a different state object each time a transition occurs. ƒ

The state object will embed the logic applicable to that state.

ƒ

Any method calls on the base object will be forwarded to the current state object. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

Context

«interface» State

state:State

handle()

request()

public void request { state.handle(); }

© 2011 ITCourseware, LLC

ConcreteStateA handle()

Rev 5.1.4

ConcreteStateB handle()

Page 397

Advanced Java Programming

State — Implementation ”

At the core of the state pattern implementation is an interface where you define the common methods to all of the states.

”

For each state you plan to support, create a concrete class that implements the interface.

”

Finally, create a "context" class whose state you are trying to abstract.

”

¾

Store a reference to the state interface as a field that is initialized to the initial state of the system.

¾

Delegate state-specific methods to the current state object.

You have two choices for who should create the state objects: ¾

You could create each state as it is needed, especially if you anticipate having few state transitions or if some states may never be used.

¾

Alternatively, you could store all of the state instances within the context class. ƒ

”

Another choice to make is who should control the state transitions. ¾

The context class can handle this responsibility, provided that there are a fixed number of transitions.

¾

The state classes themselves could know which state comes next, thereby adding coupling between the individual states. ƒ

Page 398

Do this if your system will change states often to keep from creating and destroying the same objects repeatedly.

You will have to add a method to the context class that the state can call to change states. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

«interface» State

Computer currentState:State

hibernate() keyPress() powerOn() shutdown() standBy()

hibernate() keyPress() powerOn() shutdown() standBy() setState(State) ...

ActiveState hibernate() keyPress() powerOn() shutdown() standBy()

HibernateState hibernate() keyPress() powerOn() shutdown() standBy()

ShutdownState

StandByState hibernate() keyPress() powerOn() shutdown() standBy()

hibernate() keyPress() powerOn() shutdown() standBy()

Computer.java public class Computer { State activeState = new ActiveState(this); State hibernateState = new HibernateState(this); State shutdownState = new ShutdownState(this); State standByState = new StandByState(this); State currentState; public Computer() { currentState = shutdownState; } public void hibernate() { currentState.hibernate(); } public void keyPress() { currentState.keyPress(); } public void powerOn() { currentState.powerOn(); } ... public void setState(State state) { currentState = state; } ...

We will store all of our state instances in the context object.

The initial state of the system is set to shutdown.

} © 2011 ITCourseware, LLC

Rev 5.1.4

Page 399

Advanced Java Programming

State — When to Use? ”

Use the state pattern when designing a system with objects whose behavior changes at runtime based on their current state.

”

Use the state pattern when you are refactoring existing code that contains conditional statements that depend on the state of an object. ¾

”

Page 400

The state pattern isolates changes to the state objects themselves, rather than spread the change across conditional statements. ƒ

Adding a new state is easy; just add a new state class.

ƒ

All state information is embedded in the state object itself.

Each state object is usually implemented as a singleton, since they typically contain client-independent operations.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

State.java public interface State { public void hibernate(); public void keyPress(); public void powerOn(); public void shutdown(); public void standBy(); }

ShutdownState.java public class ShutdownState implements State { private Computer computer; public ShutdownState(Computer comp) { computer = comp; } public void hibernate() { System.out.println("You can't hibernate a shutdown computer"); } public void keyPress() { System.out.println("Keypress doesn't wake a shutdown computer"); } public void powerOn() { System.out.println("Starting up. . ."); Modify the computer.setState(computer.getActiveState()); computer's class. } public void shutdown() { System.out.println("You can't shutdown a shutdown computer"); } public void standBy() { System.out.println("You can't standby a shutdown computer"); } }

Try It: Compile and run StateClient.java to see each state and transition exercised.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 401

Advanced Java Programming

Observer — Introduction ”

When designing user interfaces, it may be necessary to display the same information in multiple ways. ¾

”

”

ƒ

Adding a new display so that its addition does not propagate change into any other code.

Objects that are notified of state changes are call observers.

¾

The object that contains the state of interest is called the subject (or observable).

Each of your observers is responsible for updating itself each time a notification occurs. This ensures that each observer remains consistent with the underlying subject.

Adding additional observers is easy because the subject maintains a list that can be dynamically added to and removed from. Each observer instance you write will implement a parent interface that defines the method that is called by the subject when a notification occurs.

You may also have heard of this pattern referred to as the publish-subscribe pattern. ¾

Page 402

Keeping each display consistent with the underlying data.

¾

¾ ”

ƒ

Use the observer pattern to define a relationship between an object that contains state, and one or more objects that need to be notified when that state changes.

¾ ”

Two challenging design tasks are:

The subject is the publisher and each observer is a subscriber. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

«interface» Observer

«interface» Subject

update()

addObserver() removeObserver() notify()

ConcreteSubject listOfObservers state addObserver() removeObserver() notifyObservers() getState() setState()

© 2011 ITCourseware, LLC

subject

ConcreteObserver update()

public void notify() { Iterator it = listOfObservers.iterator(); while (it.hasNext()) { Observer obs = it.next(); obs.update(); } }

Rev 5.1.4

Page 403

Advanced Java Programming

Observer — Implementation ”

Implementing the observer pattern involves creating two interfaces and at least two concrete classes.

”

You should create an interface to define the subject's addObserver(), removeObserver(), and notify() methods.

”

Write another interface that specifies the update() method for the observer(s).

”

You will build one concrete class that implements the subject's interface.

”

Page 404

¾

Register the observer with the subject by storing it into a Collection when the addObserver() method is called, using the observer interface as the datatype for the Collection.

¾

Remove the observer from the Collection when removeObserver() is called.

¾

Your notify() method should iterate through all registered observers and call the update() method on them. ƒ

Call the notify() method whenever this object's state changes, usually within a setXXX() method.

ƒ

Alternatively, your client can call the notify() method when it has completed all changes to the subject.

Write at least one concrete observer class that implements the update() method from your observer interface. ¾

Pass a reference to the subject into the constructor and register the observer with the subject by calling the subject's addObserver() method.

¾

Within the update() method you should query the subject for new state information. Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

«interface» Observer

«interface» Subject addObserver() removeObserver() notify()

update()

BankAccount listOfObservers:List balance:double addObserver() removeObserver() notifyObservers() getBalance() setBalance()

subject

CurrentBalancePanel update() ... subject StatusPanel update() ...

Subject.java public interface Subject { public void addObserver(Observer observer); public void removeObserver(Observer observer); public void notifyObservers(); }

Observer.java public interface Observer { public void update(); }

Note: If you find that introducing this pattern has introduced too many calls to the update() method, then you may need to modify the pattern. The pattern as described uses a "pull" method to update the observer. The observer calls getXXX() methods on the subject to determine what state has changed; the subject is unaware of what data the observer is interested in. An alternate design would use a "push" model instead. The state that has changed could be passed directly to the update() method. The drawback to this model is that the coupling of the system has increased; the subject knows what the observers needs. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 405

Advanced Java Programming

Observer — When to Use? ”

You should use the observer pattern when you have, or anticipate having, two or more different views on underlying data. ¾

¾ ”

ƒ

The subject only knows about the parent interface that all observers implement.

ƒ

The observers store a reference to the subject and call get() methods on it when notified of state changes.

You can still get the loose coupling benefit of this pattern even if you only have one observer.

You should use the observer pattern when you want to be able to add new observers without changing the subject code. ¾

Page 406

This pattern loosely couples the subject to the observers.

The subject merely stores a collection of objects that implement the observer interface and calls update() on each of them as part of the notification process.

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

Java Design Patterns — Behavioral Patterns

CurrentBalancePanel.java ... public class CurrentBalancePanel extends JPanel implements Observer { private Subject subject; private JLabel balanceLabel; public CurrentBalancePanel(Subject subject) { this.subject = subject; balanceLabel = new JLabel(); this.add(new JLabel("Current Balance: ")); this.add(balanceLabel); subject.addObserver(this); }

The observer stores a reference to the subject.

public void update() { double currentBalance = ((BankAccount)subject).getBalance(); balanceLabel.setText("" + currentBalance); } }

StatusPanel.java ... public void update() { double currentBalance = ((BankAccount)subject).getBalance(); if (currentBalance < 0) { okBalanceLabel.setForeground(Color.GREEN.darker()); lowBalanceLabel.setForeground(Color.YELLOW.darker()); negBalanceLabel.setForeground(Color.RED); } ... } ...

Try It: Compile and run TellerGUI.java. Press the deposit and withdraw buttons to change the account balance. Watch the display to see the StatusPanel and CurrentBalancePanel automatically update themselves whenever the balance changes. Note: Java has built-in support for the observer pattern within the java.util package as defined by the Observable class and Observer interface. © 2011 ITCourseware, LLC

Rev 5.1.4

Page 407

Advanced Java Programming

Labs …

Modify the template method example that was discussed in the chapter. Create a new class called Query.java that subclasses DatabaseAccessTemplate.java. Your new class should execute a SQL SELECT statement and display the results to standard out. Test your program by listing the contents of the Employee table. (Solutions: Query.java, TemplateClient2.java)

†

Modify the state example that was discussed in the chapter to reflect the state diagram below. Test it out by modifying the existing client. (Solutions: StandByState2.java, Computer2.java, StateClient2.java, ActiveState2.java, HibernateState2.java, ShutdownState2.java)

power button press power button press power button press key press Active Standby Hibernate Shutdown

standby hibernate

shutdown

‡

Page 408

Using the observer example that was covered in the chapter, add another observer that acts as a logger. It should print the current balance to standard out every time it's notified of a change. (Solution: Logger.java, TellerGUI2.java)

Rev 5.1.4

© 2011 ITCourseware, LLC

Chapter 18

© 2011 ITCourseware, LLC

Java Design Patterns — Behavioral Patterns

Rev 5.1.4

Page 409

Advanced Java Programming

Page 410

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

Appendix A - JDBC SQL Programming

Objectives ”

Use SQLExceptions and SQLWarnings to detect and handle DBMS errors and warnings.

”

Describe the most important JDBC interfaces, and use their methods.

”

Use the JDBC datatypes to convert DBMS-specific data to Java data.

”

Use ResultSetMetaData to handle dynamicallygenerated SQL.

”

Manage DBMS transactions.

”

Use PreparedStatement objects to more efficiently run a SQL statement repeatedly.

”

Invoke DBMS stored procedures and functions from Java.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 411

Advanced Java Programming

Error Checking and the SQLException Class ”

A runtime error from the DBMS triggers a SQLException.

”

The SQLException's methods provide the standard DBMS error information:

”

¾

getSQLState() returns the ANSI-standard SQLSTATE value (if your DBMS supports it).

¾

getErrorCode() returns the vendor-specific SQLCODE error code.

¾

getMessage() is overridden by the SQLException class to return the vendor-specific error message.

A single action might result in multiple database errors, so a SQLException may have one or more additional SQLExceptions chained to it. ¾

”

getNextException() returns the next exception in the chain.

Most methods defined under java.sql throw SQLException; assume that your JDBC code needs to either catch or declare SQLException.

Page 412

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

Database programmers rely on a simple mechanism for obtaining error information from the database engine: after every database operation, the DBMS sets an error value that the programmer can check. An error is typically identified by a numeric error code (SQLCODE) and a brief error message. By convention, DBMS error codes are negative numbers; a SQLCODE value of 0 means no error has occured; and a special value, typically (but not always) +100, means there was no error, but no data was found to satisfy the operation. SQLCODE values are vendor-specific, however, so programmers must learn the specific code values for each product they program against. To relieve this situation, standards organizations introduced the SQLSTATE, a standardized, 5-character string encoding the error condition. Some DBMSs now implement SQLSTATE, though most still also return their own, vendor-specific, SQLCODE values and messages. With JDBC, when you call certain methods, Java automatically checks the SQLSTATE/SQLCODE and throws a SQLException when there is an error. SQLUtils.java ... public class SQLUtils { public static String formatSQLException(SQLException e) { StringBuilder msg = new StringBuilder(""); if (e != null) { msg.append(" SQLState: " + e.getSQLState() + "\n"); msg.append(" Code: " + e.getErrorCode() + "\n"); msg.append(" Message: " + e.getMessage() + "\n\n"); } return msg.toString(); } public static String formatSQLExceptions(SQLException e) { String msg = ""; while (e != null) { msg += formatSQLException(e); Call this method from a e = e.getNextException(); catch handler to print nice } error messages. return msg; } public static void printSQLErrors(SQLException e) { if (e != null) { System.err.println("SQL Error:\n" + formatSQLExceptions(e)); } } ...

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 413

Advanced Java Programming

The SQLWarning Class ”

The SQLWarning class extends SQLException.

”

Calls to certain methods of a Connection, Statement, or ResultSet object may generate one or more SQLWarnings. ¾

SQLWarning exceptions are never actually thrown; they do not need to be declared or caught. ƒ

¾

Use the getWarnings() method in each of these classes to get the first SQLWarning.

¾

Additional SQLWarnings will be chained to the first one. ƒ

”

When a SQLWarning is generated, it is silently chained to the object that generated it.

SQLWarning's getNextWarning() method retrieves the next warning in an object's chain.

The SQLWarning chain of a Statement object is cleared each time one of its execute methods is called; a ResultSet's SQLWarnings are cleared when each row is read.

Page 414

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

Example: A method for checking and printing SQLWarning information: { ... Connection conn; Statement stmt; conn = DriverManager.getConnection(connectURL, username, password ); stmt = conn.createStatement(); printSQLWarnings(conn.getWarnings()); ... }

SQLUtils.java ... public class SQLUtils { ... public static boolean printSQLWarnings(SQLWarning w) throws SQLException { if (w != null) { System.out.println("SQL Warning:"); while (w != null) { System.out.println(formatSQLException(w)); w = w.getNextWarning(); } return true; } else { return false; } } ... }

Note: SQLWarnings may not be generated by your driver. Check your driver documentation.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 415

Advanced Java Programming

JDBC Types ”

”

JDBC defines datatypes to separate the Java developer from the database implementation. ¾

Database vendors often support different types of data or use different names for the datatypes.

¾

The driver is responsible for converting DBMS types to JDBC types.

¾

JDBC datatypes are based on standard SQL datatypes.

When you use a getXXX() method on a ResultSet, the XXX refers to the Java type that is returned. int id = rs.getInt(1); String lastName = rs.getString(2);

¾

There is a suggested getXXX() method for each JDBC datatype, but there is usually more than one choice. ƒ

¾

getObject() works for any JDBC type.

Look in the mapping table to see which JDBC types are supported by which getXXX() methods.

”

The java.sql.Types class defines a static final int for each JDBC datatype.

”

These constants are the way that JDBC references the type.

Page 416

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

getByte()

8 9 9 9 9 9 9 9 9 9 9 9 9

getShort()

9 8 9 9 9 9 9 9 9 9 9 9 9

getInt()

9 9 8 9 9 9 9 9 9 9 9 9 9

getLong()

9 9 9 8 9 9 9 9 9 9 9 9 9

getFloat()

9 9 9 9 8 9 9 9 9 9 9 9 9

getDouble()

9 9 9 9 9 8 8 9 9 9 9 9 9

getBigDecimal()

9 9 9 9 9 9 9 8 8 9 9 9 9

getBoolean()

9 9 9 9 9 9 9 9 9 8 9 9 9

getString()

9 9 9 9 9 9 9 9 9 9 8 8 9 9 9 9 9 9 9

JAVA OBJECT

STRUCT

REF

ARRAY

BLOB

8 8 9

getBytes() getDate()

9 9 9

getTime()

9 9 9

8 9

getTimestamp()

9 9 9

9 9 8

getAsciiStream()

9 9 8 9 9 9

8

9

9 9 8

getBinaryStream()

9 9 8 9 9 9

getCharacterStream()

8

getClob()

8

getBlob()

8

getArray()

8

getRef() getObject()

CLOB

TIMESTAMP

TIME

DATE

LONGVARBINARY

VARBINARY

BINARY

LONGVARCHAR

VARCHAR

CHAR

BIT

NUMERIC

DECIMAL

DOUBLE

FLOAT

REAL

BIGINT

INTEGER

SMALLINT

TINYINT

Mapping Table

9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8

8 — Preferred

9 — Optional (can implicitly convert)

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 417

Advanced Java Programming

Executing SQL Queries ”

Use Statement's executeQuery() method to run a SQL SELECT statement, which will return a single ResultSet. ¾

If the Statement already had an open ResultSet, it is automatically closed first.

”

executeQuery() takes a single String argument: the SQL SELECT statement.

”

Dynamic SQL is simple with JDBC. ¾

Your program builds SQL query strings and passes them to executeQuery().

¾

The database parses and compiles the query string each time you call executeQuery().

¾

Use a PreparedStatement to create a pre-compiled or parameterized statement for improved performance when executing the same SQL statement repeatedly.

Page 418

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

EmpSals.java ... public class EmpSals { public static void main(String args[]) { try { Class.forName("org.apache.derby.jdbc.ClientDriver"); String url = "jdbc:derby://localhost:1527/j2se"; Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); String sqltxt; sqltxt = "SELECT firstname, lastname, salary, department_name" + " FROM employee, department " + " WHERE employee.department_code=department.department_code"; ResultSet rs = stmt.executeQuery(sqltxt); String name; List all of the employees String dept; and their departments. float salary; while (rs.next()) { name = rs.getString("FIRSTNAME") + " " + rs.getString("LASTNAME"); dept = rs.getString("DEPARTMENT_NAME"); salary = rs.getFloat("SALARY"); System.out.println(name + "\t" + dept + "\t" + salary); } stmt.close(); conn.close(); } catch (ClassNotFoundException cnfe) { System.out.println("Unable to load driver class: " + cnfe); System.exit(1); } catch (SQLException sqle) { System.out.println("SQL Error:"); System.out.println(" Code: " + sqle.getErrorCode()); System.out.println(" Message: " + sqle.getMessage()); System.exit(1); } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 419

Advanced Java Programming

ResultSetMetaData ”

For queries built at runtime for which you need to determine the number, types, names, etc. of columns of a ResultSet, get the ResultSet's metadata. ResultSetMetaData rsmd = rs.getMetaData();

”

A ResultSetMetaData object's methods return information about the columns of its ResultSet. int getColumnCount() String getColumnName(int column) String getColumnLabel(int column) int getColumnType(int column) String getColumnTypeName(int column) int getPrecision(int column) int getScale(int column) int getColumnDisplaySize(int column) int isNullable(int column) boolean isReadOnly(int column) boolean isCurrency(int column)

etc... ¾ ”

getColumnType() returns an int corresponding to a constant defined in java.sql.Types. ¾

”

All of these methods may throw SQLException.

This can be useful in determining which getXXX() method to call.

ResultSetMetaData is valuable when: ¾

execute() was used to run some arbitrary query.

¾

executeQuery() was used to run a query statement that was generated at runtime.

Page 420

Rev 5.1.4

© 2011 ITCourseware, LLC

Appendix A

JDBC SQL Programming

ExecuteFormat.java ... public class ExecuteFormat { public static void main(String args[]) throws ClassNotFoundException { ... ResultSetMetaData rsmd = rs.getMetaData(); int cols = rsmd.getColumnCount(); int colWidth[] = new int[cols]; String resultLine = ""; for (int col=1; col (cbuf.limit() - cbuf.position())) { cbuf.flip(); channel.write(buf); buf.clear(); cbuf.clear(); } cbuf.put(csName); cbuf.put('\n'); } cbuf.flip(); channel.write(buf); channel.close(); } catch (Exception e) { e.printStackTrace(); } } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 477

Advanced Java Programming

Chapter 4 Reflect1.java import import import import import

java.io.File; java.io.FileFilter; java.lang.reflect.Constructor; java.lang.reflect.Method; java.util.Vector;

public class Reflect1 implements IReflect { public static void main(String[] args) { Reflect1 reflect = new Reflect1(); ReflectFrame frame = new ReflectFrame(reflect); frame.setVisible(true); } public Vector getCtors(String className) { Vector v = new Vector(); try { Class cls = Class.forName(className); Constructor[] ctors = cls.getDeclaredConstructors(); for (Constructor ctor : ctors) { v.add(ctor); } } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } return v; } public Object instantiate(Constructor ctor, Object[] args) { Object o = null; // fill in code here return o; } public Vector getMethods(Object obj) { Vector v = new Vector(); // fill in code here return v; } public Object invoke(Method method, Object target, Object[] args) { Object retValue = null; // fill in code here Page 478

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Reflect1.java (cont'd) return retValue; } public Vector getClasses() { Vector v = new Vector(); File curDir = new File("."); File[] classFiles = curDir.listFiles(new FileFilter() { public boolean accept(File f) { return f.getName().contains(".class"); }}); for (File file : classFiles) { String name = file.getName(); name = name.substring(0, name.indexOf(".class")); v.add(name); } return v; } }

Reflect2.java import import import import import

java.io.File; java.io.FileFilter; java.lang.reflect.Constructor; java.lang.reflect.Method; java.util.Vector;

public class Reflect2 implements IReflect { public static void main(String[] args) { Reflect2 reflect = new Reflect2(); ReflectFrame frame = new ReflectFrame(reflect); frame.setVisible(true); } public Vector getCtors(String className) { Vector v = new Vector(); try { Class cls = Class.forName(className); Constructor[] ctors = cls.getDeclaredConstructors(); for (Constructor ctor : ctors) { v.add(ctor); } } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 479

Advanced Java Programming

Chapter 4 (cont'd) Reflect2.java (cont'd) return v; } public Object instantiate(Constructor ctor, Object[] args) { Object o = null; try { o = ctor.newInstance(args); } catch (Exception e) { e.printStackTrace(); } return o; } public Vector getMethods(Object obj) { Vector v = new Vector(); // fill in code here return v; } public Object invoke(Method method, Object target, Object[] args) { Object retValue = null; // fill in code here return retValue; } public Vector getClasses() { Vector v = new Vector(); File curDir = new File("."); File[] classFiles = curDir.listFiles(new FileFilter() { public boolean accept(File f) { return f.getName().contains(".class"); }}); for (File file : classFiles) { String name = file.getName(); name = name.substring(0, name.indexOf(".class")); v.add(name); } return v; } }

Page 480

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Reflect3.java import import import import import

java.io.File; java.io.FileFilter; java.lang.reflect.Constructor; java.lang.reflect.Method; java.util.Vector;

public class Reflect3 implements IReflect { public static void main(String[] args) { Reflect3 reflect = new Reflect3(); ReflectFrame frame = new ReflectFrame(reflect); frame.setVisible(true); } public Vector getCtors(String className) { Vector v = new Vector(); try { Class cls = Class.forName(className); Constructor[] ctors = cls.getDeclaredConstructors(); for (Constructor ctor : ctors) { v.add(ctor); } } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } return v; } public Object instantiate(Constructor ctor, Object[] args) { Object o = null; try { o = ctor.newInstance(args); } catch (Exception e) { e.printStackTrace(); } return o; } public Vector getMethods(Object obj) { Vector v = new Vector(); Class cls = obj.getClass(); Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { v.add(method); } return v;

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 481

Advanced Java Programming

Chapter 4 (cont'd) Reflect3.java (cont'd) } public Object invoke(Method method, Object target, Object[] args) { Object retValue = null; // fill in code here return retValue; } public Vector getClasses() { Vector v = new Vector(); File curDir = new File("."); File[] classFiles = curDir.listFiles(new FileFilter() { public boolean accept(File f) { return f.getName().contains(".class"); }}); for (File file : classFiles) { String name = file.getName(); name = name.substring(0, name.indexOf(".class")); v.add(name); } return v; } }

Reflect4.java import import import import import

java.io.File; java.io.FileFilter; java.lang.reflect.Constructor; java.lang.reflect.Method; java.util.Vector;

public class Reflect4 implements IReflect { public static void main(String[] args) { Reflect4 reflect = new Reflect4(); ReflectFrame frame = new ReflectFrame(reflect); frame.setVisible(true); } public Vector getCtors(String className) { Vector v = new Vector(); try { Class cls = Class.forName(className); Constructor[] ctors = cls.getDeclaredConstructors(); Page 482

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Reflect4.java (cont'd) for (Constructor ctor : ctors) { v.add(ctor); } } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } return v; } public Object instantiate(Constructor ctor, Object[] args) { Object o = null; try { o = ctor.newInstance(args); } catch (Exception e) { e.printStackTrace(); } return o; } public Vector getMethods(Object obj) { Vector v = new Vector(); Class cls = obj.getClass(); Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { v.add(method); } return v; } public Object invoke(Method method, Object target, Object[] args) { Object retValue = null; try { retValue = method.invoke(target, args); } catch (Exception e) { e.printStackTrace(); } return retValue; } public Vector getClasses() { Vector v = new Vector(); File curDir = new File("."); File[] classFiles = curDir.listFiles(new FileFilter() { public boolean accept(File f) { return f.getName().contains(".class"); }}); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 483

Advanced Java Programming

Chapter 4 (cont'd) Reflect4.java (cont'd) for (File file : classFiles) { String name = file.getName(); name = name.substring(0, name.indexOf(".class")); v.add(name); } return v; } }

Page 484

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 5 ImageToFile.java import import import import import import

java.io.FileOutputStream; java.sql.Blob; java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement;

public class ImageToFile { public static void main(String args[]) { try { Class.forName("org.apache.derby.jdbc.ClientDriver"); String url = "jdbc:derby://localhost:1527/j2se"; Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT lastname, mugshot " + "FROM employee " + "WHERE mugshot IS NOT NULL"); while (rs.next()) { String filepath = rs.getString(1) + ".gif"; Blob b = rs.getBlob(2); FileOutputStream ostream = new FileOutputStream(filepath); ostream.write(b.getBytes(1, (int)b.length())); ostream.close(); System.out.println("Image saved as " + filepath); } stmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); } } }

LongTermEmps.java import java.sql.Connection; import java.sql.DriverManager; © 2011 ITCourseware, LLC

Rev 5.1.4

Page 485

Advanced Java Programming

Chapter 5 (cont'd) LongTermEmps.java (cont'd) import import import import

java.sql.ResultSet; java.sql.Statement; javax.sql.rowset.CachedRowSet; com.sun.rowset.CachedRowSetImpl;

public class LongTermEmps { public static void main(String args[]){ try { Class.forName("org.apache.derby.jdbc.ClientDriver"); String url = "jdbc:derby://localhost:1527/j2se"; Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet result = stmt.executeQuery( "SELECT lastname, hire_date, salary " + "FROM employee " + "WHERE hire_date < {d '1995-01-01'}"); CachedRowSet crs = new CachedRowSetImpl(); crs.populate(result); while (crs.next()) { System.out.println(crs.getString("lastname") + " crs.getString("hire_date") + " " + crs.getString("salary")); } crs.close(); stmt.close(); conn.close();

" +

} catch (Exception e) { e.printStackTrace(); } } }

LongTermEmps2.java import import import import import Page 486

java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement; javax.sql.rowset.CachedRowSet; Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

LongTermEmps2.java (cont'd) import com.sun.rowset.CachedRowSetImpl; public class LongTermEmps2 { public static void main(String args[]){ try { Class.forName("org.apache.derby.jdbc.ClientDriver"); String url = "jdbc:derby://localhost:1527/j2se"; Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet result = stmt.executeQuery( "SELECT lastname, hire_date, salary " + "FROM employee " + "WHERE hire_date < {d '1995-01-01'}"); CachedRowSet crs = new CachedRowSetImpl(); crs.populate(result); stmt.close(); while (crs.next()) { System.out.println(crs.getString("lastname") + " crs.getString("hire_date") + " " + crs.getString("salary"));

" +

if (crs.getFloat("salary") < 50000) crs.updateFloat("salary",50000); crs.updateRow(); } crs.acceptChanges(conn); crs.close(); conn.close(); } catch (Exception e) { e.printStackTrace(); } } }

LongTermEmps3.java import import import import import

java.sql.Connection; java.sql.DriverManager; java.sql.ResultSet; java.sql.Statement; javax.sql.rowset.CachedRowSet;

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 487

Advanced Java Programming

Chapter 5 (cont'd) LongTermEmps3.java (cont'd) import com.sun.rowset.CachedRowSetImpl; public class LongTermEmps3 { public static void main(String args[]){ try { Class.forName("org.apache.derby.jdbc.ClientDriver"); String url = "jdbc:derby://localhost:1527/j2se"; Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet result = stmt.executeQuery( "SELECT id, lastname, firstname, hire_date, salary " + "FROM employee " + "WHERE hire_date < {d '1995-01-01'}"); CachedRowSet crs = new CachedRowSetImpl(); crs.populate(result); crs.moveToInsertRow(); crs.updateInt("id",1000); crs.updateString("lastname","Seitz"); crs.updateString("firstname","Robert"); crs.updateFloat("salary",100000); crs.insertRow(); crs.moveToCurrentRow(); while (crs.next()) { System.out.println(crs.getString("lastname") + " crs.getString("hire_date") + " " + crs.getString("salary")); } crs.setTableName("employee"); crs.acceptChanges(conn); crs.close(); conn.close();

" +

} catch (Exception e) { e.printStackTrace(); } } } Page 488

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 6 GetImage.java import import import import import

java.io.IOException; java.io.InputStream; java.io.FileOutputStream; java.net.URL; java.net.URLConnection;

public class GetImage { public static void main(String args[]) { if (args.length == 0) { System.err.println("usage: java GetImage image_URL"); System.exit(1); } URL imgURL = null; URLConnection imgConn = null; String imgType = null; try { imgURL = new URL(args[0]); imgConn = imgURL.openConnection(); // connect explicitly to catch connection problem exceptions imgConn.connect(); // Check the content-type to make sure it is an image imgType = imgConn.getContentType(); if (! imgType.startsWith("image/")) { System.err.println(args[0] + ": not an image"); System.exit(2); } // extract the specific image type from the content-type value imgType = imgType.substring(imgType.indexOf('/') + 1); } catch (IOException e) { System.err.println("Error establishing URL connection: " + e); System.exit(3); } String fileName = "image." + imgType; byte[] buffer = new byte[1000]; FileOutputStream imgFile = null; InputStream imgStream = null; try { © 2011 ITCourseware, LLC

Rev 5.1.4

Page 489

Advanced Java Programming

Chapter 6 (cont'd) GetImage.java (cont'd) imgFile = new FileOutputStream(fileName); imgStream = imgConn.getInputStream(); int len = -1; while ((len = imgStream.read(buffer)) != -1) { imgFile.write(buffer, 0, len); } } catch (IOException ioex) { System.err.println("Error copying image: " + ioex); System.exit(3); } finally { if (imgFile != null) { try { imgFile.close(); } catch (IOException ignore) {} } if (imgStream != null) { try { imgStream.close(); } catch (IOException ignore) {} } } } }

SendFile.java import import import import import

java.io.IOException; java.io.OutputStream; java.io.FileInputStream; java.net.ServerSocket; java.net.Socket;

public class SendFile { public static void main(String[] args) { String file = "data.txt"; int port = 8000; ServerSocket ss = null; Socket s = null; Page 490

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

SendFile.java (cont'd) OutputStream sockout = null; byte[] data = null; // contents of the file try { FileInputStream in = new FileInputStream(file); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { System.err.println("Error reading " + file + ": " + e); System.exit(1); } try { ss = new ServerSocket(port); while (true) { // wait for the connection s = ss.accept(); // build sockout from the socket's Output Stream sockout = s.getOutputStream(); // Tell the user that we've connected System.out.println("Connected to " + s.getInetAddress() + ":"+ s.getPort()); // Send the client the contents of the file sockout.write(data); s.close(); } } catch (IOException e) { System.err.println(e) ; } finally { // Always be sure to close the sockets to release resources if (ss != null) { try { ss.close(); } catch (IOException ignore) {} © 2011 ITCourseware, LLC

Rev 5.1.4

Page 491

Advanced Java Programming

Chapter 6 (cont'd) SendFile.java (cont'd) } if (s != null) { try { s.close(); } catch (IOException ignore) {} } } } }

data.txt There's nothing very mysterious about you, except that nobody really knows your origin, purpose, or destination. Tact, n.: The unsaid part of what you're thinking. The most exciting phrase to hear in science, the one that heralds new discoveries, is not "Eureka!" (I found it!) but "That's funny ..." -- Isaac Asimov My pen is at the bottom of a page, Which, being finished, here the story ends; 'Tis to be wished it had been sooner done, But stories somehow lengthen when begun. -- Byron Speaking of love, one problem that recurs more and more frequently these days, in books and plays and movies, is the inability of people to communicate with the people they love; Husbands and wives who can't communicate, children who can't communicate with their parents, and so on. And the characters in these books and plays and so on (and in real life, I might add) spend hours bemoaning the fact that they can't communicate. I feel that if a person can't communicate, the very _____ least he can do is to shut up! -- Tom Lehrer, "That Was the Year that Was" My idea of roughing it is when room service is late. A list is only as strong as its weakest link. -- Don Knuth Page 492

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

data.txt (cont'd) Her days were spent in a kind of slow bustle; always busy without getting on, always behind hand and lamenting it, without altering her ways; wishing to be an economist, without contrivance or regularity; dissatisfied with her servants, without skill to make them better, and whether helping, or reprimanding, or indulging them, without any power of engaging their respect. -- J. Austen GetFile.java import import import import import

java.io.IOException; java.io.BufferedReader; java.io.InputStreamReader; java.net.Socket; java.net.InetAddress;

public class GetFile { public static void main(String[] args) { Socket s = null; BufferedReader sockin = null; try { // create the connection s = new Socket(InetAddress.getLocalHost(), 8000); // create a BufferedReader to read lines from the server output sockin = new BufferedReader( new InputStreamReader(s.getInputStream())); // Tell the user that we've connected System.out.println("Connected to " + s.getInetAddress() + ":"+ s.getPort()); // read what the server sends String linein = null; while((linein = sockin.readLine()) != null) { System.out.println(linein); } } catch (IOException e) { System.err.println(e); } // Always be sure to close the socket to release resources finally { if (s != null) { try { s.close(); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 493

Advanced Java Programming

Chapter 6 (cont'd) GetFile.java (cont'd) } catch (IOException ignore) {} } } } }

ServerStatistics.java public class ServerStatistics implements java.io.Serializable { private String fileName; private int connectionCount; private int port; public ServerStatistics(String fnam, int port, int count) { fileName = fnam; this.port = port; connectionCount = count; } public String getFileName() { return fileName; } public int getConnectionCount() { return connectionCount; } public int getPort() { return port; } public void incrementConnectionCount() { connectionCount += 1; } public String toString() { StringBuilder result = new StringBuilder("ServerStatistics:"); result.append(" serving file ").append(fileName); result.append(" on port ").append(port); result.append(" ").append(connectionCount); result.append(" connections."); return result.toString(); } }

Page 494

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

SendFile2.java import import import import import import

java.io.IOException; java.io.FileInputStream; java.io.ObjectOutputStream; java.io.OutputStream; java.net.ServerSocket; java.net.Socket;

public class SendFile2 { public static void main(String[] args) { String file = "data.txt"; int port = 8000; int adminPort = 9000; ServerStatistics statistics = new ServerStatistics(file, port, 0); ServerSocket ss = null; Socket s = null; OutputStream sockout = null; byte[] data = null; // contents of the file try { FileInputStream in = new FileInputStream(file); data = new byte[in.available()]; in.read(data); in.close(); } catch (IOException e) { System.err.println("Error reading " + file + ": " + e); System.exit(1); } // start a thread listening for admin requests new AdminThread(adminPort, statistics).start(); try { ss = new ServerSocket(port); while (true) { // wait for the connection s = ss.accept(); statistics.incrementConnectionCount(); // build sockout from the socket's Output Stream © 2011 ITCourseware, LLC

Rev 5.1.4

Page 495

Advanced Java Programming

Chapter 6 (cont'd) SendFile2.java (cont'd) sockout = s.getOutputStream(); // Tell the user that we've connected System.out.println("Connected to " + s.getInetAddress() + ":"+ s.getPort()); // Send the client the contents of the file sockout.write(data); s.close(); } } catch (IOException e) { System.err.println(e) ; } finally { // Always be sure to close the sockets to release resources if (ss != null) { try { ss.close(); } catch (IOException ignore) {} } if (s != null) { try { s.close(); } catch (IOException ignore) {} } } } } class AdminThread extends Thread { private int adminPort; private ServerStatistics statistics; AdminThread(int adminPort, ServerStatistics statistics) { this.adminPort = adminPort; this.statistics = statistics; } Page 496

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

SendFile2.java (cont'd) public void run() { ServerSocket ss = null; Socket s = null; ObjectOutputStream sockout = null; try { ss = new ServerSocket(adminPort); while (true) { s = ss.accept(); sockout = new ObjectOutputStream(s.getOutputStream()); // Tell the user that we've connected System.out.println("Connected to admin client " + s.getInetAddress() + ":"+ s.getPort()); sockout.writeObject(statistics); s.close(); } } catch (IOException e) { System.err.println("Error in admin thread: " + e) ; } finally { // Always be sure to close the sockets to release resources if (ss != null) { try { ss.close(); } catch (IOException ignore) {} } if (s != null) { try { s.close(); } catch (IOException ignore) {} } } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 497

Advanced Java Programming

Chapter 6 (cont'd) AdminClient.java import import import import

java.io.ObjectInputStream; java.io.IOException; java.net.Socket; java.net.InetAddress;

public class AdminClient { public static void main(String args[]) { Socket s = null; ObjectInputStream sockin = null; try { // Connect to the server's admin port s = new Socket(InetAddress.getLocalHost(), 9000); sockin = new ObjectInputStream(s.getInputStream()); // Tell the user that we've connected System.out.println("Connected to " + s.getInetAddress() + ":" + s.getPort()); // get the statistics object ServerStatistics stats = (ServerStatistics)sockin.readObject(); System.out.println(stats); } catch (IOException ioe) { System.err.println("Error connecting to server: " + ioe); } catch (ClassNotFoundException e) { System.err.println( "Error reading ServerStatistics obj from admin server " + e); } finally { if (s != null) { try { s.close(); } catch (IOException ignore) {} } } } } Page 498

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 7 Customer1.java import java.rmi.Naming; public class Customer1 { public static void main(String[] args) { try { Store store = (Store) Naming.lookup("///Store"); Attendant attendant = store.getAttendant(); int orderNumber = attendant.submitOrder("hdw123", 5); System.out.println("The order number is: " + orderNumber); attendant.release(); } catch (Exception e) { System.err.println(e); } } }

Attendant2.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Attendant2 extends Remote { public int submitOrder(Order order) throws RemoteException; public boolean release() throws RemoteException; }

AttendantServer2.java import import import import import import import import

java.rmi.NoSuchObjectException; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.text.DateFormat; java.util.Date; java.util.HashMap; java.util.Map; java.util.TimeZone;

public class AttendantServer2 extends UnicastRemoteObject implements Attendant2 { private DateFormat tf; private StoreServer2 store; © 2011 ITCourseware, LLC

Rev 5.1.4

Page 499

Advanced Java Programming

Chapter 7 (cont'd) AttendantServer2.java (cont'd) public AttendantServer2(StoreServer2 store) throws RemoteException { this.store = store; tf = DateFormat.getTimeInstance(); tf.setTimeZone(TimeZone.getDefault()); } public int submitOrder(Order order) { int orderNum = StoreServer2.getOrderNumber(); System.out.println("Order #" + orderNum + " received at " + tf.format(new Date())); HashMap items = order.getItems(); for (Map.Entry item : items.entrySet() ) { System.out.println(" Item: " + item.getKey() + " quantity: " + item.getValue()); } return orderNum; } public boolean release() { boolean success = false; try { success = UnicastRemoteObject.unexportObject(this, false); } catch (NoSuchObjectException e) { System.err.println(e); } return success; } }

Customer2.java import java.rmi.Naming; public class Customer2 { public static void main(String[] args) { try { Store2 store = (Store2) Naming.lookup("///Store2"); Attendant2 attendant = store.getAttendant(); Page 500

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Customer2.java (cont'd) Order order = new Order(); order.add("hdw123", 5); order.add("app456", 2); order.add("per789", 3); int orderNumber = attendant.submitOrder(order); System.out.println("The order number is: " + orderNumber); attendant.release(); } catch (Exception e) { System.err.println(e); } } }

Order.java import java.util.HashMap; public class Order implements java.io.Serializable { private HashMap orderItems; public Order() { orderItems = new HashMap(); } public void add(String itemCode, int quantity) { orderItems.put(itemCode, new Integer(quantity)); } public HashMap getItems() { return orderItems; } }

Store2.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Store2 extends Remote { public Attendant2 getAttendant() throws RemoteException; }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 501

Advanced Java Programming

Chapter 7 (cont'd) StoreServer2.java import import import import import import

java.rmi.Naming; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.util.Collection; java.util.HashMap; java.util.Set;

public class StoreServer2 extends UnicastRemoteObject implements Store2 { private HashMap items; private static int nextOrder=1; public StoreServer2() throws RemoteException { items = new HashMap(); items.put("hdw123", new ItemImpl("hdw123", "1 GB SIM", 50)); items.put("hdw124", new ItemImpl("hdw124", "60 GB HD", 30)); items.put("hdw125", new ItemImpl("hdw125", "80 GB HD", 25)); items.put("per456", new ItemImpl("per456", "InkJet Printer", 36)); items.put("per457", new ItemImpl("per457", "Laser Printer", 4)); } public Attendant2 getAttendant() throws RemoteException { return new AttendantServer2(this); } public Set getCodes() { return items.keySet(); } public Collection getItems() { return items.values(); } public Item getItem(String code) { return items.get(code); } public static synchronized int getOrderNumber() { return nextOrder++; } public static void main(String[] args) { try { StoreServer2 store = new StoreServer2(); Naming.rebind("///Store2", store); } catch (java.net.MalformedURLException e) { System.err.println(e); Page 502

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

StoreServer2.java (cont'd) } catch (RemoteException e) { System.err.println(e); } } }

Attendant3.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Attendant3 extends Remote { public String[] listItems() throws RemoteException; public Item3 getItem(String code) throws RemoteException; public int submitOrder(Order order) throws RemoteException; public boolean release() throws RemoteException; }

AttendantServer3.java import import import import import import import import import

java.rmi.NoSuchObjectException; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.text.DateFormat; java.util.Date; java.util.HashMap; java.util.Map; java.util.Set; java.util.TimeZone;

public class AttendantServer3 extends UnicastRemoteObject implements Attendant3 { private DateFormat tf; private StoreServer3 store; public AttendantServer3(StoreServer3 store) throws RemoteException { this.store = store; tf = DateFormat.getTimeInstance(); tf.setTimeZone(TimeZone.getDefault()); } public String[] listItems() { Set codeSet = store.getCodes(); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 503

Advanced Java Programming

Chapter 7 (cont'd) AttendantServer3.java (cont'd) String[] codes = new String[codeSet.size()]; return codeSet.toArray(codes); } public Item3 getItem(String code) { return store.getItem(code); } public int submitOrder(Order order) throws RemoteException { int orderNum = StoreServer3.getOrderNumber(); System.out.println("Order #" + orderNum + " received at " + tf.format(new Date())); HashMap items = order.getItems(); for (Map.Entry item : items.entrySet() ) { Item3 invItem = store.getItem(item.getKey()); int onHand = invItem.getQuantityOnHand(); int orderQuantity = item.getValue().intValue(); System.out.println(" item.getValue());

Item: " + item.getKey() + " quantity: " +

if (onHand < orderQuantity) { System.out.println(" backordered"); } else { ItemImpl3 impl = (ItemImpl3) invItem; impl.setQuantityOnHand(onHand - orderQuantity); } } return orderNum; } public boolean release() { boolean success = false; try { success = UnicastRemoteObject.unexportObject(this, false); } catch (NoSuchObjectException e) { System.err.println(e); } return success; } } Page 504

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Customer3.java import java.rmi.Naming; public class Customer3 { public static void main(String[] args) { try { Store3 store = (Store3) Naming.lookup("///Store3"); Attendant3 attendant = store.getAttendant(); String[] itemCodes = attendant.listItems(); System.out.println("All item codes: "); for (String code : itemCodes) { System.out.println("Item Code: " + code); } System.out.println(); Item3 i = attendant.getItem("hdw123"); System.out.println("Item Code: " + i.getItemCode() + " Description: " + i.getDescription() + " Quantity On Hand: " + i.getQuantityOnHand()); Order order = new Order(); order.add("hdw123", 5); order.add("per456", 3); int orderNumber = attendant.submitOrder(order); System.out.println("The order number is: " + orderNumber); System.out.println("Item Code: " + i.getItemCode() + " Description: " + i.getDescription() + " Quantity On Hand: " + i.getQuantityOnHand()); attendant.release(); } catch (Exception e) { System.err.println(e); } } }

Item3.java import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; public interface Item3 extends Remote { © 2011 ITCourseware, LLC

Rev 5.1.4

Page 505

Advanced Java Programming

Chapter 7 (cont'd) Item3.java (cont'd) public String getItemCode() throws RemoteException; public String getDescription() throws RemoteException; public int getQuantityOnHand() throws RemoteException; } class ItemImpl3 extends UnicastRemoteObject implements Item3 { private String itemCode; private String description; private int quantityOnHand; public ItemImpl3() throws RemoteException { } public ItemImpl3(String code, String desc, int quantity) throws RemoteException { itemCode = code; description = desc; quantityOnHand = quantity; } public String getItemCode() { return itemCode; } public void setItemCode(String code) { itemCode = code; } public String getDescription() { return description; } public void setDescription(String desc) { description = desc; } public int getQuantityOnHand() { return quantityOnHand; } public void setQuantityOnHand(int q) { quantityOnHand = q; } }

Page 506

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Store3.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Store3 extends Remote { public Attendant3 getAttendant() throws RemoteException; }

StoreServer3.java import import import import import import

java.rmi.Naming; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.util.Collection; java.util.HashMap; java.util.Set;

public class StoreServer3 extends UnicastRemoteObject implements Store3 { private HashMap items; private static int nextOrder=1; public StoreServer3() throws RemoteException { items = new HashMap(); items.put("hdw123", new ItemImpl3("hdw123", "1 GB SIM", 50)); items.put("hdw124", new ItemImpl3("hdw124", "60 GB HD", 30)); items.put("hdw125", new ItemImpl3("hdw125", "80 GB HD", 25)); items.put("per456", new ItemImpl3("per456", "InkJt Printer", 36)); items.put("per457", new ItemImpl3("per457", "Laser Printer", 4)); } public Attendant3 getAttendant() throws RemoteException { return new AttendantServer3(this); } public Set getCodes() { return items.keySet(); } public Collection getItems() { return items.values(); } public Item3 getItem(String code) { return items.get(code); } public static synchronized int getOrderNumber() { return nextOrder++; } public static void main(String[] args) { © 2011 ITCourseware, LLC

Rev 5.1.4

Page 507

Advanced Java Programming

Chapter 7 (cont'd) StoreServer3.java (cont'd) try { StoreServer3 store = new StoreServer3(); Naming.rebind("///Store3", store); } catch (java.net.MalformedURLException e) { System.err.println(e); } catch (RemoteException e) { System.err.println(e); } } }

Page 508

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 8 ChatIF.java import java.rmi.Remote; import java.rmi.RemoteException; public interface ChatIF extends Remote { public void postChat(String msg, String sender) throws RemoteException; public void registerForNotification(Notifiable n) throws RemoteException; }

ChatServer.java import import import import import

java.rmi.Naming; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.util.HashSet; java.util.Iterator;

public class ChatServer extends UnicastRemoteObject implements ChatIF { private HashSet listeners = null; public ChatServer() throws RemoteException { listeners = new HashSet(); } public void postChat(String msg, String sender) { System.out.println(sender + ": " + msg); Iterator it = listeners.iterator(); while (it.hasNext()) { Notifiable not = it.next(); try { not.notify(msg, sender); } catch (Exception e) { System.err.println(e); } } } public void registerForNotification(Notifiable n) { if (!listeners.contains(n)) { © 2011 ITCourseware, LLC

Rev 5.1.4

Page 509

Advanced Java Programming

Chapter 8 (cont'd) ChatServer.java (cont'd) listeners.add(n); } } public static void main(String[] args) { try { ChatServer c = new ChatServer(); Naming.rebind("//localhost:1099/chat", c); System.out.println("Chat bound."); } catch (Exception e) { System.err.println(e); } } }

Notifiable.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Notifiable extends Remote { public void notify(String msg, String sender) throws RemoteException; }

ChatClient.java import import import import import

java.rmi.Naming; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.io.InputStreamReader; java.io.BufferedReader;

public class ChatClient extends UnicastRemoteObject implements Notifiable { public ChatClient() throws RemoteException{ BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Please enter alias: "); try { String alias = in.readLine(); Page 510

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

ChatClient.java (cont'd) ChatIF c = (ChatIF)Naming.lookup("//localhost:1099/chat"); c.registerForNotification(this); while (true) { System.out.print("Enter a chat message, '##' to quit: "); String line = in.readLine(); if (line.equalsIgnoreCase("##")) { System.exit(0); } c.postChat(line, alias); } } catch (Exception e) { System.err.println(e); } } public void notify(String msg, String sender) { System.out.println("\n" + sender + ": " + msg); } public static void main(String[] args) { try { new ChatClient(); } catch (RemoteException e) { System.err.println(e); } } }

ISBN_IF.java import java.rmi.Remote; import java.rmi.RemoteException; public interface ISBN_IF extends Remote { public String getTitle(String isbn) throws RemoteException; }

ISBN_Impl.java import import import import import

java.rmi.MarshalledObject; java.rmi.RemoteException; java.rmi.activation.Activatable; java.rmi.activation.ActivationID; java.util.HashMap;

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 511

Advanced Java Programming

Chapter 8 (cont'd) ISBN_Impl.java (cont'd) public class ISBN_Impl extends Activatable implements ISBN_IF { private HashMap map = null; public ISBN_Impl(ActivationID id, MarshalledObject data) throws RemoteException { super(id, 0); map = new HashMap(); map.put("0131483986", "Java How to Program"); map.put("1586639161 ", "Java"); map.put("0201310058", "Effective Java Programming Language Guide"); map.put("0321305027 ", "The Java Developer's Guide to Eclipse"); map.put("0596009208 ", "Head First Java"); map.put("0596007736", "Java in a Nutshell"); } public String getTitle(String isbn) { String title = map.get(isbn); return title; } }

rmid.policy /* allow the JVM for an activation group to specify a security policy */ grant { permission com.sun.rmi.rmid.ExecOptionPermission "Djava.security.policy=*"; };

group.policy /* allow remote objects in the activation group to accept * connetcionts on any non-privileged port */ grant { permission java.net.SocketPermission "*:1024-", "accept,resolve"; };

Page 512

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

ISBNSetup.java import import import import import import import

java.rmi.Naming; java.rmi.activation.Activatable; java.rmi.activation.ActivationDesc; java.rmi.activation.ActivationGroup; java.rmi.activation.ActivationGroupDesc; java.rmi.activation.ActivationGroupID; java.util.Properties;

public class ISBNSetup { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println( "usage: java -Djava.rmi.server.codebase=codebase_url" + "ISBNSetup activation_group_policy_file"); System.exit(1); } String policy = args[0]; Properties props = new Properties(); props.put("java.security.policy", policy); ActivationGroupDesc group = new ActivationGroupDesc(props, null); ActivationGroupID groupId = ActivationGroup.getSystem().registerGroup(group); // copy the activation group's codebase from the system property String codebase = System.getProperty("java.rmi.server.codebase"); ActivationDesc desc = new ActivationDesc (groupId, "ISBN_Impl", codebase, null); // Register the interface with the activation system (rmid) ISBN_IF isbn = (ISBN_IF)Activatable.register(desc); System.out.println("Got stub for ISBN"); // Bind it in the registry (rmiregistry) Naming.rebind("ISBNImpl", isbn); System.out.println("Exported ISBN_Impl"); } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 513

Advanced Java Programming

Chapter 8 (cont'd) titles.txt 0131483986, Java How to Program 1586639161, Java 0201310058, Effective Java Programming Language Guide 0321305027, The Java Developer's Guide to Eclipse 0596009208, Head First Java 0596007736, Java in a Nutshell ISBNClient.java import java.rmi.Naming; public class ISBNClient { public static void main(String args[]) { try { String loc = "rmi://localhost/ISBNImpl"; ISBN_IF isbn = (ISBN_IF) Naming.lookup(loc); String result = isbn.getTitle("0201310058"); System.out.println("Title for 0201310058: " + result); } catch (Exception e) { System.err.println(e); } } }

StockServer2.java import import import import import import import import import

java.rmi.RemoteException; java.util.HashMap; java.util.HashSet; java.util.Iterator; java.util.Map; java.util.Set; javax.naming.Context; javax.naming.InitialContext; javax.rmi.PortableRemoteObject;

public class StockServer2 extends PortableRemoteObject implements Stock { Map clients; Page 514

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

StockServer2.java (cont'd) Map stocks = null; public StockServer2() throws RemoteException { clients = new HashMap(); stocks = new HashMap(); stocks.put("ORCL", new Float(12.55)); stocks.put("OATS", new Float(11.20)); stocks.put("FLEX", new Float(14.12)); stocks.put("MSFT", new Float(25.66)); stocks.put("AUO", new Float(17.23)); stocks.put("EBAY", new Float(99.55)); } public float getQuote(String ticker) throws RemoteException { if (stocks.containsKey(ticker)) { Float f = stocks.get(ticker); return f.floatValue(); } else { return -1.0F; } } public void setQuote(String ticker, float value) throws Exception { System.out.println("Setting " + ticker + " to " + value); stocks.put(ticker, new Float(value)); if (clients.containsKey(ticker)) { Set c = clients.get(ticker); Iterator it = c.iterator(); while (it.hasNext()) { StockListener n = it.next(); n.stockEvent(ticker, value); } } } public void registerForStockEvents(String ticker, StockListener n) { Set notifList = null; if (clients.containsKey(ticker)) { notifList = clients.get(ticker); notifList.add(n); } else { notifList = new HashSet(); notifList.add(n); clients.put(ticker,notifList); } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 515

Advanced Java Programming

Chapter 8 (cont'd) StockServer2.java (cont'd) public static void main(String[] args) { try { StockServer2 s = new StockServer2(); Context ctx = new InitialContext(); ctx.rebind("StockService", s); System.out.println("Stock bound."); for (int i = 0; i < 100; i++ ) { Thread.sleep(1000); s.setQuote("MSFT", s.getQuote("MSFT") * 1.03f); s.setQuote("OATS", s.getQuote("OATS") * 1.05f); s.setQuote("EBAY", s.getQuote("EBAY") * 1.08f); } ctx.unbind("StockService"); System.exit(0); } catch(Exception e) { System.err.println(e); } } }

StockClient2.java import import import import

java.rmi.RemoteException; javax.naming.Context; javax.naming.InitialContext; javax.rmi.PortableRemoteObject;

public class StockClient2 extends PortableRemoteObject implements StockListener { private String[] stocks = {"OATS", "MSFT", "AUO"}; public StockClient2() throws RemoteException { try { Context context = new InitialContext(); Object o = context.lookup("StockService"); Stock s = (Stock) PortableRemoteObject.narrow(o, Stock.class); for (int i = 0; i < stocks.length; i++) { s.registerForStockEvents(stocks[i], this); System.out.println(stocks[i] + "=" + s.getQuote(stocks[i])); Page 516

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

StockClient2.java (cont'd) } } catch(Exception e) { System.err.println(e); } } public void stockEvent(String ticker, float value) { System.out.println(); System.out.println(ticker + " has changed value to " + value); } public static void main(String[] args) throws Exception { new StockClient2(); } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 517

Advanced Java Programming

Chapter 9 Lab1.txt Your policy file should include: permission java.io.FilePermission "C:\\advj2se\\ch09\\*", "write"; Or something like it, depending upon your setup. Lab2.txt Command: appletviewer WriteFile.html Clicking the applet's Close button should throw an AccessControlException, because the applet lacks the java.lang.RuntimePermission for the target exitVM. The appletviewer checks for this permission when System.exit() is called. Lab3.txt Your .java.policy file should now contain the added permission: permission java.lang.RuntimePermission "exitVM"; Command: appletviewer WriteFile.html Clicking the applet's Close button should now exit the appletviewer without throwing an exception. Lab4.txt When you run ShowTimeClient, TimeServer has an exception: Exception in thread "RMI TCP Connection(2)-10.0.0.1" java.security.AccessControl Exception: access denied (java.net.SocketPermission 10.0.0.1:1121 accept,resolve ) The exception tells you TimeServer needs a SocketPermission with accept and resolve actions. After adding the accept permission, your .java.policy file should look something like this:

Page 518

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Lab4.txt (cont'd) grant codeBase "file:///C:/advj2se/ch09/-" { permission java.net.SocketPermission "*:*", "connect, resolve, accept"; permission java.io.FilePermission "C:\\advj2se\\ch09\\server\\-", "read"; permission java.io.FilePermission "C:\\advj2se\\ch09\\*", "write"; permission java.lang.RuntimePermission "exitVM"; }; Or something like it, depending upon your setup.

TimeServer1.java import import import import import import import

java.rmi.Naming; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject; java.net.MalformedURLException; java.text.DateFormat; java.util.Date; java.util.TimeZone;

public class TimeServer1 extends UnicastRemoteObject implements Time { public TimeServer1() throws RemoteException { } public String getSystemTime() { DateFormat df = DateFormat.getTimeInstance(); df.setTimeZone(TimeZone.getDefault()); return df.format(new Date()); } public static void main(String args[]) { System.setSecurityManager(new SecurityManager()); try { TimeServer1 ts = new TimeServer1(); Naming.rebind("///Time", ts); } catch (MalformedURLException e) { System.err.println(e); } catch (RemoteException e) { System.err.println(e); } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 519

Advanced Java Programming

Chapter 9 (cont'd) Lab5.txt Your rmiserver.policy file should look like this: grant codeBase "file:///C:/advj2se/ch09/server/*" { permission java.net.SocketPermission "*:*", "accept, connect, listen, resolve"; }; Your .java.policy file should look like this: grant codeBase "file:///C:/advj2se/ch09/-" { permission java.net.SocketPermission "*:*", "connect, resolve"; permission java.io.FilePermission "C:\\advj2se\\ch09\\server\\-", "read"; permission java.io.FilePermission "C:\\advj2se\\ch09\\*", "write"; permission java.lang.RuntimePermission "exitVM"; }; Run the TimeServer with the following command: java -Djava.rmi.server.codebase=file:///C:/advj2se/ch09/server/ -Djava.security.policy==rmiserver.policy TimeServer

Page 520

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 10 metacontents.txt Volume in drive C is ENTERPRISE Volume Serial Number is 3926-10F1 Directory of C:\advj\ch16\META-INF 08/06/2002 12:25p . 08/06/2002 12:25p .. 08/06/2002 12:25p 349 MANIFEST.MF 08/06/2002 12:25p 402 FIREFLY.SF 08/06/2002 12:25p 1,140 FIREFLY.DSA 3 File(s) 1,891 bytes 2 Dir(s) 755,441,664 bytes free keystore.txt Keystore type: jks Keystore provider: SUN Your keystore contains 2 entries ladybug, Aug 6, 2002, keyEntry, Certificate fingerprint (MD5): ED:3F:A1:AD:02:18:72:76:43:2E:0F:C0:A4:73:1D:96 firefly, Aug 6, 2002, keyEntry, Certificate fingerprint (MD5): 1C:39:84:E0:72:30:17:1E:85:55:C9:59:73:CF:68:69 metacontents2.txt Volume in drive C is ENTERPRISE Volume Serial Number is 3926-10F1 Directory of C:\advj\ch16\meta-inf 08/06/2002 12:25p . 08/06/2002 12:25p .. 08/06/2002 12:34p 349 MANIFEST.MF 08/06/2002 12:34p 402 FIREFLY.SF 08/06/2002 12:34p 1,140 FIREFLY.DSA 08/06/2002 12:34p 402 LADYBUG.SF 08/06/2002 12:34p 1,114 LADYBUG.DSA 5 File(s) 3,407 bytes 2 Dir(s) 755,380,224 bytes free © 2011 ITCourseware, LLC

Rev 5.1.4

Page 521

Advanced Java Programming

Chapter 10 (cont'd) ShowDates.java import import import import import import

java.io.*; java.security.Key; java.security.KeyStore; java.security.cert.Certificate; java.security.cert.X509Certificate; java.util.Enumeration;

public class ShowDates { public static void main(String[] args) { try { String keyStoreLocation = System.getProperty("user.home"); String keyStoreFile = ".keystore"; // String password = "Hello, I must be going"; String password = "password"; KeyStore keyStore = KeyStore.getInstance("jks"); FileInputStream fis = new FileInputStream( keyStoreLocation + File.separator + keyStoreFile); keyStore.load(fis, password.toCharArray()); Enumeration aliases = keyStore.aliases(); while (aliases.hasMoreElements()) { String a = aliases.nextElement().toString(); System.out.println(a); if (keyStore.isKeyEntry(a)) { System.out.println(a + " is a key."); Key key = keyStore.getKey(a, password.toCharArray()); System.out.println("Private Key:"); System.out.println(key); } else if (keyStore.isCertificateEntry(a)) { System.out.println(a + " is a certificate."); } Certificate cert = keyStore.getCertificate(a); if (cert instanceof X509Certificate) { X509Certificate x509cert = (X509Certificate) cert; System.out.println("Not valid before: " + x509cert.getNotBefore()); Page 522

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

ShowDates.java (cont'd) System.out.println("Not valid after: " + x509cert.getNotAfter()); } } } catch (Exception e) { e.printStackTrace(); } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 523

Advanced Java Programming

Chapter 11 EncryptText.java import import import import import

java.io.*; java.security.Key; javax.crypto.Cipher; javax.crypto.CipherOutputStream; javax.crypto.KeyGenerator;

public class EncryptText { public static void main(String args[]) { try { System.out.println("Enter data for encrypted file."); System.out.println("Type EOF on line to end."); BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); KeyGenerator keyGen = KeyGenerator.getInstance("DES"); Key theKey = keyGen.generateKey(); Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, theKey); // write encrypted input text to a file FileOutputStream fos = new FileOutputStream("EncFile.txt"); CipherOutputStream cos = new CipherOutputStream(fos,c); PrintWriter pw = new PrintWriter(cos); String s; while(!(s = br.readLine()).equalsIgnoreCase("EOF")) { pw.println(s); } br.close(); pw.close(); // Save key to a file ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream("Keyfile.dat")); oos.writeObject(theKey); oos.close(); } catch (Exception e) { System.err.println("Error : " + e.getMessage()); } } } Page 524

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

DecryptText.java import import import import

java.io.*; java.security.Key; javax.crypto.Cipher; javax.crypto.CipherInputStream;

public class DecryptText { public static void main(String args[]) { try { // read key from file ObjectInputStream ois = new ObjectInputStream( new FileInputStream("Keyfile.dat")); Key theKey = (Key) ois.readObject(); ois.close(); Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding"); c.init(Cipher.DECRYPT_MODE, theKey); // Read encrypted text from file FileInputStream fis = new FileInputStream("EncFile.txt"); CipherInputStream cis = new CipherInputStream(fis,c); BufferedReader br = new BufferedReader( new InputStreamReader(cis)); String s; while((s = br.readLine()) != null) { System.out.println(s); } br.close(); } catch (Exception e) { System.err.println("Error : " + e.getMessage()); } } }

PasswordDecrypt.java import import import import import import import

java.io.*; javax.crypto.Cipher; javax.crypto.CipherInputStream; javax.crypto.SecretKey; javax.crypto.SecretKeyFactory; javax.crypto.spec.PBEKeySpec; javax.crypto.spec.PBEParameterSpec;

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 525

Advanced Java Programming

Chapter 11 (cont'd) PasswordDecrypt.java (cont'd) public class PasswordDecrypt { public static void main(String args[]) { try { BufferedReader br = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Enter Password for Decryption: "); String password = br.readLine(); byte[] salt = {(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, (byte)0x32, (byte)0x9a, (byte)0xfa, (byte)0x71 }; PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 10); PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); SecretKey theKey = skf.generateSecret(keySpec); Cipher c = Cipher.getInstance("PBEWithMD5AndDES"); c.init(Cipher.DECRYPT_MODE, theKey, paramSpec); FileInputStream fis = new FileInputStream("EncFile.dat"); CipherInputStream cis = new CipherInputStream(fis, c); BufferedReader br2 = new BufferedReader( new InputStreamReader(cis)); String s; while((s = br2.readLine()) != null) System.out.println(s); } catch (Exception e) { System.err.println("Error : " + e.getMessage()); } } }

Page 526

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

PasswordList.java import import import import import import import import

java.security.Key; java.util.ArrayList; java.util.Iterator; javax.crypto.Cipher; javax.crypto.SealedObject; javax.crypto.SecretKeyFactory; javax.crypto.spec.PBEKeySpec; javax.crypto.spec.PBEParameterSpec;

class UsernamePassword implements Serializable { private String username; private String password; private String website; public UsernamePassword(String w, String u, String p) { username = u; password = p; website = w; } public String toString() { return "website: "+ website + " username: " + username + " password: " + password; } } public class PasswordList { private BufferedReader buf; private ArrayList passwords = null; PBEParameterSpec paramSpec = null; Cipher cipher = null; Key theKey = null; public PasswordList() { try { buf = new BufferedReader(new InputStreamReader(System.in)); String password = promptForPassword(); createCipher(password); passwords = getPasswordList(); int opt; while ((opt = displayMenu() ) != 3) { switch(opt) { case 1: addPassword(); break; case 2: showPasswords(); break; © 2011 ITCourseware, LLC

Rev 5.1.4

Page 527

Advanced Java Programming

Chapter 11 (cont'd) PasswordList.java (cont'd) default: System.out.println("Invalid Option"); } } savePasswords(); } catch (Exception e) { e.printStackTrace(); } } private String promptForPassword() throws IOException { System.out.print("Enter decrypt password: "); String password = buf.readLine(); return password; } private void createCipher(String password) throws Exception { byte[] salt = {(byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, (byte)0x32, (byte)0x9a, (byte)0xfa, (byte)0x71 }; paramSpec = new PBEParameterSpec(salt, 10); PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); theKey = skf.generateSecret(keySpec); cipher = Cipher.getInstance("PBEWithMD5AndDES"); cipher.init(Cipher.DECRYPT_MODE, theKey, paramSpec); } @SuppressWarnings("unchecked") // Not supported in 1.5.0 private ArrayList getPasswordList() { ArrayList pw = new ArrayList(); try { File file = new File ("passwords.dat"); if (file.exists()) { ObjectInputStream ois = new ObjectInputStream( new FileInputStream(file)); Page 528

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

PasswordList.java (cont'd) SealedObject so = (SealedObject) ois.readObject(); pw = (ArrayList) so.getObject(cipher); ois.close(); } } catch (Exception e) { System.err.println(e); } return pw; } private int displayMenu() { int choice = 0; String input; try { System.out.println("\n Menu"); System.out.println("1 - Add Password"); System.out.println("2 - Show Passwords"); System.out.println("3 - Quit"); System.out.print("\nEnter Option: "); input = buf.readLine(); choice = Integer.parseInt(input); } catch (IOException e) { System.err.println(e); } catch (NumberFormatException e) { System.err.println(e); } return choice; } private void addPassword() { try { UsernamePassword up; String ws,u,p; System.out.print("Website: "); ws = buf.readLine(); System.out.print("Username: "); u = buf.readLine(); System.out.print("Password: "); p = buf.readLine(); up = new UsernamePassword(ws, u, p); passwords.add(up); } catch (Exception e) { System.err.println(e.getMessage()); } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 529

Advanced Java Programming

Chapter 11 (cont'd) PasswordList.java (cont'd) } private void showPasswords() { Iterator iter = passwords.iterator(); while (iter.hasNext()) System.out.println(iter.next()); } private void savePasswords() throws Exception { ObjectOutputStream ois = new ObjectOutputStream( new FileOutputStream("passwords.dat")); cipher.init(Cipher.ENCRYPT_MODE, theKey, paramSpec); SealedObject so = new SealedObject(passwords, cipher); ois.writeObject(so); ois.close(); } public static void main(String[] args) { new PasswordList(); } }

Page 530

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 12 KSJAAS.java import import import import

java.security.Principal; java.util.Set; javax.security.auth.Subject; javax.security.auth.login.LoginContext;

public class KSJAAS { public static void main(String[] args) { LoginContext context = null; Subject subject = null; try { context = new LoginContext("KSJAAS", new LoginHandler()); context.login(); subject = context.getSubject(); Set principals = subject.getPrincipals(); for (Principal p : principals) { System.out.println("Principal type: " + p.getClass().getName() + " name: " + p.getName()); } } catch (Exception e) { e.printStackTrace(); } } }

KSJAAS.txt You need to change the login config file to specify com.sun.security.auth.module.KeyStoreLoginModule. You also need to create a policy file for the application. Because we're only looking at the Subject, and not calling doAs(), you don't need a separate policy entry specifying the principal. Because of that, the all.policy file in the chapter directory will do the job. Normally, that's all you would have to do. But since NTJAAS doesn't use a callback handler, you need to edit the source code to pass a LoginHandler to the LoginContext constructor.

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 531

Advanced Java Programming

Chapter 12 (cont'd) ksjaas.bat REM ksjaas.bat java -Djava.security.manager -Djava.security.policy=..\all.policy Djava.security.auth.login.config=kslogin.conf KSJAAS

kslogin.conf KSJAAS { com.sun.security.auth.module.KeyStoreLoginModule required; };

EgLoginHandler.java import import import import import import import import

java.io.BufferedReader; java.io.IOException; java.io.InputStreamReader; javax.security.auth.callback.Callback; javax.security.auth.callback.CallbackHandler; javax.security.auth.callback.NameCallback; javax.security.auth.callback.PasswordCallback; javax.security.auth.callback.UnsupportedCallbackException;

public class EgLoginHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback cb : callbacks) { if (cb instanceof NameCallback) { NameCallback ncb = (NameCallback) cb; System.out.print(ncb.getPrompt() + " "); BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String name = in.readLine(); ncb.setName(name); } else if (cb instanceof PasswordCallback) { PasswordCallback pcb = (PasswordCallback) cb; System.out.print(pcb.getPrompt() + " "); BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); Page 532

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

EgLoginHandler.java (cont'd) String password = in.readLine(); pcb.setPassword(password.toCharArray()); } else { throw new UnsupportedCallbackException(cb); } } } }

EgCallback.java import java.text.NumberFormat; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; public class EgCallback { public static void main(String[] args) { LoginContext lc = null; try { lc = new LoginContext("EgCallback", new EgLoginHandler()); lc.login(); Subject subject = lc.getSubject(); Object o = Subject.doAs(subject, new SalariesAction()); if (o instanceof Double) { double d = ((Double) o).doubleValue(); System.out.println("Total salary: " + NumberFormat.getCurrencyInstance().format(d)); } lc.logout(); } catch (Exception e) { e.printStackTrace(); } } }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 533

Advanced Java Programming

Chapter 12 (cont'd) eglogin.conf EgCallback { EgLoginModule required; };

egbuild.bat REM egbuild.bat javac Eg*.java jar cvfm egcallback.jar egcallback.mf Eg*.class

egcallback.mf Manifest-Version: 1.0 Main-Class: EgCallback Class-Path: sa.jar

egcallback.policy grant codeBase "file:///C:/advj2se/ch12/Solutions/egcallback.jar" { permission java.security.AllPermission; }; grant codeBase "file:///C:/advj2se/ch12/Solutions/sa.jar", principal EgPrincipal "Mary" { permission java.io.FilePermission "salaries.txt", "read"; };

egrun.bat REM egrun.bat java -Djava.security.manager -Djava.security.policy=egcallback.policy Djava.security.auth.login.config=eglogin.conf -jar egcallback.jar

Page 534

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 13 GetRates.java import import import import import

javax.naming.Context; javax.naming.InitialContext; javax.naming.NamingException; java.rmi.RemoteException; java.util.Hashtable;

public class GetRates { public static void main(String[] args) { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); env.put(Context.PROVIDER_URL, "rmi:///"); try { InitialContext ctx = new InitialContext(env); RateInfo rates = (RateInfo) ctx.lookup("RateInfo"); System.out.println(rates.getInfo()); } catch (RemoteException re) { System.err.println(re); } catch (NamingException ne) { System.err.println(ne); } } }

ServerStatusLister.java import import import import import import import

javax.naming.InitialContext; javax.naming.Context; javax.naming.NamingEnumeration; javax.naming.NameClassPair; javax.naming.NamingException; java.rmi.RemoteException; java.util.Hashtable;

public class ServerStatusLister { public static void main(String args[]) { Hashtable env = new Hashtable();

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 535

Advanced Java Programming

Chapter 13 (cont'd) ServerStatusLister.java (cont'd) env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); env.put(Context.PROVIDER_URL, "rmi:///"); try { InitialContext ctx = new InitialContext(env); NamingEnumeration list = ctx.list(""); while (list.hasMore()) { NameClassPair ncp = list.next(); String name = ncp.getName(); if (name.startsWith("ServerStatus.")) { try { ServerStatus stat = (ServerStatus)ctx.lookup(name); System.out.println(stat.getStatus()); } catch (RemoteException re) { System.err.println("Remote method failed for " + name + ": " + re); } catch (NamingException ne) { System.err.println("Failed looking up " + name + ": " + ne); } } } } catch (NamingException ne) { System.err.println(ne); } } }

NSLookup1.java import import import import import import import Page 536

java.util.Hashtable; javax.naming.Context; javax.naming.NamingEnumeration; javax.naming.NamingException; javax.naming.directory.Attribute; javax.naming.directory.Attributes; javax.naming.directory.DirContext; Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

NSLookup1.java (cont'd) import javax.naming.directory.InitialDirContext; public class NSLookup1 { public static void main(String[] arg) { String host = ""; String[] rrtypes = new String[] {"A"}; if (arg.length > 0) { host = arg[0]; } else { System.out.println("Usage: java NSLookup1 hostname"); System.exit(1); } Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); env.put(Context.PROVIDER_URL, "dns://ns1.granitecanyon.com/"); try { DirContext ctxt = new InitialDirContext(env); Attributes att = ctxt.getAttributes(host, rrtypes); NamingEnumeration attlist = att.getAll(); while (attlist.hasMore()) { Attribute a = (Attribute) attlist.next(); // Normally we would iterate through attribure values. // Attribute.toString() gives nice enough output. System.out.println(a); } } catch (NamingException ne) { System.out.println(ne); } } }

NSLookup2.java import import import import import import

java.util.Hashtable; javax.naming.Context; javax.naming.NamingEnumeration; javax.naming.NamingException; javax.naming.directory.Attribute; javax.naming.directory.Attributes;

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 537

Advanced Java Programming

Chapter 13 (cont'd) import javax.naming.directory.DirContext;

NSLookup2.java (cont'd) import javax.naming.directory.InitialDirContext; public class NSLookup2 { public static void main(String[] arg) { String host = ""; String[] rrtypes = new String[] {"A"}; if (arg.length > 0) { host = arg[0]; if (arg.length > 1) { rrtypes = new String[arg.length - 1]; for (int i = 1; i < arg.length; i++) { rrtypes[i - 1] = arg[i]; } } } else { System.out.println("Usage: java NSLookup2 hostname RRtype(s)"); System.exit(1); } Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); env.put(Context.PROVIDER_URL, "dns://ns1.granitecanyon.com/"); try { DirContext ctxt = new InitialDirContext(env); Attributes att = ctxt.getAttributes(host, rrtypes); NamingEnumeration attlist = att.getAll(); while (attlist.hasMore()) { Attribute a = (Attribute)attlist.next(); // Normally we would iterate through attribure values. // Attribute.toString() gives nice enough output. System.out.println(a); } } catch (NamingException ne) { System.out.println(ne); } } } Page 538

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 14 MileageCounter.java import import import import import import

java.io.File; javax.xml.parsers.SAXParser; javax.xml.parsers.SAXParserFactory; org.xml.sax.Attributes; org.xml.sax.SAXException; org.xml.sax.helpers.DefaultHandler;

public class MileageCounter { public static void main(String args[]) { if (args.length != 1) { System.out.println("Usage: java MileageCounter garage.xml"); System.exit(1); } SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); MileageHandler handler = new MileageHandler(); parser.parse(new File(args[0]), handler); System.out.println("The number of cars with less than 20,000 " + "miles is " + handler.getCount()); } catch (Exception e) { System.err.println ("ERROR " + e); } } } class MileageHandler extends DefaultHandler { private int counter = 0; public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (qName.equals("car") || qName.equals("van")) { String miles = atts.getValue("miles"); if ( Integer.parseInt(miles) < 20000) { counter ++; } } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 539

Advanced Java Programming

Chapter 14 (cont'd) MileageCounter.java (cont'd) public int getCount() { return counter; } }

AddNewCar.java import import import import import import

java.io.File; javax.xml.parsers.DocumentBuilder; javax.xml.parsers.DocumentBuilderFactory; org.w3c.dom.Document; org.w3c.dom.Element; org.w3c.dom.Text;

public class AddNewCar { public static void main (String args[]) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new File("garage.xml") ); addCar(document,"Saturn", "SL2", "2002"); } catch (Exception e) { System.err.println(e); } } public static void addCar(Document d, String carMake, String carModel, String carYear) { Element car = d.createElement("car"); Element make = d.createElement("make"); Text text = d.createTextNode(carMake); make.appendChild(text); Element model = d.createElement("model"); text = d.createTextNode(carModel); model.appendChild(text); Page 540

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

AddNewCar.java (cont'd) Element year = d.createElement("year"); text = d.createTextNode(carYear); year.appendChild(text); car.appendChild(make); car.appendChild(model); car.appendChild(year); car.setAttribute("miles", carYear); Element garage = d.getDocumentElement(); garage.appendChild(car); } }

AddNewCar2.java import import import import import import import import import import import import import

java.io.File; javax.xml.parsers.DocumentBuilder; javax.xml.parsers.DocumentBuilderFactory; javax.xml.transform.Result; javax.xml.transform.Source; javax.xml.transform.Transformer; javax.xml.transform.TransformerFactory; javax.xml.transform.dom.DOMSource; javax.xml.transform.stream.StreamResult; javax.xml.transform.stream.StreamSource; org.w3c.dom.Document; org.w3c.dom.Element; org.w3c.dom.Text;

public class AddNewCar2 { public static void main (String args[]) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new File("garage.xml") ); addCar(document,"Saturn","SL2","2002"); Source xslSource = new StreamSource("../garage.xslt"); DOMSource domSource = new DOMSource(document); Result result = new StreamResult("garage.html"); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 541

Advanced Java Programming

Chapter 14 (cont'd) AddNewCar2.java (cont'd) TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(xslSource); transformer.transform(domSource, result); } catch (Exception e) { System.err.println(e); } } public static void addCar(Document d, String carMake, String carModel, String carYear) { Element car = d.createElement("car"); Element make = d.createElement("make"); Text text = d.createTextNode(carMake); make.appendChild(text); Element model = d.createElement("model"); text = d.createTextNode(carModel); model.appendChild(text); Element year = d.createElement("year"); text = d.createTextNode(carYear); year.appendChild(text); car.appendChild(make); car.appendChild(model); car.appendChild(year); car.setAttribute("miles", carYear); Element garage = d.getDocumentElement(); garage.appendChild(car); } }

Page 542

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 15 Pager.java public class Pager { public native void page(String message, String id); static { System.loadLibrary("Pager"); } }

PagerTest.java public class PagerTest { public static void main(String args[]) { String message = "Houston, we have a problem..."; String id = "SysDBA"; Pager p = new Pager(); p.page(message, id); } }

Pager.c #include #include "Pager.h" #include "LegacyPager.h" JNIEXPORT void JNICALL Java_Pager_page (JNIEnv *env, jobject obj, jstring message, jstring id) { const char *localMessage = (*env)->GetStringUTFChars(env, message, NULL); const char *localId = (*env)->GetStringUTFChars(env, id, NULL); pageThem(localMessage, localId); (*env)->ReleaseStringUTFChars(env, message, localMessage); (*env)->ReleaseStringUTFChars(env, id, localId); }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 543

Advanced Java Programming

Chapter 15 (cont'd) Pager2.java public class Pager2 { public native void page(String message, String id); public native String who(String id); static { System.loadLibrary("Pager2"); } }

PagerTest2.java public class PagerTest2 { public static void main(String args[]) { String message = "Houston, we have a problem..."; String id = "SysDBA"; Pager2 p = new Pager2(); p.page(message, id); String person = p.who(id); System.out.println("id belongs to " + person); } }

Pager2.c #include #include "Pager2.h" #include "LegacyPager.h" JNIEXPORT void JNICALL Java_Pager2_page (JNIEnv *env, jobject obj, jstring message, jstring id) { const char *localMessage = (*env)->GetStringUTFChars(env, message, NULL); const char *localId = (*env)->GetStringUTFChars(env, id, NULL); pageThem(localMessage, localId); (*env)->ReleaseStringUTFChars(env, message, localMessage); (*env)->ReleaseStringUTFChars(env, id, localId); } Page 544

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Pager2.c (cont'd) JNIEXPORT jstring JNICALL Java_Pager2_who (JNIEnv *env, jobject obj, jstring id) { const char *localMessage = {"Isaac Newton"}; return (*env)->NewStringUTF(env, localMessage); }

© 2011 ITCourseware, LLC

Rev 5.1.4

Page 545

Advanced Java Programming

Chapter 16 IdGenerator2.java public class IdGenerator2 { private int counter; private static IdGenerator2 theInstance; private IdGenerator2() { counter = 0; } public static synchronized IdGenerator2 getInstance() { if (theInstance == null) { theInstance = new IdGenerator2(); } return theInstance; } public synchronized int getNextId() { return counter++; } /* * This method is not strictly necessary in this example, but if * your Singleton class were to extend a class that implemented * clone(), without this method it would be possible to create more * than one instance via cloning. */ public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }

HumanResourcesApp2.java public class HumanResourcesApp2 { public static void main(String[] args) { NewHireHelper2 h1 = new NewHireHelper2(); NewHireHelper2 h2 = new NewHireHelper2(); h1.start(); h2.start(); } } class NewHireHelper2 extends Thread { public void createNewEmployee() { IdGenerator2 gen = IdGenerator2.getInstance(); Page 546

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

HumanResourcesApp2.java (cont'd) int id = gen.getNextId(); Employee e = new Employee(id); // add new employee to database } public void run() { createNewEmployee(); } }

IdGeneratorFactory.java public class IdGeneratorFactory { //Factory Method public IdGenerator3 getIdGenerator() { if (Configuration.isConfigValid()) { return FileIdGenerator.getInstance(); } else { return SimpleIdGenerator.getInstance(); } } }

SimpleIdGenerator.java public class SimpleIdGenerator implements IdGenerator3 { private int counter; private static SimpleIdGenerator theInstance; public static synchronized SimpleIdGenerator getInstance() { if (theInstance == null) { theInstance = new SimpleIdGenerator(); } return theInstance; } private SimpleIdGenerator() { counter = 0; } public synchronized int getNextId() { return counter++; } /* * This method is not strictly necessary in this example, but if © 2011 ITCourseware, LLC

Rev 5.1.4

Page 547

Advanced Java Programming

Chapter 16 (cont'd) SimpleIdGenerator.java (cont'd) * your Singleton class were to extend a class that implemented * clone(), without this method it would be possible to create more * than one instance via cloning. */ public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }

Configuration.java import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; public class Configuration { private static boolean valid; private static int next; static { Properties p = new Properties(); try { FileInputStream inputStream = new FileInputStream("hrapp.properties"); if (inputStream != null) { p.load(inputStream); String value = p.getProperty("next"); Integer i = new Integer(value); valid = true; next = i.intValue(); } } catch (NumberFormatException nfe) { valid = false; } catch (IOException e) { valid = false; } } public static boolean isConfigValid() { Page 548

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Configuration.java (cont'd) return valid; } public static int getNext() { return next; } }

FileIdGenerator.java public class FileIdGenerator implements IdGenerator3 { private int counter; private static FileIdGenerator theInstance; private FileIdGenerator() { counter = Configuration.getNext(); } public static synchronized FileIdGenerator getInstance() { if (theInstance == null) { theInstance = new FileIdGenerator(); } return theInstance; } public synchronized int getNextId() { return counter++; } /* * This method is not strictly necessary in this example, but if * your Singleton class were to extend a class that implemented * clone(), without this method it would be possible to create more * than one instance via cloning. */ public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } }

HumanResourcesApp3.java public class HumanResourcesApp3 { public static void main(String[] args) { NewHireHelper3 h1 = new NewHireHelper3(); NewHireHelper3 h2 = new NewHireHelper3(); h1.start(); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 549

Advanced Java Programming

Chapter 16 (cont'd) HumanResourcesApp3.java (cont'd) h2.start(); } } class NewHireHelper3 extends Thread { public void createNewEmployee() { IdGeneratorFactory factory = new IdGeneratorFactory(); IdGenerator3 gen = factory.getIdGenerator(); int id = gen.getNextId(); Employee e = new Employee(id); // add new employee to database } public void run() { createNewEmployee(); } }

IdGenerator3.java public interface IdGenerator3 { public int getNextId(); }

hrapp.properties next=22

BuilderClient.java public class BuilderClient { public static void main(String[] args) { Director d = new Director(); Builder b = Builder.getInstance("FlatFile"); d.setBuilder(b); OutputFile flat = d.construct(); flat.write("manager.txt"); b = Builder.getInstance("PropertyFile"); d.setBuilder(b); OutputFile prop = d.construct(); Page 550

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

BuilderClient.java (cont'd) prop.write("manager.properties"); System.out.println("output files created"); } }

Director.java public class Director { private Builder builder; private Manager manager; public Director() { manager = new Manager(42); manager.setFaxNumber("303 867-5309"); manager.setLocation("Gunnison"); } public void setBuilder(Builder builder) { this.builder = builder; } public OutputFile construct() { builder.buildId(manager.getId()); builder.buildFaxNumber(manager.getFaxNumber()); builder.buildLocation(manager.getLocation()); return builder.getFile(); } }

Builder.java public abstract class Builder { public static Builder getInstance(String source) { if (source.equals("PropertyFile")) { return new PropertyBuilder(); } return new FlatFileBuilder(); } public public public public

abstract abstract abstract abstract

void buildId(int id); void buildFaxNumber(String fax); void buildLocation(String loc); OutputFile getFile();

} © 2011 ITCourseware, LLC

Rev 5.1.4

Page 551

Advanced Java Programming

Chapter 16 (cont'd) PropertyBuilder.java public class PropertyBuilder extends Builder { private PropertyFile file; public PropertyBuilder() { file = new PropertyFile(); } public void buildId(int id) { file.append("id=" + id); } public void buildFaxNumber(String fax) { file.append("faxNumber=" + fax); } public void buildLocation(String location) { file.append("location=" + location); } public OutputFile getFile() { return file; } }

FlatFileBuilder.java public class FlatFileBuilder extends Builder { private static String EOL = System.getProperty("line.separator"); FlatFile file = new FlatFile(); public void buildId(int id) { file.append("" + id + EOL); } public void buildFaxNumber(String fax) { file.append(fax + EOL); } public void buildLocation(String location) { file.append(location + EOL); } public OutputFile getFile() { return file; } }

Page 552

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

OutputFile.java public interface OutputFile { public void write(String filename); }

PropertyFile.java import import import import import

java.io.FileNotFoundException; java.io.FileOutputStream; java.io.IOException; java.util.Properties; java.util.regex.Pattern;

public class PropertyFile implements OutputFile { private Properties props = new Properties(); private Pattern pattern = Pattern.compile("="); public void append(String s) { String[] tokens = pattern.split(s); props.setProperty(tokens[0], tokens[1]); } public void write(String file) { try { FileOutputStream fos = new FileOutputStream(file); props.store(fos, null); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } }

FlatFile.java import import import import import

java.io.BufferedWriter; java.io.FileNotFoundException; java.io.FileOutputStream; java.io.IOException; java.io.OutputStreamWriter;

public class FlatFile implements OutputFile { private StringBuffer content = new StringBuffer(); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 553

Advanced Java Programming

Chapter 16 (cont'd) FlatFile.java (cont'd) public void append(String s) { content.append(s); } public void write(String file) { try { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file)); BufferedWriter bw = new BufferedWriter(osw); bw.write(content.toString()); bw.close(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } }

Page 554

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Chapter 17 IOFacade2.java import java.io.*; public class IOFacade2 { private static IOFacade2 theInstance = null; private IOFacade2() { } public static IOFacade2 getInstance() { if (theInstance == null) { theInstance = new IOFacade2(); } return theInstance; } public void writeToSerializedObjectFile(String filename, Object obj) throws IOException { ObjectOutputStream out = null; boolean append = true; try { File file = new File(filename); out = new ObjectOutputStream( new FileOutputStream(file, append)); out.writeObject(obj); } catch (IOException e) { log(e); throw e; } finally { out.close(); } } public void writeToTextFile(String filename, String text) throws IOException { PrintWriter out = null; boolean append = true; try { File file = new File(filename); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 555

Advanced Java Programming

Chapter 17 (cont'd) IOFacade2.java (cont'd) out = new PrintWriter(new BufferedWriter( new FileWriter(file, append))); out.println(text); } catch (IOException e) { log(e); throw e; } finally { out.close(); } } public void writeToBinaryFile(String filename, byte[] bytes) throws IOException { BufferedOutputStream out = null; boolean append = true; try { File file = new File(filename); out = new BufferedOutputStream( new FileOutputStream(file, append)); out.write(bytes); } catch (IOException e) { log(e); throw e; } finally { try { out.close(); } catch (IOException ioe) { log(ioe); throw ioe; } } } private void log(Exception e) { try { writeToTextFile("log.txt", e.toString()); } Page 556

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

IOFacade2.java (cont'd) catch (IOException ioe) { System.err.println(ioe); } } }

FacadeClient2.java public class FacadeClient2 { public static void main(String[] args) { IOFacade2 facade = IOFacade2.getInstance(); String text = "To be, or not to be: that is the question"; byte[] bytes = {70, 65, 67, 65, 68, 69, 1, 1, 1}; try { facade.writeToSerializedObjectFile("string.ser", text); facade.writeToTextFile("string.txt", text); facade.writeToBinaryFile("bytes.bin", bytes); } catch (Exception e) { System.err.println(e); } } }

GenericArrayAdapter2.java import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; public class GenericArrayAdapter2 implements Collection { private GenericArray adaptee; public GenericArrayAdapter2() { adaptee = new GenericArray(); } public GenericArrayAdapter2(int initialSize) { adaptee = new GenericArray(initialSize); } public boolean add(E o) { adaptee.addElement(o); return true; } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 557

Advanced Java Programming

Chapter 17 (cont'd) GenericArrayAdapter2.java (cont'd) public boolean addAll(Collection c) { Iterator it = c.iterator(); while (it.hasNext()) { if (!contains(it.next())) { return false; } } return true; } public boolean isEmpty() { if (adaptee.getSize() == 0) return true; else return false; } public Iterator iterator() { return new Iterator() { int current = 0; public boolean hasNext() { return current != adaptee.getSize(); } public E next() { try { E nextElem = (E)adaptee.getElement(current++); return nextElem; Page 558

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

GenericArrayAdapter2.java (cont'd) } catch(IndexOutOfBoundsException e) { throw new NoSuchElementException(); } } public void remove() { throw new UnsupportedOperationException(); } }; } public boolean remove(Object obj) { int index = adaptee.indexOfObject(obj); if (index != -1) { adaptee.removeElement(index); return true; } return false; } public boolean removeAll(Collection c) { boolean flag = false; Iterator it = c.iterator(); while (it.hasNext()) { if (remove(it.next())) { if (flag == false) { flag = true; } } } return flag; } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } public int size() { return adaptee.getSize(); } public Object[] toArray() { return adaptee.getArray(); } @SuppressWarnings("unchecked") // Not supported in 1.5.0 public T[] toArray(T[] array){ // make sure array is big enough int size = adaptee.getSize(); © 2011 ITCourseware, LLC

Rev 5.1.4

Page 559

Advanced Java Programming

Chapter 17 (cont'd) GenericArrayAdapter2.java (cont'd) if (array.length < size) { array = (T[])java.lang.reflect.Array.newInstance( array.getClass().getComponentType(), size); } // add elements to array Iterator it = this.iterator(); Object[] temp = array; for (int i = 0; i < size; i++) { temp[i] = it.next(); } // add null terminator if (array.length > size) { array[size] = null; } return array; } public boolean equals(Object o) { return adaptee.equals(o); } public int hashCode() { return adaptee.hashCode(); } }

AdapterClient2.java import java.util.*; public class AdapterClient2 { public static void main(String[] args) { Collection c = new GenericArrayAdapter2(); populateCollection(c); System.out.println("Original Collection: " ); printCollection(c); removeItemFromCollection(c); System.out.println("Collection After Remove: " ); printCollection(c); removeItemsFromCollection(c); System.out.println("Collection After Remove All: " ); printCollection(c); } private static void populateCollection(Collection c) { Page 560

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

AdapterClient2.java (cont'd) for (int i = 0; i < 10; i++) { c.add("Element: " + i); } } private static void removeItemFromCollection(Collection c) { c.remove("Element: 8"); } private static void removeItemsFromCollection(Collection c){ ArrayList list = new ArrayList(); for (int i = 0; i < 5; i++) { list.add("Element: " + i); } c.removeAll(list); } private static void printCollection(Collection c) { Iterator it = c.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }

ArithmeticComponent2.java public abstract class ArithmeticComponent2 { public void add(ArithmeticComponent2 component) { throw new UnsupportedOperationException(); } public void remove(ArithmeticComponent2 component) { throw new UnsupportedOperationException(); } public ArithmeticComponent2 getChild(int i) { throw new UnsupportedOperationException(); } public int evaluate() { throw new UnsupportedOperationException(); } public void print() { throw new UnsupportedOperationException(); } }

Operator2.java import java.util.ArrayList; import java.util.Iterator; © 2011 ITCourseware, LLC

Rev 5.1.4

Page 561

Advanced Java Programming

Chapter 17 (cont'd) Operator2.java (cont'd) public class Operator2 extends ArithmeticComponent2 { private ArrayList children; private String operator; public Operator2(String operator) { this.operator = operator; children = new ArrayList(); } public void add(ArithmeticComponent2 component) { children.add(component); } public void remove(ArithmeticComponent2 component) { children.remove(component); } public ArithmeticComponent2 getChild(int i) { return children.get(i); } public int evaluate() { int result = 0; boolean firstChild = true; Iterator it = children.iterator(); while (it.hasNext()) { ArithmeticComponent2 comp = it.next(); if (firstChild == true) { result = comp.evaluate(); firstChild = false; continue; } if (operator.equals("+")) result += comp.evaluate(); else if (operator.equals("-")) result -= comp.evaluate(); else if (operator.equals("*")) result *= comp.evaluate(); else if (operator.equals("/")) result /= comp.evaluate(); } return result; } public void print() { Iterator it = children.iterator(); Page 562

Rev 5.1.4

© 2011 ITCourseware, LLC

Solutions

Operator2.java (cont'd) while (it.hasNext()) { ArithmeticComponent2 comp = it.next(); comp.print(); if (it.hasNext()) System.out.print(" " + operator + " "); } } }

Operand2.java public class Operand2 extends ArithmeticComponent2 { private int op; public Operand2(int op) { this.op = op; } public void print() { System.out.print(op); } public int evaluate() { return op; } }

CompositeClient2.java public class CompositeClient2 { public static void main(String[] args) { // 5 * 12 + 3 * 9 ArithmeticComponent2 expression = new Operator2("+"); ArithmeticComponent2 subExpression1 = new Operator2("*"); ArithmeticComponent2 subExpression2 = new Operator2("*"); expression.add(subExpression1); subExpression1.add(new Operand2(5)); subExpression1.add(new Operand2(12)); expression.add(subExpression2); subExpression2.add(new Operand2(3)); subExpression2.add(new Operand2(9)); expression.print(); System.out.println("= " + expression.evaluate()); } } © 2011 ITCourseware, LLC

Rev 5.1.4

Page 563

Advanced Java Programming

Chapter 18 Query.java import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.Statement; public class Query extends DatabaseAccessTemplate { private ResultSet rs; protected void runStatement(Statement stmt, String sql) throws Exception { rs = stmt.executeQuery(sql); } protected void processResults() throws Exception { ResultSetMetaData rsmd = rs.getMetaData(); int numColumns = rsmd.getColumnCount(); for (int i = 1; i