text:
This chapter provides a more detailed view of the Message Queue broker, which was introduced in The Message Queue Service. The chapter examines the services provided by the broker, the tools you use to configure these services, and the administrative tasks required to support these services.
The chapter includes the following sections:
Figure 1–6 shows the different elements of the Message Queue service. Chapter 2, Client Programming Model described the programming model and how clients use the Java and C APIs to interact with the Message Queue client runtime, the part of the message service that is directly accessed by client applications. This chapter focuses on the broker services, the part of the message service that is accessed through administration tools.
The broker is the centerpiece of the Message Queue service shown in Figure 1–6. The broker provides the set of services that enable secure, reliable messaging:
Connection services that manage the physical connections between a broker and its clients that provide transport for incoming and outgoing messages. See Connection Services.
Message delivery services that route and deliver JMS messages as well as control messages used by the message service to support reliable delivery. See Message Delivery Services.
Persistence services that manage the writing of data to persistent storage and its retrieval from persistent storage. See Persistence Services.
Security services that authenticate users connecting to the broker and authorize their actions. See Security Services
Clustering services that support the grouping of brokers into a cluster to achieve scalability and availability. See Chapter 4, Broker Clusters.
Monitoring services that generate metrics and diagnostic information and write this information to a specified output channel. See Monitoring Services.
The sections that follow describe each of the broker services. These services are configured by setting broker configuration properties. Broker properties are specified in different configuration files and can also be set using options of the broker startup command. Chapter 4, Configuring a Broker, in Oracle GlassFish Message Queue 4.4.2 Administration Guide describes the broker configuration files and explains the order of precedence by which property values in one configuration file can be used to override values set in a different file. Properties set with the startup command override all other settings.
You use connection-related properties to configure and manage the physical connections between a broker and its clients. As shown in Figure 1–6 both application clients and administration clients can connect to the broker. The JMS specification does not dictate that providers implement any specific wire protocols. Message Queue connection services, used by application clients and administration clients to connect to the broker, are currently layered on top of TCP, TLS, HTTP, or HTTPS protocols. TLS (Transport Layer Security) is a successor to and compatible with SSL (Secure Socket Layer).
There are two general types of connection services:
NORMAL: Services that provide JMS support and allow clients to connect to the broker (jms, ssljms, http, or https) and are layered on top of TCP, TLS, HTTP, or HTTPS protocols, respectively. (Services layered on top of HTTP allow messages to pass through firewalls.)
ADMIN: Services that allow administrators to connect to the broker ( admin, ssladmin) and are layered on top of TCP or TLS protocols.
Connection services are available through dedicated ports that can be dynamically assigned by the broker's Port Mapper (see Port Mapper Service) or statically assigned by the administrator. By default, when you start the broker, the jms and admin services are up and running. Additionally, you can configure a broker to run any or all of the connection services.
Each connection service is multi-threaded, supporting multiple connections, and each service supports specific authentication and authorization (access control) features. See Security Services for more information.
Should a connection fail, the Message Queue service can automatically retry connecting the client to the same broker or to a different broker if this feature is enabled. For more information, see the description of the automatic reconnect feature in Appendix B, Message Queue Features
The connections provided by Message Queue connection services can be configured to specify which brokers to connect to, how to handle reconnection, message flow control, and so on. For additional information about how connections can be configured, see Connection Factories and Connections.
Connection configuration can be performed by both administrators and in client application code:
An administrator creates connection factory administered objects that encapsulate connection behaviors. In addition, an administrator can use broker properties to activate non-default connection services, to assign static ports if required, to configure threading, and to specify a host to connect to if multiple network interfaces are used. An administrator can also specify a ping interval to test whether the client is accessible; this is useful in managing resources.
Client code can instantiate configuration factory objects and set their attributes to achieve desired connection behaviors. These attributes specify non-default connection services, hosts, ports, a list of brokers to connect to in case reconnection is required, and reconnection behavior. The client can also specify a ping interval to test for failed connections.
A client can connect to the Message Queue service through a firewall. This can be done either by having the firewall administrator open a specific port and then connecting to that (static) port or by using the HTTP or HTTPS service as summarized in Appendix B, Message Queue Features.
Connection services are dynamically assigned a port by a common Port Mapper service that resides at a the broker's main port, 7676. When the Message Queue client runtime sets up a connection with the broker, it first contacts the Port Mapper, requesting a port number for the connection service it has chosen.
You can override the Port Mapper by assigning a static port number for the jms, ssljms, admin and ssladmin connection services when configuring these services. However, static ports are generally used only in special situations, such as in making connections through a firewall, and are not generally recommended.
Each connection service is multithreaded, supporting multiple connections. The threads needed for these connections are maintained by the broker in a pool. How they are allocated depends on the values you specify for the minimum and maximum thread values, and on the threading model you choose.
You can set broker properties to specify a minimum number and maximum number of threads. As threads are needed by connections, they are added to the thread pool for the service supporting that connection. The minimum specifies the number of threads available to be allocated. When the available threads exceeds this minimum threshold, the system will shut down threads as they become free until the minimum is reached again, thereby saving on memory resources. Under heavy loads, the number of threads might increase until the pool's maximum number is reached; at this point, new connections are rejected until a thread becomes available.
The threading model you choose specifies whether threads are dedicated to a single connection or shared by multiple connections:
In the dedicated model, each connection to the broker requires two threads: one for incoming messages and one for outgoing messages. This limits the number of possible connections but provides high performance.
In the shared model, connections are processed by a shared thread when sending or receiving messages. Because each connection does not require dedicated threads, this model increases the number of possible connections, but adds some overhead for thread management and thereby impacts performance.
Once clients are connected to the broker, the routing and delivery of messages can proceed. In this phase, the broker is responsible for creating and managing different types of physical destinations, for ensuring a smooth flow of messages, and for using resources efficiently. The broker properties related to routing and delivery are used by the broker to manage these tasks in a way that suits your application's needs.
A physical destination on the broker is a memory location where messages are stored before being delivered to a message consumer. There are four kinds of physical destinations:
Admin-created destinations are created by an administrator using Message Queue administration tools. Admin-created destinations correspond to destination administered objects created by an administrator and accessed by client applications by using a JNDI lookup. Admin-created destinations can also correspond to destination objects created programmatically by a client application. You use Message Queue administration tools to set or update properties for each admin-created destination.
Auto-created destinations are automatically created by the broker whenever a message consumer or producer attempts to access a nonexistent destination. These are typically used during development. You can set a broker property to disallow the creation of such destinations. You set broker properties to configure all auto-create destinations on a particular broker.
An auto-created destination is automatically destroyed by the broker when it is no longer being used: that is, when it has no consumer clients and no longer contains any messages. If a broker restarts, it only recreates this kind of destination if it contains persistent messages.
Temporary destinations are explicitly created and destroyed programmatically by client applications that need a destination at which to receive replies to messages. As their name implies, these destinations are temporary. They are maintained by the broker only for the duration of the connection in which they are created.
Temporary destinations are only stored persistently only if the consumer of the destination is set to automatically reconnect in the event of failure. Otherwise, they are not recreated when a broker is restarted. Nevertheless, temporary destinations are visible to administration tools.
The dead message queue is a specialized destination, created automatically at broker startup and used to store dead messages for diagnostic purposes. You can set properties for the dead message queue using the imqcmd utility.
Managing a destination involves one or more of the following tasks:
Creating, pausing, resuming, or destroying a destination
Listing all destinations on a broker
Displaying information about the state and properties of a destination
Displaying metrics information for a destination
Compacting disk space used to persist messages for a destination
Updating a physical destination's properties
Management tasks vary with the kind of destination being managed: admin-created, auto-created, temporary, or dead message queue. For example, temporary destinations do not need to be explicitly destroyed; auto created properties are configured using broker configuration properties which apply to all auto-created destinations on that broker.
For optimal performance, you can set properties when creating or updating physical destinations. Properties that can be set include the following:
The type and name of the destination.
Individual and aggregate limits for destinations (the maximum number of messages, the maximum number of total bytes, the maximum number of bytes per message, the maximum number of producers).
What the broker should do when individual or aggregate limits are exceeded.
The maximum number of messages to be delivered in a single batch.
Whether deleted messages for a destination should be sent to the dead message queue.
In the case of a broker cluster, whether a destination should be propagated to other brokers in the cluster.
For a queue destination you can also configure the maximum number of active and back up consumers and you can specify (for broker clusters) whether delivery to a local queue is preferred.
You can also configure the limits and behavior of the dead message queue. Note, however, that default properties for this queue differ from those of a standard queue.
Destinations can consume significant resources, depending on the number and size of messages they handle and on the number and durability of the consumers that register; therefore, they need to be managed closely to guarantee good messaging service performance and reliability.
You can set properties to prevent a broker from being overwhelmed by incoming messages and to prevent the broker from running out of memory. The broker uses three levels of memory protection to keep the message service operating as resources become scarce: destination limits, system-wide limits, and system memory thresholds. Ideally, if destination limits and system-wide limits are set appropriately, critical system-memory thresholds should never be breached.
You can set destination properties to manage memory and message flow for each destination. For example, you can specify the maximum number of producers allowed for a destination, the maximum number (or size) of messages allowed in a destination, and the maximum size of any single message.
You can also specify how the broker should respond when any such limits are reached: to slow producers, to throw out the oldest messages, to throw out the lowest-priority messages, or to reject the newest messages.
You can also use properties to set limits that apply to all destinations on a broker: you can specify the total number of messages and the memory consumed by all messages. If any of the system-wide message limits are reached, the broker rejects new messages.
Finally, you can use properties to set thresholds at which the broker takes increasingly serious action to prevent memory overload. The action taken depends on the state of memory resources: green (plenty of memory is available), yellow (broker memory is running low), orange (broker is low on memory), red (broker is out of memory). As the broker's memory state progresses from green to red, the broker takes increasingly serious actions:
It throws out in-memory copies of persistent messages in the data store.
It throttles back producers of non-persistent messages, eventually stopping the flow of messages into the broker. Persistent message flow is automatically limited by the requirement that each message be acknowledged by the broker.
For a broker to recover in case of failure, it needs to recreate the state of its message delivery operations. To be able to do this, it must save state information to a data store. When the broker restarts, it uses the saved data to recreate destinations and durable subscriptions, to recover persistent messages, to roll back open transactions, and to recreate its routing table for undelivered messages. It can then resume message delivery.
The Message Queue service supports both file-based and JDBC compliant persistence modules (see Figure 3–1). File-based persistence is the default.
File-based persistence is a mechanism that uses individual files to store persistent data. If you use file-based persistence you can set broker properties to do the following:
Compact the data store to alleviate fragmentation as messages are added and removed.
Synchronize the in-memory state with the physical storage device on every write. This helps eliminate data loss due to system crashes.
Manage the allocation of messages to data store files and manage the resources needed for file management and storage.
File-based persistence is generally faster that JDBC-based persistence; however, some users prefer the redundancy and administrative control provided by a JDBC-compliant store.
JDBC-Based persistence uses a Java Database Connectivity (JDBCTM) interface to connect the broker to a JDBC-compliant data store. To have the broker access a data store through a JDBC driver you must do the following:
Set JDBC-related broker configuration properties. You use these to specify the JDBC driver used, to authenticate the broker as a JDBC user, to create needed tables, and so on.
Use the imqdbmgr utility to create a data store with the proper schema.
Complete procedures for completing these tasks and related configuration properties are detailed in the Chapter 4, Configuring a Broker, in Oracle GlassFish Message Queue 4.4.2 Administration Guide.
The Message Queue service supports authentication and authorization (access control) for each broker instance, and also supports encryption:
Authentication ensures that only verified users can establish a connection to the broker.
Authorization specifies which users or groups have the right to access resources and to perform specific operations.
Encryption protects messages from being tampered with during delivery over a connection.
Authentication and authorization depend upon a repository that contains information about the users of the messaging system—their names, passwords, and group memberships. In addition, to authorize specific operations for a user or group, the broker must check an access control properties file that specifies which operations a user or group can perform. You are responsible for setting up the information the broker needs to authenticate users and authorize their actions.
Figure 3–2 shows the components needed by the broker to provide authentication and authorization.
As Figure 3–2 shows, you can store user data in a flat file user repository that is provided with the Message Queue service, you can access an existing LDAP repository, or you can plug in a Java Authentication and Authorization Service (JAAS) service. You set a broker property to indicate your choice.
If you choose a flat-file repository, you must use the imqusermgr utility to manage the repository. This option is easy to use and built-in.
If you want to use an existing LDAP server, you use the tools provided by the LDAP vendor to populate and manage the user repository. You must also set properties in the broker instance configuration file to enable the broker to query the LDAP server for information about users and groups.
The LDAP option is better if scalability is important or if you need the repository to be shared by different brokers. This might be the case if you are using broker clusters.
If you want to plug-in an existing JAAS authentication service, you need to set the corresponding properties in the broker instance configuration file.
When a client requests a connection, the client must supply a user name and password. The broker compares the specified name and password to those stored in the user repository. On transmitting the password from client to broker, the passwords are encoded using either base 64 encoding or message digest (MD5) hashing. MD5 is used for a flat file repository; base 64 is required for LDAP repositories. If using LDAP you may want to use the secure TLS protocol. You can set broker properties to configure the type of encoding used by each connection service separately or to set the encoding on a broker-wide basis.
When a user attempts to perform an operation, the broker checks the user's name and group membership (from the user repository) against those specified for access to that operation (in the access control properties file). The access control properties file specifies permissions to users or groups for the following operations:
Connecting to a broker
Accessing destinations: creating a consumer, a producer, or a queue browser for any given destination or all destinations
Auto-creating destinations
You set broker properties to specify the following information:
The name of the access control file
How passwords should be encoded
How long the system should wait for a client to respond to an authentication request from the broker
Information required by secure connections
In addition to the file-based and LDAP-based built-in authentication mechanisms, Message Queue also supports the Java Authentication and Authorization Service (JAAS), which allows you to plug a variety of services into the broker to authenticate Message Queue clients.
JAAS defines an abstraction layer between an application and an authentication mechanism, allowing the desired mechanism to be plugged in with no disruption or change to application code. For the Message Queue service, the abstraction layer lies between the broker and the authentication provider. By setting a few broker properties, it is possible to plug in any JAAS-compliant authentication service and to upgrade or change this service with no disruption or change to broker code.
The service to be plugged in consists of a LoginModule and of logic that performs the authentication. A JAAS configuration file contains the location of the LoginModule. When the broker starts up it locates this file and uses information in the file to determine which LoginModules it will use to perform the authentication. The fact that the broker plugs in an authentication service is transparent to the client; the client continues to pass authentication information to the broker as before and gains access to broker services if the identifying information (user name, password) is authenticated by the plugged in service.
For complete information about JAAS-based authentication, see Using JAAS-Based Authentication in Oracle GlassFish Message Queue 4.4.2 Administration Guide.
To encrypt messages sent between clients and broker, you need to use a connection service based on the Secure Socket Layer (SSL) standard. SSL provides security at a connection level by establishing an encrypted connection between an SSL-enabled broker and an SSL-enabled client.
You can set broker properties to specify the security properties of the SSL keystore to be used and the name and location of a password file.
For more information, see Message Encryption in Oracle GlassFish Message Queue 4.4.2 Administration Guide
Message-Oriented Middleware (MOM) systems use a broad spectrum of technologies and standards to provide messaging services. Often, these technologies and standards are incompatible, leading to MOM systems that cannot communicate with each other in a larger enterprise application context.
To alleviate this inability to communicate, Message Queue incorporates bridge services, which are overseen by the Bridge Service Manager, an application that runs in same JVM as a broker. The Bridge Service Manager supports individual bridge services of various types. Each type of bridge service provides connectivity at the broker level to a MOM technology or standard that would otherwise be unavailable in Message Queue.
At present, Message Queue provides two bridge services, the JMS bridge service and the STOMP bridge service.
Because the JMS specification does not dictate the communication protocol between brokers and clients, each JMS provider (including Message Queue) has defined and uses its own propriety protocol. This situation has led to non-interoperability across JMS providers.
The JMS bridge service in Message Queue closes this gap by enabling a Message Queue broker to map its destinations to destinations in external JMS providers. This mapping effectively allows the Message Queue broker to communicate with clients of the external JMS provider.
The JMS bridge service supports mapping destinations to external JMS providers that:
Are JMS 1.1 compliant
Support JNDI administrative objects
Use connection factories of type javax.jms.ConnectionFactory or javax.jms.XAConnectionFactory
Support the XA interfaces as a resource manager for transacted mapping
As an administrative and management convenience, the JMS bridge service supports the creation of any number of JMS bridges in a broker. Each JMS bridge in the broker is identified by a unique name, has its own configuration, and is managed separately from other JMS bridges in the broker.
A JMS bridge consists of two primary components:
One or more links, each of which maps between a destination in the Message Queue broker and a destination in an external JMS provider or in another Message Queue broker.
A default Dead Message Queue (DMQ) where undeliverable messages are sent. Additional, special-purpose DMQs can also be specified.
To provide destination mapping, each link consists of:
A source: the destination from which the JMS bridge receives messages. The source consists of a connection factory for creating connections to a JMS provider and a destination in that provider.
A target: the destination to which the JMS bridge forwards messages received from the source. The target consists of a connection factory for creating connections to a JMS provider and a destination in that provider. Additionally, a target can optionally specify a message transformer that alters messages from the source before forwarding them to the target destination.
Links are unidirectional. Links that have an external JMS provider or another Message Queue broker as their source are called inbound links, and links that have the Message Queue broker as their source are called outbound links.
To provide flexible, high-performing message transfer between mapped destinations, a JMS bridge offers these features:
Pooled, shared, and dedicated Connections
Transactional message transfer
JMS bridges in enhanced (high availability) broker clusters
Message transformation during message delivery
JMSReplyTo header processing
Dead Message Queue (DMQ) processing
The STOMP (Streaming Text Oriented Messaging Protocol) open source project at http://stomp.codehaus.org defines a simple communication protocol that clients written in any language can use to communicate with any messaging provider that supports the STOMP protocol.
Message Queue provides support for the STOMP protocol through the STOMP bridge service. This service enables a Message Queue broker to communicate with STOMP clients.
The STOMP bridge service provides the features needed to fully integrate STOMP messaging into the JMS messaging environment of Message Queue:
Registration with the Message Queue Port Mapper service so that STOMP clients can discover the service dynamically
Support for TCP and SSL/TLS connections, including SSL/TLS connections requiring client authentication
Automatic conversion of STOMP frame messages to and from JMS BytesMessage and TextMessage types
Extensible message handling and transformation (by defining a custom message transformer)
Support for the full STOMP protocol, including the STOMP JMS bindings
The broker includes components for monitoring and diagnosing application and broker performance. These include the components shown in the following figure:
Components that generate data: a metrics generator and broker code that logs events.
A logger component that writes out information to a number of output channels.
A metrics message producer that sends JMS messages containing metrics information to topic destinations for consumption by JMS monitoring clients.
A comprehensive set of Java Management Extensions (JMX) MBeans that expose broker resources using the JMX API
Support for the Java ES Monitoring Framework
The following subsections describe these components.
The metrics generator provides information about broker activity, such as message flow in and out of the broker, the number of messages in broker memory and the memory they consume, the number of open connections, and the number of threads being used.
You can set broker properties to turn the generation of metric data on and off, and to specify how frequently metrics reports are generated.
The Message Queue logger takes information generated by broker code and the metrics generator and writes that information to standard output (the console), to a log file, and, on SolarisTM platforms, to the syslog daemon process in case of errors.
You can set broker properties to specify the type of information gathered by the logger as well as the type written to each of the output channels. In the case of a log file, you can also specify the point at which the log file is closed and output is rolled over to a new file. Once the log file reaches a specified size or age, it is saved and a new log file created.
For details about how to configure the logger and how to use it to obtain performance information, see Configuring and Using Broker Logging in Oracle GlassFish Message Queue 4.4.2 Administration Guide.
The metrics message producer shown in Figure 3–3 receives information from the metrics generator at regular intervals and writes the information into messages, which it then sends to one of a number of metric topic destinations, depending on the type of metric information contained in the message.
Message Queue clients subscribed to these metric topic destinations can consume the messages and process the metric data contained in the messages. This allows developers to create custom monitoring tools to support messaging applications. For details of the metric quantities reported in each type of metrics message, see Chapter 21, Metrics Information Reference, in Oracle GlassFish Message Queue 4.4.2 Administration Guide. For information about how to configure the production of metrics messages, see Chapter 4, Using the Metrics Monitoring API, in Oracle GlassFish Message Queue 4.4.2 Developer's Guide for Java Clients and Using the Message-Based Monitoring API in Oracle GlassFish Message Queue 4.4.2 Administration Guide.
The broker implements a comprehensive set of Java Management Extensions (JMX) MBeans that represent the broker's manageable resources. Using the JMX API, you can access these MBeans to perform broker configuration and monitoring operations programmatically from within a Java application.
In this way, the MBeans provide a Java application access to data values representing static or dynamic properties of a broker, connection, destination, or other resource. The application can also receive notifications of state changes or other significant events affecting the resource.
For more information see JMX-Based Administration.
Message Queue supports the Sun Java Enterprise System (Java ES) Monitoring Framework, which allows Java Enterprise System components to be monitored using a common graphical interface. This interface is implemented by a web-based console called the Sun Java System Monitoring Console. If you are running Message Queue along with other Java ES components, you might find it more convenient to use a single interface to manage all these components.
The Java ES monitoring framework defines a common data model (CMM) to be used by all Java ES component products. This model enables a centralized and uniform view of all Java ES components. Message Queue exposes the following objects to the Java ES monitoring framework:
the installed product
the broker instance name
the broker port mapper
each connection service
each physical destination
the persistent store
the user repository
Each one of these objects is mapped to a CMM object whose attributes can be monitored using the Java ES monitoring console. At runtime, administrators can use the console to view performance statistics, create rules to monitor automatically, and acknowledge alarms. For detailed information about the mapping of Message Queue objects to CMM objects, see the Sun Java Enterprise System Monitoring Guide.
Using the Java ES Monitoring Framework will not impact broker performance because all the work of gathering metrics is done by the monitoring framework, which pulls data from the broker's existing monitoring data infrastructure.
This section describes the tools you use to configure and manageMessage Queue broker services. The tools fall into two categories:
The following illustration shows the administration tools provided by Message Queue for configuring and managing broker services.
The administration tools include the following command line interfaces:
Broker utility (imqbrokerd). Used to start a broker. You can use options to the imqbrokerd command to specify whether brokers should be connected in a broker cluster and to specify additional startup configuration information.
Command utility (imqcmd). Used after starting a broker to manage broker resources, such as connection services, connections, durable subscriptions, transactions, physical destinations, and so forth.
Object Manager utility (imqobjmgr). Used to create, list, update, and delete administered objects in a JNDI object store.
User Manager utility (imqusermgr). Used to populate a file-based user repository for user authentication and authorization.
Database Manager utility (imqdbmgr). Used to create and manage a JDBC-based persistent data store. (The built-in file store requires no external management.)
Key Tool utility (imqkeytool). Used to generate self-signed broker certificates needed for SSL authentication.
Service Administrator utility (imqsvcadmin). Used to install, query, and remove a broker as a Windows service.
In addition to the command line utilities shown in Figure 3–4,Message Queue administration tools also include the GUI-based Administration Console. The Administration Console combines some of the capabilities of the Command utility (imqcmd) and the Object Manager utility (imqobjmgr). You can use it to do the following:
Manage a broker, its connection services, and other resources.
Create, update, and delete physical destinations.
Connect to a JNDI object store, add administered objects to the store, and manage them.
To serve customers who need a standard programmatic means to monitor and access the broker, Message Queue also supports the Java Management Extensions (JMX) architecture, which allows a Java application to manage broker resources programmatically.
Resources include everything that you can manipulate using the Command utility (imqcmd) and the Message Queue Admin Console: the broker, connection services, connections, destinations, durable subscribers, transactions, and so on.
Management includes the ability to dynamically configure and monitor resources, and the ability to obtain notifications about state changes and error conditions.
The JMX specification defines an architecture for the instrumentation and programmatic management of distributed resources. This architecture is based on the notion of a managed bean, or MBean: a Java object, similar to a JavaBean, representing a resource to be managed. Message Queue MBeans are associated with individual resources such as connection services, connections, or destinations, or with whole categories of resources, such as the set of all destinations on a broker. There are separate configuration MBeans and monitor MBeans for setting a resource's configuration properties and monitoring its runtime state.
Java applications access MBeans through remote method invocation (RMI) protocols. The MBeans are hosted by an MBean server in the broker, which functions as an MBean container. The MBean server is accessed by means of a RMI connector, which is used to obtain an MBean server connection, which, in turn, provides access to the individual MBeans.
The JMX specification defines an architecture that enables the programmatic management of any distributed resource. This architecture is defined by design patterns, APIs, and various services.
JMX-based administration provides dynamic, fine grained, programmatic access to the broker. You can use this kind of administration in a number of ways.
You can include JMX code in your JMS client application to monitor application performance and, based on the results, to reconfigure the Message Queue resources you use to improve performance.
You can write JMX client applications that monitor the broker to identify use patterns and performance problems, and you can use the JMX API to reconfigure the broker to optimize performance.
You can write a JMX client application to automate regular maintenance tasks, rolling upgrades, and so on.
You can write a JMX client application that constitutes your own version of the Command utility (imqcmd), and you can use it instead of imqcmd.
You can use the standard Java Monitoring and Management Console (jconsole) that provides standard web browser access to the broker's MBeans.
JMX is the Java standard for building management applications and is widely used for managing Java EE infrastructure. If your Message Queue client is a part of a larger Java EE deployment, JMX support allows you to use a standard programmatic management framework throughout your Java EE application. Message Queue is based on the JMX 1.2 specification, which is part of JDK 1.5.
To manage a Message Queue broker using the JMX architecture, see Oracle GlassFish Message Queue 4.4.2 Developer's Guide for JMX Clients. For information on JMX infrastructure and configuring the broker's JMX support, see Appendix D, JMX Support, in Oracle GlassFish Message Queue 4.4.2 Administration Guide.
This section describes the tasks that you need to complete to support a Message Queue development or a production environment.
In developing a client component, it's best to keep administrative work to a minimum. The Message Queue product is designed to help you do this and can be used out of the box. It should be enough just to start the broker. The following practices allow you to focus on development:
Use default implementations of the data store (built-in file persistence), the user repository (file-based), and access control properties file. These are adequate for developmental testing. The default user repository is created with default entries that allow you to use the broker immediately after installation. You can use the default user name (guest) and password (guest) to authenticate a client.
Use a simple file-system object store by creating a directory for that purpose, and store administered objects there. You can also instantiate administered objects directly in code if you prefer not to create an object store at all.
Use auto-created physical destinations rather than explicitly creating destinations on the broker. See the appropriate developer's guide for information.
In a production environment, message service management plays a key role in application performance and in meeting the enterprise requirements for scaling, availability, and security. In this environment, the administrator has many more tasks to perform. These can be roughly divided into setup and maintenance operations.
Typically, you have to perform the following setup operations:
Secure administrative access
Whether you use a file-based or LDAP user repository, make sure that the administrator is in the admin group and has a secure password. If necessary, create a secure connection to the broker for the administrator.
Secure client access
Whether you use a file-based or LDAP user repository, populate the user repository with the names of users who can access the message service and edit the access control properties file to give them appropriate authorization. If necessary set up SSL-based connection services. To prevent unauthenticated connections, be sure to change the "guest" user's password.
Create and configure physical destinations
Set destination attributes so that the number of messages and the amount of memory allocated for messages can be supported by broker resources.
Create and configure administered objects.
If you want to use an LDAP object store, configure and set up the store. Create and configure connection factory and destination administered objects.
If horizontal scaling and/or message service availability is required, create a broker cluster.
For a conventional broker cluster, create a cluster configuration file and designate a master broker.
For an enhanced broker cluster, create a cluster configuration file that specifies property values for enhanced cluster mechanisms.
To monitor and control broker resources and to tune application performance, you must do the following after an application has been deployed:
Support and manage application clients
Monitor and manage destinations, durable subscriptions, and transactions
Disable auto-create capability
Monitor and manage the dead message queue
Monitor and tune the broker
Recover failed brokers
Monitor, tune, and reconfigure the broker
Manage broker memory resources
Expand clusters if necessary
Manage administered objects
Create additional administered objects as needed and adjust connection factory attributes to improve performance and throughput.


text:
Interesting that Tomlin is rated in the top 5 coaches players want to play for...
October 26, 2008
Sports of The Times
N.F.L. Players Evaluate Their Coaches
By WILLIAM C. RHODEN
What do N.F.L. players really think about the coaches for whom they play and the franchises for which they work?
Outside of sound bites and manicured postgame comments, the collective thoughts of players about coaches and teams have remained a mystery. Until now.
Last season, the N.F.L. players union commissioned the Wharton Sports Business Initiative at the University of Pennsylvania to conduct an unprecedented survey of players. It was the first time players had been asked about issues related to their coaches. The survey asked players to name names, and the players overwhelmingly obliged.
Asked which active N.F.L. coaches they would most like to play for, the players picked Tony Dungy (Indianapolis Colts) followed by Lovie Smith (Chicago Bears) and Bill Belichick (New England Patriots). Herman Edwards (Kansas City Chiefs) was fourth and Mike Tomlin (Pittsburgh Steelers) fifth.
Asked to name the coaches they would least like to play for, the players named Tom Coughlin (Giants), Eric Mangini (Jets), Jon Gruden (Tampa Bay Buccaneers), Bobby Petrino (formerly of the Atlanta Falcons) and Belichick.
The naming of Belichick on both lists illustrated how players were willing to make compromises when it comes to winning.
The study is especially relevant at a time of midseason coaching changes, wide swings of performance levels from week to week and periodic episodes of player-coach confrontations.
I think this survey is historic, said Tukufu Zuberi, the chairman of the sociology department at Penn, who conducted the study with Camille Z. Charles, an associate sociology and education professor. Nothing like it has ever been done before.
Zuberi added: You always hear sportscasters and analysts ranking teams and ranking the best coaches and what is important about being a good coach. Its rare that the athletes themselves express their opinion. What this survey does is give the players a voice.
A total of 1,440 players, or roughly 80 percent of those active in 2007, completed the study by the Wharton Sports Business Initiative, a research and executive think tank that is not a degree-granting program.
The players were asked questions in six major categories, including the most influential coach in their lives and the five most important attributes for a head coach. The players were also asked to identify the worst organizations in the N.F.L. (Oakland no surprise there; Miami; Arizona; Cleveland; and Cincinnati) and the best (New England, Indianapolis, Dallas, Green Bay and Pittsburgh).
There was overwhelming common ground among the players despite their racial differences; 65 percent are African-American, 29 percent white, 3 percent Asian, 2 percent other and 1 percent Hispanic.
The good news for the N.F.L. is that 90 percent of the players said they respected their head coach, three-quarters said they trusted their head coach and 79 percent said their coach was top quality.
More than 50 percent of the players said their pro coach not their college or high school coach was the most influential coach in their lives.
According to the survey, the most desirable attributes in a head coach were good communication skills, followed by motivational skills, approachability, management skills and leading by example.
There were also significant differences between white and black players. For instance, respect and trust were listed by all players as crucial components for successful relationships, but white players expressed more trust and respect for their head coaches than black players.
Who would have thought that the most important things to players is that the coach respects them? Zuberi said. This has a fundamental impact on the players attitudes toward the coaches. I didnt expect that white players would trust and respect their coaches more than black players.
Another distinction was that African-American players were not entirely race neutral when it came to head coaches. Race matters.
Although all players agreed on the top 10 most desirable head coaches, there were subtle differences between white and black players.
Among all players, Dungy was selected as the top coach. White players ranked Belichick second, Smith third, the Denver Broncos Mike Shanahan fourth and the Tennessee Titans Jeff Fisher fifth.
Black players ranked Smith second, Belichick third, Edwards fourth and Tomlin fifth.
Edwards was sixth among white players, and Shanahan dropped to ninth among black players. Mike Holmgren of Seattle was ranked seventh among white players and 13th among black players.
Its not just a question of winning, it is a question of how the players feel about these coaches, Zuberi said.
In contrast to the mainstream workplace, black players are an overwhelming majority in the N.F.L.
This can be interpreted as a true meritocracy where the best talent prevails. On the other hand, power is unequally distributed as one moves up the ladder. Six of the 32 head coaches are African-American, and the presence of African-Americans becomes more rare the higher one goes in management.
The black football-playing majority must answer to a predominantly white power structure, which includes team executives and owners.
Given the disparity in trust and respect between blacks and whites, the study suggested a new model is needed for franchises that hope to get the most out of their players. This means going beyond simply relying on a cluster of veteran players to maintain order in the locker room. They must hire and promote respected African-Americans and place them into positions of power and authority.
Communication also requires a franchise to ask itself tough questions: Who can get the most out of players? Who can best understand players? Who has the greatest insight? Who can best speak to the culture?
It was no coincidence that black players listed four African-American coaches among their top five.
These are just the players opinions, Zuberi said of the study, but we havent been listening to those opinions.
A coachs ability to coach should be balanced against his ability to gain the trust and respect of the players. Players are expected to respect and trust the coach. The coach needs to do the same for the players.
The study was intended to be the first in a series of annual player surveys that will examine a variety of aspects of N.F.L. franchises including the front office and ownership.
N.F.L. players have long been viewed as parts to be moved about without much consideration given to what they think.
If the survey proves anything, its that players have perspectives and opinions. The question is whether management is listening.
E-mail: [email="email@example.com"]email@example.com[/email]

subset: commoncrawl


text:
Young Innovators Program
Clarkson University's Young Innovators program takes investing in the future of students to an entirely new level.
Our innovative approach to entrepreneurship and innovation allows students to trade an ownership stake in their company for full tuition.
Young Innovators are identified through the yearly business plan competition; they are students who have some form of intellectual property (e.g. provisional patent, copyright, trademark, trade secret, etc.) or who have built a business on an innovative idea. In lieu of tuition payments, these students attend Clarkson through a combination of merit-based financial aid and the University's acquisition of a 10% ownership interest in their business ventures. In addition to tuition, students also receive weekly guidance from Shipley Leadership, office space in our Peyton Hall incubator, and Clarkson alumni mentors.


text:
When you step into her office, there are conference championship plaques and banners, press clippings and other accolades that Madonna Thompson and her teams have racked up during her coaching career.
When you step into her office, there are conference championship plaques and banners, press clippings and other accolades that Madonna Thompson and her teams have racked up during her coaching career.
But one image stands out, in the corner above the area where her assistant coach, Chris Sanford, sits. It's a black-and-white portrait that, in a way, helped shape her life and career path before she was born.
In the photograph is a line of 10 women who played basketball for Collinwood High School in 1945. The photo's relevancy comes from the woman standing at the front of the line holding a basketball in the short shorts girls called uniforms back in the day.
The woman, now 85-year-old Clara Nell Duesterhoeft, was a school teacher for 40-plus years, but back then she was standout on the high school's girls basketball team. She is the grandmother of Thompson, Shelton State Community College women's basketball coach. Thompson's mother is a retired kindergarten teacher, but she too was a high school basketball standout. Eddie Thompson, Madonna's father, played basketball and football at Collinwood's rival — Wayne County High.
So before she said her first words or took her first steps, basketball was in Madonna's blood.
"From the time she was big enough to walk she was interested in ball," Eddie said in a telephone interview. "From the time she was in kindergarten she could dribble a ball equally well with either hand. Very ambidextrous and showed a lot of athleticism from an early age."
At age 39, Thompson has her Shelton State Lady Buccaneers just four victories away from the National Junior College Athletic Association national championship. Her team is 32-0 heading into tonight's second-round game in Salina, Kan.
Thompson pushes her team to its limits, and if players don't maintain a certain standard, she isn't afraid to let them know. In the team's final regular-season game, her second unit checked in with a 12-point lead midway through the second half. A few minutes and unforced turnovers later, the opponent cut it to six.
"Get off the floor," she yelled to the five girls she believes could be starters at other junior college programs.
Her starters got the message, as they quickly pushed the lead back to double digits and went on to finish the regular season undefeated for the first time in school history. She gets that fire and passion for the game from growing up in a life of basketball.
Small-town girl
Eddie Thompson recalls a time during Madonna's childhood when the two would toss a Nerf ball back and forth in the yard.
"She never missed a catch that was close to her," he said.
But Madonna, always looking for new challenges, wanted to take it up a notch. So, as Eddie remembers, Madonna grabbed a skateboard and rode down the driveway, telling him to toss her the ball.
"She never missed one or lost control of the skateboard," Eddie said. "She was always looking for challenges and things like that let me know she would be great at whatever she did."
Eddie is full of Madonna stories, including the one about how he and his wife, Margaret, decided to name her.
"You know how Madonna got her name, don't you?" Eddie asks. "Her name is Madonna Michelle. I was a big Beatles fan, still am, so I picked two of my favorite songs, 'Lady Madonna' and 'Michelle.'"
Born in Florence, Thompson grew up in Collinwood, Tenn., just 3 miles across the state line. With about 1,000 people in the town, there weren't many options outside of sports. She remembers playing in the woods for hours and only having basketball and soccer as options.
She was always competing, looking for challenges. Whether that was with her father or friends, her thirst for winning was the same.
"When she was in elementary school, we started playing one-on-one and she'd get mad when I let her beat me," Eddie said. "By the time she was in junior high, she was beating me. I wasn't letting her anymore."
Easy choice
In her small community, Madonna said it was easy to get the keys to the local gymnasium and get a pickup game going. She played with her dad, friends, guys and anyone else who was willing.
"The only sports my high school offered were cheerleading and basketball, so it wasn't a hard choice for me," Madonna said. "That's all I did. Year-round, my time was spent playing basketball. I can't imagine doing anything else."
That drive to be the best helped her become one of the top basketball players in the state. Thompson was a starting point guard as a freshman. She made the all-state tournament team that year and was a runner-up for Miss Basketball.
Thompson's play caught the attention of some Division I programs, in particular the University of Alabama.
"When I watched Madonna play, her intensity level was incredible," former UA coach Rick Moody said. "And it was obvious she was a pure shooter, and we needed that. She was just an intense competitor, and you could tell she absolutely hated to lose. Looking back, it was one of the greatest moves I ever made."
Final Four
After watching her cousin, Mia Daniel, who was two years older, star in high school and go on to play at the University of Kentucky, Thompson knew she wanted to play on the next level and knew she wanted to do it in the Southeastern Conference. She committed to play at Alabama early in her high school career after receiving offers from Middle Tennessee State and other schools.
She made an immediate impact at UA, earning a starting spot as a freshman.
"One thing that leaders do is they have a positive impact on others," Moody said. "Not just someone who knows what to say at the right time, someone who comes and laces up those tennis shoes every single day and competes and wants to be the best she can be for the right reasons. A lot of players along the way that want to be the very best they can be, but there are only a few that want to be the best they can be to win championships and be the best team player. In a nutshell, that's the impact she had."
Thompson felt comfortable from the start with the Crimson Tide.
"I made the transition fine because we had good players and good coaches on our team," she said. "Everyone from the training staff to the managers to the coaches were so supportive, and I always felt at home."
Thompson's years at Alabama, 1992-95, were some of the more successful in the program's history. Moody said the team led the nation in scoring and 3-point shooting percentage during Madonna's time at UA. She played as a combo guard, bringing the ball up the floor or spotting up for open 3s.
The team made the NCAA tournament every year, and reached the Final Four in 1994 with a 26-7 record.
"It was a great, once-in-a-lifetime experience for all of us," Thompson said. "It was tough and took a lot of hard work with people playing well at the right time. All things came together for us. We had the right chemistry and it was the right time. It was hard to get there, but we had a blast."
While any deep tournament run takes a total team effort, Moody said Thompson's contributions were a key factor.
"Her defensive intensity and ability to hit an open 3 was a huge part of our success that year," Moody said. "If they left her open, it was done. She just relished her role as the ultimate team player."
The calling
Thompson earned a master's degree in speech pathology. She got a job in her field, but that didn't last long. The game kept calling her name.
There was a void that grew larger each day she was away from basketball. She thought she would enjoy her time away from it, but it consumed her thoughts again.
"The more time that passed between me playing that last basketball game," she said, "I started missing it more and more and more. I kept thinking, 'I got to find a way to get back in.'"
So she spoke to Moody, and he had three opportunities for her. She explored those options and decided Shelton State was the best fit. With Moody's recommendation, she got the head coaching job that she continues to hold 15 years later.
"Basketball is definitely my thing, without a doubt," Thompson said. "It's the one thing that makes sense and comes easy to me. I'm comfortable with it and I enjoy it."
During her 15-year tenure, she has led Shelton State to nine Alabama Community College Conference championships, including two in a row and seven in the last eight years.
"When you win one you want to win another one," she said. "It becomes addictive. You want to keep that special feeling and never lose it. Ever."
Thompson enjoys the challenge of picking the right players and putting them together. Every player isn't built to respond to her aggressive coaching style, and she recruits accordingly.
"Some kids just don't respond to anything. They don't want to be pushed, and we try to avoid those kids," she said. "We don't want those kids here. I tell everyone that I will not lower my standards to meet them. They will have to meet me."
Sanford, her assistant, notes how competitive and detail-oriented Thompson is when recruiting players.
"You're going to have to play the way she wants you to play or you're not going to make it," Sanford said. "I really try to hammer that home because I don't want anyone coming here and thinking it's going to be a certain way when it's not."
Now those years of hard work and dedication has Thompson on the cusp of winning her first national championship. The road won't be easy, but she thinks this is the year her team has a legitimate shot at winning it all.
"I really think she would be ecstatic," Sanford said. "It would validate the program she's built. ... It would be a culmination of all of her hard work and dedication to this program. There would be a lot of raw excitement and emotion to win a national championship."


text:
Message Board
Maggie Madison Message Board
Talk about the novels, new and used books that Madison has written!
Author Madison's Book Reviews
Pinch Me
After healing her trampled heart and maintaining her weight at a size 14 for more than a year, chocoholic and yo-yo dieter, Megan Harrigan, is resigned to leaving her love life just as it is--a complete void. She's just putting her love life on hold until she loses enough weight to feel ... worthy. To Megan's mind, worthy doesn't come in anything over a size ten. When the boss's deliciously hunky nephew, comes to town, he's determined to succeed in repla...


text:
Artists draw their inspiration from a variety of places. Some travel to exotic locations in search of inspiring images. Others choose to stay much closer to home, seeking inspiration in the trees and wildlife of our Colorado town. Brandy Llewellyn, an Evergreen resident and artist, straddles two worlds in her search for artistic inspiration. Brandy and her husband spend winters in Colorado and summers in Sanibel Island, Fla. Having spent many years in U.S. coastal areas as a child, Llewellyn turned her fascination with the sea into a full-fledged love of coastal and maritime art.
If you currently subscribe or have subscribed in the past to the Canyon Courier, then simply find your account number on your mailing label and enter it below.
Click the question mark below to see where your account ID appears on your mailing label.
|ZIP Code:


text:
A second candidate has entered the race for outgoing Beaufort County Council Chairman Weston Newton's seat.
Mark Lawson, a sales manager for Servpro, filed financial disclosures with the S.C. Ethics Commission on Friday and Saturday. He'll face attorney Tabor Vaux - son of another local attorney, Roberts Vaux - Jan. 29 in the Republican Party primary.
Lawson says he's lived in Bluffton since 1996 but counts 22 years total in Beaufort County. The married father of three hasn't been politically active but has served as a coach, as an officer at the Hilton Head Presbyterian Church, as a member of the Bluffton High School Booster Club and as president of Bluffton Youth Sports.
"There's not a particular policy that I'm looking to change or make different, but I think there are a lot of things our County Council makes decisions on that affect all of us, from youth to senior citizens, and living here for 22 years I think the knowledge that I've gained as being part of the actual public would add a benefit to County Council," he said.
Newton vacated his seat to serve as a statehouse representative after 10 years as chairman. His renumbered and redrawn District 9 covers the heart of Bluffton, from Buck Island Road just south of U.S. 278 to Malphrus Road as well as the area south of S.C. 46 all the way to Daufuskie Island.
Lawson graduated with a degree in business administration from Washington and Jefferson College in Pennsylvania and worked as a real estate broker in charge of sales at Heritage Lakes for 10 years before leaving for Servpro when the market collapsed, he said.
"Real estate, construction and the tourism industry have been some of the major factors that help our economy, and so coming from that I've had experience in the real estate and development aspects," he said.
28-year-old Vaux cites his experience as an assistant solicitor in the 14th Circuit, a five-county district including Beaufort, as an asset. He graduated from the Charleston School of Law in 2008, split time between Beaufort and Jasper for two years, then spent two years running the day-to-day operations in Hampton and Allendale while handling cases as the sole prosecutor.
His wife, Erin, works as an assistant solicitor in Ridgeland. He's worked at Vaux and Marscher, the Old Town Bluffton firm of his father, since June.
Along with support for Beaufort County's land preservation program, he stressed regionalism and intergovernmental cooperation.
"It all kind of starts with communication and relationships and it will stem from there," he said. "Once you open up the lines - not that they're not already - but it's good to build on those relationships that are already there."
He said he views an upcoming reassessment expected to deal a blow to property values as the biggest obstacle on the county's agenda - one that needs balance as discussions over possible tax increases to make up lost revenue press forward.
"It might need to be a combination of both (cuts and tax increases)," he said. "Often times the answer might lie in the middle and not just fall to one side or the other."
He said he hasn't arrived at a firm position on going forward with the as-yet unfunded Bluffton Parkway realignment expected to cost about $25 million.
"I need to look more at studies and the costs associated," he said. "It's kind of one of those things where, right now, you can kind of see both sides of it and I need to look into it a bit more before I take a firm stance."
The only public event scheduled so far to meet candidates is the Jan. 17 meeting of the Beaufort County Republican Party, said Jerry Hallman, the county chairman.
"Nothing high profile as far as a debate or anything like that is concerned," he said. "I'm actually happy to have two people running."
Blain Lotz, Hallman's Democratic Party counterpart, did not return phone calls, but no Democratic candidates had filed paperwork with the S.C. Ethics Commission by the Monday deadline.
Residents can still run as a petition candidate by filing valid signatures from 5 percent of district voters with the Beaufort County Board of Elections by Jan. 18 at noon. The special election to fill the last two years of Newton's term will be held March 19.


text:
Long Beach, Calif. - Pacific erased a 17-point deficit and scored four points in 3.3 seconds for a 59-57 win over Richmond at the Long Beach Classic Saturday. Kendall Keyon's lay-up with 0.2 seconds remaining off a steal by KiKi Moore gave Pacific the win.
Moore finished with 15 points on 6-of-9 shooting, while Kenyon added 13 points, eight rebounds and four blocks, but saw her double-double streak snapped at five. Madison Parrish set a new career high with seven rebounds and tallied 12 points. Moore also added four assists and three steals.
Trailing 57-55, Moore's drive to the hoop rimmed out, but Kenyon was fouled on the rebound with 3.5 to play. Kenyon's clutch free throws knotted the game at 57-57, and Moore stole the inbounds pass from behind the three-point line. Moore found Kenyon underneath and she banked it in from the baseline for the win with 0.2 seconds left.
Pacific improves to 5-5 on the season, while Richmond falls to 5-7.
The Tigers out-scored Richmond 30-14 in the paint, but rallied from down 17 in the first half. Pacific fell behind 17-0 in the first 6:27, but roared back with a 25-7 run to take the lead.
The Tigers missed their first six shots from the field, while the Spiders hit back-to-back three pointers for a 12-0 lead. Richmond stretched it to 17-9 before Madison Parrish finally broke the seal after a 6:33 scoring drought.
Kenyon added an and-one, and blocked two consecutive shot attempts at the other end before Moore went coast-to-coast. Moore added another three points for a 10-0 run before Richmond restored a 10-point lead on a three-point play from Genevieve Okoro.
Pacific clamped down defensively, holding Richmond to two field goals in a span of 13 attempts, while Parrish hit a pair of free throws to cut the gap to 20-14 with 9:15 left in the first.
Unique Coleman knocked down a triple from the corner as the Tigers took their first lead, 25-24, with 5:21 left in the half. Shanice Butler and Moore hit lay-ups as the Tigers led 30-26, before Kristina Johnson's two free-throws with 1:26 to go. But the Spiders closed the half with the final three points.
Pacific held a 32-29 lead at half, as Moore led all scorers with 12 at the break. After starting 5-of-8, Pacific held Richmond to 5-of-27 shooting the rest of the first half. Pacific shot 39 percent in the first frame, to the Spiders 29 percent.
After the Spiders scored first to open the second, Marjorie Heard hit a jumper and Moore added a three-pointer. Parrish hit a free throw and Kenyon a baseline runner as Pacific led 40-35 with 13:08 to go.
Richmond reeled off five straight points to tie the game, and Okoro gave the Spiders their first lead of the second half with a free throw at the 12:11 mark, 41-40.
Claire Conricode drained a three from the wing to restore a 43-41 Pacific lead. Kenyon found Heard for an easy lay-in, but the Spiders refused to be squished, pulling within one at 49-48.
Hailie Eackles canned a try for a four-point lead and Shanice Butler's turn around floater put Pacific back up by five. Richmond scored four-straight from the free throw line, but Parrish and Lauren Tolson traded free throws as Pacific's lead held at one.
The Tigers came up empty on an offensive possession with two minutes left, as the Spiders took the lead, 57-55, on a three-pointer by Olivia Healy with 1:29 to play. After trading defensive stops, the Tigers broke out of a timeout with 20.7 seconds left.
Moore's drive rimmed out, but Kenyon posted the offensive rebound and was fouled with 3.5 seconds to go. Kenyon knocked down both free throws to knot the game at 57-57.
With 3.5 to go, the Spiders looked up court to try and complete a pass on the run for a game-winning attempt, but Moore read the play, stepped in and picked off the pass. Kenyon, who was fronting the inbounder, accepted a pass on the baseline and banked in a runner for the go-ahead score.
Richmond could only inbound with 0.2 seconds as the Tigers came away with their first win away from the Spanos Center.
Kenyon was named to the Long Beach Classic All-Tournament Team.
The Tigers are back in action next Saturday at 2 p.m. against Portland in the WCC opener at the Spanos Center.


text:
Java 1A Practical Class
Table of Contents
Last week you improved the error handling of your program by catching errors and throwing exceptions. You did this by defining your own exception,
PatternFormatException, which extended the class
Exception. This week you will explore what "extending" a class actually means by looking at inheritance in more detail. You will also use this knowledge to refactor your implementation of LoaderLife you wrote last week to separate out the data structure used to record the state of the world into a separate object.
Remember to check the course website regularly for announcements and errata:
An interface in Java defines a type, and specifies the methods which are required in any implementation of the interface. For example, we could state the following methods are required in an implementation which is able to store, update and draw the state of a world in the Game of Life:
package uk.ac.cam.acr31.life; public interface World { public void setCell(int x, int y, boolean alive); public boolean getCell(int x, int y); public int getWidth(); public int getHeight(); public int getGeneration(); public int getPopulation(); public void print(Writer w); public void draw(Graphics g,int width, int height); public World nextGeneration(int log2StepSize); }
Particular bits to note in this definition of the interface
World are the use of the keyword
interface in the definition (not
class), and the use of the semicolon (
;) instead of curly brackets (
{ and
}) after the method names, indicating that the methods themselves are merely prototypes or descriptions and cannot contain actual code.
The specification of the interface
World states that any implementation of the interface is required to provide nine methods:
getHeight, and so on. Since the interface does not provide an implementation of the methods, the following is wrong and will result in a compile error:
World w = new World(); //Wrong; will result in compile error
In order to implement an interface in Java you write a class which contains implementations of every method defined in the interface. In addition, you must use the keyword
implements to name the interface explicitly in the class definition. For example:
package uk.ac.cam.crsid.tick5; import uk.ac.cam.acr31.life.World; import java.io.Writer; import java.awt.Graphics; import java.io.PrintWriter; public class TestArrayWorld implements World { private int generation; private int width; private int height; private boolean[][] cells; public TestArrayWorld(int w, int h) { width = w; height = h; // TODO: set generation equal to zero // TODO: set cells to reference a new rectangular two-dimensional // boolean array of size height by width } protected TestArrayWorld(TestArrayWorld prev) { width = prev.width; height = prev.height; // TODO: set generation equal to prev.generation+1 // TODO: set cells to reference a new rectangular two-dimensional // boolean array of size height by width } public boolean getCell(int x, int y) { /* TODO */ } public void setCell(int x, int y, boolean alive) { /*TODO*/ } public int getWidth() { /*TODO*/ } public int getHeight() { /*TODO*/ } public int getGeneration() { /*TODO*/ } public int getPopulation() { return 0; } public void print(Writer w) { /*TODO*/ } public void draw(Graphics g, int width, int height) { /*Leave empty*/ } private TestArrayWorld nextGeneration() { //Construct a new TestArrayWorld object to hold the next generation: TestArrayWorld world = new TestArrayWorld(this); //TODO: Use for loops with "setCell" and "computeCell" to populate "world" return world; } public World nextGeneration(int log2StepSize) { TestArrayWorld world = this; //TODO: repeat the statement in curly brackets 2^log2StepSize times { world = world.nextGeneration(); } return world; } //TODO: Add any other private methods which you find helpful }
You will be instructed to complete this code later in the workbook. For the moment just read through it and the explanation that follows. Some of the keywords used (such as
private and
protected) might be unfamiliar to you. These are explained later.
In Java, a class may implement multiple interfaces, in which case a list of comma-separated interfaces should appear after the keyword
implements in the class definition.
You can create variables of type
World which reference an instance of a class which implements the interface
World. For example, if you've implemented a class called
MyWorldImpl which implements the
World interface, then the following is correct
MyWorldImpl a = new MyWorldImpl(); System.out.println(a.getPopulation()); World b = a; System.out.println(b.getPopulation());
or more simply
World b = new MyWorldImpl(); System.out.println(b.getPopulation());
Any class which implements the interface
World can be assigned to a variable of type
World. This allows easy substitution of multiple different implementations, providing an extensible method of defining new ways of storing the state of the world in Conway's Game of Life. For example, later on in this Workbook, you will adapt your code from Tick 2 which used a
long integer to store the state of a world in a class called
TestPackedWorld. You will also adapt code from Tick 3 and Tick 4 which used a Java array to store the state of the world in a class called
TestArrayWorld. Since both these classes will implement the
World interface, you can substitute one implementation in place of another when drawing the state of the world to the terminal or (as we shall see later) a graphical display.
The interface
World is provided for you inside the package
uk.ac.cam.acr31.life, as shown in the definition written at the start of this Workbook. This interface, along with several other classes in this package, have been written for you. Using the
World interface defined in this package enables the interoperability described above—it also allows you to plug in implementations by other students if you wish. To introduce the name "
World" as short-hand for
uk.ac.cam.acr31.life.World, you need to write
import uk.ac.cam.acr31.life.World; at the top of your source files. This has been done for you in
To use the interface
World you also need to download and save the jar file containing the interface definition from http://www.cl.cam.ac.uk/teaching/current/ProgJava/world.jar. To use the code available in this jar file, you will need to tell the java compiler (
javac) and the java runtime environment (
java) the location of the jar file. If you don't tell the compiler or the runtime where the jar file is, the tools won't be able to locate the definition of the
World interface and your own programs will not compile or run.
You can instruct the Java tools to look inside a jar file by providing an additional argument on the command line. For example, if you have saved
world.jar to your home directory, then you can tell the Java compiler to look at, and possibly use, the contents of
world.jar when compiling your own implementation of
TestArrayWorld as follows:
crsid@machine:~> javac -cp /home/crsid/world.jar:. \ uk/ac/cam/crsid/tick5/TestArrayWorld.java
The option
-cp stands for class path. The class path in Java is, by default, the set of directories and jar files which are searched for class definitions. By default, the standard library and current working directory are on the class path but, as you've seen above, you may have to manually add to the class path if you wish to work with libraries provided by third parties.
If you want to include multiple directories and jar files on the class path, then you can use the colon (
:) operator to separate them. In the example above, the classes within
world.jar, as well as the class files located in the current working directory (represented by "
.") are put on the class path. (Whilst the current working directory is on the class path by default, it is removed when using the
-cp option, so you will often need to include it again.)
-jar option you have used in previous weeks is actually just a convenient way of adding the jar file to the class path, and then executing the class specified as the entry point. For example, last week you built a jar file called
crsid-tick4.jar with the entry point set to
uk.ac.cam.crsid.tick4.LoaderLife. You can run the main method in
LoaderLife by executing:
crsid@machine:~> java -jar crsid-tick4.jar
which is the same as writing
crsid@machine:~> java -cp crsid-tick4.jar uk.ac.cam.crsid.tick4.LoaderLife
Create a new package called
uk.ac.cam.crsid.tick5 and copy the contents of
TestArrayWorld as shown in the previous section into a file with a suitable name inside this package. Copy across your implementation of
LoaderLife from last week, renaming the class
RefactorLife. Finally, copy across your implementations of
PatternLoader and
PatternFormatException. Remember to update the package statements at the top of your source files appropriately.
When implementing
TestArrayWorld you do not have to implement the
draw method, so as the comment suggests, you may leave it blank. Similarly you will see that
getPopulation method returns 0 rather than the correct answer. These are commonly known as method stubs. The idea is to put something simple in so that the program will compile and unrelated functionality will work. Once the program compiles the programmer will return to the stubs and incrementally replace them with working code.
Writer rather than simply printing using
System.out.print and
System.out.println. Here is a skeleton which you can use to complete the new version of
public void print(Writer w) { PrintWriter pw = new PrintWriter(w); // See the Java documentation for PrintWriter // // use pw.print("something") to write to the writer // use pw.println("something") to write a newline // // you must always call pw.flush() at the end of this method // to force the PrintWriter to write to the terminal (if you // do not, then data may be buffered inside PrintWriter). }
You can use the Java
OutputStreamWriter class to create an instance of type
Writer which outputs information to the terminal. For example, the following snippet of code should print the contents of a variable
world of type
World to the terminal:
Writer w = new OutputStreamWriter(System.out); world.print(w);
Remember to include appropriate import statements at the top of your source file. For example, you will need to write:
import java.io.PrintWriter; import java.io.OutputStreamWriter;
to successfully use the
PrintWriter and
World interface specifies a
nextGeneration method which takes a single argument called
log2StepSize. This argument states the number of generations to iterate through before returning the state of the new world. For example, if
log2StepSize has the value 0, then, since 20 = 1, executing the method
nextGeneration with the value 0 should update the state of the world by one generation. If
log2StepSize has the value 2, then since 22 = 4, executing the method
nextGeneration with the value 2 should update the state of the world by four generations. You should use a
for loop inside the method
nextGeneration to update the state of the world the correct number of times. You might find it helpful to recall that
1 << n is equivalent to 2n.
A good way to implement the
nextGeneration method described above is to first complete the private
nextGeneration method (the one which takes no arguments) which should perform a single timestep forward in the Game of Life. Then complete the original
nextGeneration method required by the interface by repeatedly calling your private
nextGeneration method. You will need to use the methods
computeCell and
countNeighbours which are discussed next.
In previous weeks you wrote several helpful methods inside the body of what is now called
RefactorLife. These methods include
countNeighbours and
computeCell. You should move these methods from
RefactorLife to
TestArrayWorld; they should become non-static, private methods and operate directly on the
cells field. For example, the method
countNeighbours should have the following prototype inside
private int countNeighbours(int x, int y)
When you've finished refactoring your code, your implementation of
RefactorLife should behave just as
LoaderLife did last week. For example, the following should work:
crsid@machine:~>java -cp /home/crsid/world.jar:. \ uk/ac/cam/crsid/tick5/RefactorLife \ http://www.cl.cam.ac.uk/teaching/current/ProgJava/life.txt 0 - ________ ___#____ _#_#____ __##____ ________ ________ ________ ________
Pressing Enter should show successive generations of the Game of Life. Typing q followed by Enter should quit the application as before.
In the last section you produced an implementation of the interface
World which used arrays to store the state of the world. In this section you will write a second class called
TestPackedWorld to use a
long integer to store the state of the world, just as you did in Tick 2.
In order to use your latest implementation of
RefactorLife you simply replaced all instances of
TestArrayWorld with
TestPackedWorld, but this now precludes the use of Java arrays to store the state of the world. A better solution is to accept an argument on the command line which instructs the program to use a particular implementation—arrays or
long—as the underlying storage mechanism.
The approach you should use is to modify
RefactorLife to accept an option on the command line to specify the underlying storage architecture used. If the user types "
--array" as the first argument, then the storage architecture used should be a Java array, using
TestArrayWorld; if the user types "
--long" as the first argument then the storage used to record the state of the world should be
TestPackedWorld. If no switch is specified, then your implementation of
RefactorLife should default to using Java arrays to store the state of the world. Here is an example invocation which requests the use of Java arrays using the "
--array" switch:
crsid@machine:~>java -cp /home/crsid/world.jar:. \ uk/ac/cam/crsid/tick5/RefactorLife --array \ http://www.cl.cam.ac.uk/teaching/current/ProgJava/life.txt 0
Here is an example invocation of which requests the use of a
long integer to store the state of the world:
crsid@machine:~>java -cp /home/crsid/world.jar:. \ uk/ac/cam/crsid/tick5/RefactorLife --long \ http://www.cl.cam.ac.uk/teaching/current/ProgJava/life.txt 0
Here is an example invocation which specifies no storage type (your code should default to using Java arrays):
crsid@machine:~>java -cp /home/crsid/world.jar:. \ uk/ac/cam/crsid/tick5/RefactorLife \ http://www.cl.cam.ac.uk/teaching/current/ProgJava/life.txt 0
You may have heard in lectures that you cannot compare strings for equality as follows:
String first = new String("a"); String second = new String("a"); if (first == second) { //does not perform String equality System.out.println("This is not printed"); } else { System.out.println("This is printed!"); }
this is because the equality operator for variables which reference Java objects (e.g.
first and
second above) returns
true only if the two references point to the same underlying object. In the above code snippet,
first and
second are variables which reference two separate instances of a Java String which contain the same character sequence.
To check whether the contents of two String objects contain the same characters you should use the
equals method of the String object:
if (first.equals(second)) { System.out.println("This is printed"); } else { System.out.println("This is not printed!"); }
All variables which reference Java objects contain an
equals method which you should use to compare two references for equality.
When you write your improved implementation of
RefactorLife, you should declare a variable of type
World to reference an instance of either
TestArrayWorld or
TestPackedWorld and use if-else statements to update the reference to point to the correct instance. Here is a skeleton piece of code:
public static main(String[] args) { String worldType = args.length == 3 ? args[0] : "--array"; //TODO: initialise other variables here and interpret format string // which defines the size and state of the world World world = null; if (worldType.equals("--array")) { world = new TestArrayWorld(/* TODO */); } else if (worldType.equals("--long") { world = new TestPackedWorld(/* TODO */); } else { //TODO: print a descriptive error message return; } //TODO: use the "world" variable to display the state of the world // on the terminal using the "print" method }
Your implementation of
TestArrayWorld and
TestPackedWorld share substantial amounts of identical code. This is bad from a software engineering
point of view because you have implemented the same bugs twice, and you'll have to fix them in two places. When you need to add new features you will have to add them in two places too. If you add more methods of storing the state of the world by creating new classes which implement
World, you'll then have three or more places to update with new features (or bug fixes)!
One solution to this is to use code inheritance to collect together the shared code in one place. Unlike interfaces, inheritance allows the programmer to share code between classes. Shared pieces of code are placed in the parent class, and this basic implementation is then extended by a child class. The child classes then automatically inherit any methods or fields provided in the parent class.
A parent class might not provide an implementation of all the methods which are expected to appear in the child classes. In which case, the parent class is an abstract class; since not all the methods have an implementation, it is not possible to create an instance of an abstract class. Next is an example abstract class which collects together all the shared code which is found in your implementation of
TestArrayWorld and
TestPackedWorld. A full explanation of this code is given in subsequent subsections of this Workbook.
package uk.ac.cam.crsid.tick5; import java.awt.Color; //TODO: insert other appropriate "import" statements here public abstract class WorldImpl implements World { private int width; private int height; private int generation; protected WorldImpl(int width, int height) { this.width = width; this.height = height; this.generation = 0; } protected WorldImpl(WorldImpl prev) { this.width = prev.width; this.height = prev.height; this.generation = prev.generation + 1; } public int getWidth() { return this.width; } public int getHeight() { return this.height; } public int getGeneration() { return this.generation; } public int getPopulation() { return 0; } protected String getCellAsString(int x,int y) { return getCell(x,y) ? "#" : "_"; } protected Color getCellAsColour(int x,int y) { return getCell(x,y) ? Color.BLACK : Color.WHITE; } public void draw(Graphics g,int width, int height) { int worldWidth = getWidth(); int worldHeight = getHeight(); double xscale = (double)width/(double)worldWidth; double yscale = (double)height/(double)worldHeight; for(int x=0;x<worldWidth;++x) { for(int y=0;y<worldHeight;++y) { int xpos = (int)(x*xscale); int ypos = (int)(y*yscale); int nextx = (int)((x+1)*xscale); int nexty = (int)((y+1)*yscale); if (g.hitClip(xpos,ypos,nextx-xpos,nexty-ypos)) { g.setColor(getCellAsColour(x, y)); g.fillRect(xpos,ypos,nextx-xpos,nexty-ypos); } } } }
//TODO: Complete here in parent public World nextGeneration(int log2StepSize) { //Remember to call nextGeneration 2^log2StepSize times } //TODO: Complete here in parent public void print(Writer w) { //Use getCellAsString to get text representation of the cell } //TODO: Complete here in parent protected int countNeighbours(int x, int y) { //Compute the number of live neighbours } //TODO: Complete here in parent protected boolean computeCell(int x, int y) { //Compute whether this cell is alive or dead in the next generation //using "countNeighbours" } // Will be implemented by child class. Return true if cell (x,y) is alive. public abstract boolean getCell(int x,int y); // Will be implemented by child class. Set a cell to be live or dead. public abstract void setCell(int x, int y, boolean alive); // Will be implemented by child class. Step forward one generation. protected abstract WorldImpl nextGeneration(); }
Note that the class
WorldImpl has no method of storing the state of the world. This task is left to child classes which extend
A few new keywords have been introduced in this class definition. The keyword
abstract prefixes both the keyword
class and several methods. Just as you saw earlier with interfaces, abstract methods contain no body and instead are terminated with a semi-colon (
Methods and fields are prefixed with one of three access modifiers. Fields or methods which are marked
private cannot be accessed by any other class (not even children); those marked
protected can only be accessed within the class or any child (or any subsequent child of the child); those marked with
public are accessible from any class. Finally, if a method or field does not have any access modifier, it is accessible by any class in the same package. You should use access modifiers to minimise access to fields and methods as much as possible in order to control complexity and therefore reduce the chance for unintentional interdependence between classes; this should help reduce bugs and make your code more legible to others (and yourself when you return to read it after a few months).
To create a subclass of
WorldImpl you use the
extends keyword. For example, to create a new child class of
WorldImpl called
ArrayWorld you should write the following:
public class ArrayWorld extends WorldImpl { ... }
Unlike interfaces, a class can only inherit from a single parent in Java. All the methods of the parent class are inherited by the child with the exception of the constructors. If a parent class has no default constructor (i.e. it has no constructor which takes zero arguments) then the child class must provide a constructor; in addition the constructor provided in the child class must call the constructor of the parent class. For example, the class
WorldImpl does not have a default constructor. Consequently
ArrayWorld as declared above must provide at least one constructor and inside it call a constructor for the parent class. This can be done as follows:
public class ArrayWorld extends WorldImpl { public ArrayWorld(int width, int height) { super(width,height); //possibly other constructor stuff here } ... }
In this example the special method
super is used to call a constructor in the parent class, in this case the constructor in
WorldImpl which takes two
int arguments. The call to
super must be the first statement found inside the body of the constructor. If a child has a method body provided for every abstract method found in a parent class, then the child class is no longer an abstract class, and concrete instances of it can be created. For example:
World world = new ArrayWorld(8,8);
is possible if
ArrayWorld provides implementations for the three abstract methods found in
The existence of a concrete class such as
ArrayWorld allows the last important keyword introduced in the class
WorldImpl to be discussed. The keyword is
this, which is a read-only variable which references the current object instance on which the method has been called. For example, in the code snippet above, the variable
world references a new instance of
ArrayWorld. Inside the body of the call to the constructor of the parent class (
this references the new instance of
ArrayWorld under construction. Therefore
this.width references the field called
width found in the class definition of
WorldImpl, whereas
width references the local variable of the same name which is the first argument to the constructor.
The keyword
this is optional in many cases. If you refer back to the constructor for
TestArrayWorld you will see that it has been omitted. This is because the arguments of the constructor are called
w and
h and so the member variable
width can be referred to without needing to write
this.width. If the argument of a method has the same name as a member variable then the argument masks the member variable.
Your implementation of
ArrayWorld and
PackedWorld both extend the abstract class
WorldImpl which in turn implements the interface
World. Therefore both
ArrayWorld and
PackedWorld are of type
World. Consequently, you can use the graphics display class inside
world.jar which you downloaded at the start of this workbook. To use the graphical display component, you first need to import the class by typing "
import uk.ac.cam.acr31.life.WorldViewer;" at the top of
RefactorLife. You can create a new instance of the
WorldViewer class as follows:
WorldViewer viewer = new WorldViewer();
To use an instance of
WorldViewer to display a
World you can use the
show method. For example, if you have a variable called
world of type
World then you can type:
This method can be called repeatedly to update the screen when a new generation is computed. You should destroy the
WorldViewer instance after you have finished by calling
Another representation of the Game of Life is to use an
int[][] to store the number of generations since a cell was last alive. An implementation of this can be downloaded from http://www.cl.cam.ac.uk/teaching/current/ProgJava/AgingWorld.java. Place a copy of this file in the package
uk.ac.cam.crsid.tick5 and update the package declaration in the file.
Keeping a history of the number of generations since each cell was last alive is not currently exploited. It would be nice to use colour to display the number of generations since the cell was last alive. To do so, you should add the following method to your
AgingWorld class as follows:
protected Color getCellAsColour(int x, int y) { int age = getCellAge(x, y); final int[] colors = new int[] {00000000,16711680,16717568,16724224,16731136,16738048,16744960, 16751616,16758528,16765440,16772096,16776982,16777062,16777141}; if (age >= colors.length) { return Color.WHITE;} return new Color(colors[age]); }
The method
getCellAsColour overrides the default implementation of
getCellAsColour found in
WorldImpl. When the
draw method is called on
AgingWorld, the
draw method provided by
WorldImpl will run as normal. However, the
draw method calls
getCellAsColour and the new implementation will be used instead of the default one in
WorldImpl. This is depicted graphically in Figure 1, "AgingWorld overrides the
getCellAsColour method".
To complete your tick you need to prepare a jar file with the contents of all the classes you have written in this workbook and email it to
email@example.com. Your jar file should contain:
uk/ac/cam/crsid/tick5/RefactorLife.java uk/ac/cam/crsid/tick5/RefactorLife.class uk/ac/cam/crsid/tick5/WorldImpl.java uk/ac/cam/crsid/tick5/WorldImpl.class uk/ac/cam/crsid/tick5/TestArrayWorld.java uk/ac/cam/crsid/tick5/TestArrayWorld.class uk/ac/cam/crsid/tick5/TestPackedWorld.java uk/ac/cam/crsid/tick5/TestPackedWorld.class uk/ac/cam/crsid/tick5/ArrayWorld.java uk/ac/cam/crsid/tick5/ArrayWorld.class uk/ac/cam/crsid/tick5/PackedWorld.java uk/ac/cam/crsid/tick5/PackedWorld.class uk/ac/cam/crsid/tick5/AgingWorld.java uk/ac/cam/crsid/tick5/AgingWorld.class uk/ac/cam/crsid/tick5/Pattern.java uk/ac/cam/crsid/tick5/Pattern.class uk/ac/cam/crsid/tick5/PackedLong.java uk/ac/cam/crsid/tick5/PackedLong.class uk/ac/cam/crsid/tick5/PatternLoader.java uk/ac/cam/crsid/tick5/PatternLoader.class uk/ac/cam/crsid/tick5/PatternFormatException.java uk/ac/cam/crsid/tick5/PatternFormatException.class
You should be able to run your program in one of three ways:
java -cp world.jar:crsid-tick5.jar \
uk.ac.cam.crsid.tick5.RefactorLife [url/file]
java -cp world.jar:crsid-tick5.jar \
uk.ac.cam.crsid.tick5.RefactorLife [url/file] [index]
java -cp world.jar:crsid-tick5.jar \
uk.ac.cam.crsid.tick5.RefactorLife [worldType] [url/file] [index]


text:
I always wrap each bottle individually with bubble-wrap and then put it in it's own gallon-size ziplock baggie. Line the box with more bubble-wrap, add the "bottle bundles", and then more bubble-wrap around and between all the bottles. So far, so good.
If you don't feel comfortable holding the package over your head and dropping onto concrete, you have not packed it well enough!


text:
Half pitcher, half belly itcher.
Baseball is a lonely sport. It's a game of individual achievement and individual failure. While spectators can chat, eat hot dogs, and chuck the occasional cell phone, the solitary player of baseball stands alone in a giant field, exposed if he makes the slightest mistake. Or the same mistake, over and over, as in the case of Chuck Knoblauch.
Sony's MLB 07: The Show gets exposed plenty by glitches, confusing controls, obscure rules and weak graphics. But it also knocks a solo shot out of the park: the "Road to the Show" mode that captures baseball's individual character. A beefed up version of last year's Career mode, the "Road to the Show" adds even more depth to the series' already-solid lineup of play options. Errors abound, but Sony deftly manages the save.


text:
I've been watching a lot of Ats lately. Watched all of the Spike Btvs episodes again too, which was great. Hadn't seen Season 6 for a long time, and was surprised how much I loved it. Season 7 was good but gah! Those bloody Potentials and depressed Buffy and some of the pacing and filler episodes just dragged it down for me.
Discovered that I really, really love Lies My Parents Told Me, despite Giles being possessed by an OOC pod-person. Was great to watch it after such a long break.
Angel Series 5 ultimately depresses me, as I long for Season 6! As soon as I finish watching season 5 I have to run off and read fan fiction to continue the story on.
Just Rewards - reading reviews elsewhere, I conclude that I liked it a lot more than most people. It does get many many brownie points just for the huge thrill of simple seeing Spike and Angel interacting. That in itself is enough to make me give it 10/10. Spike's initial reaction of vamping and attacking Angel, the snark, Angel's angry poutiness at Spike being there, it's all great. I also love that tiny change of tone when Spike pulls Angel up in the lobby, drops the baiting, lowers his voice and tells it like it is. Throughout season 5 the best Spangel moments for me are the ones where Spike and Angel cut through the crap and immediately understand what the other is saying. Especially when it's not necessarily something that one of the other characters would get ( ie - after Fred dies Spike tells Angel quietly that he can't sense Fred in Illyria at all. Angel gets it immediately). That's what being vampires and having a hundred years of kicking around together brings you.
The plot is crap. It doesn't make sense, and no matter how many times I watch it I still don't understand the Spike bluff and that whole deal with Hainsley.
But who cares? We get Spike in Angel's bedroom calling him 'Beefcake', Spike telling another character that he's Angel's date, Angel losing his shit multiple times during the episode, but still managing to look contrite and in need of comfort sex when he goes to kill Spike in the cemetery. What's not to love?
Spangel Interaction - 10/10. Dumb Plot - Minus -3 points. So 7/10 for me.
Oh, and one of my favourite lines of the whole series is in this episode .... Angel: ".... they eat babies!" Harmony: "Just their heads!" Bwahhhaaaaaa!!