tibco activespaces transactionsdownloads.fluency.kabira.com/fluency/p.fluency.javasdk-1... ·...

264
TIBCO ActiveSpaces Transactions ® Developer's Guide Software Release 1.1.4 Published February 06, 2011

Upload: others

Post on 16-Mar-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

TIBCO ActiveSpaces Transactions ®

Developer's Guide

Software Release 1.1.4Published February 06, 2011

Page 2: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Important InformationSOME TIBCO SOFTWARE EMBEDS OR BUNDLES OTHER TIBCO SOFTWARE. USE OF SUCH EMBEDDED OR BUNDLED TIBCOSOFTWARE IS SOLELY TO ENABLE THE FUNCTIONALITY (OR PROVIDE LIMITED ADD-ON FUNCTIONALITY) OF THE LICENSEDTIBCO SOFTWARE. THE EMBEDDED OR BUNDLED SOFTWARE IS NOT LICENSED TO BE USED OR ACCESSED BY ANY OTHERTIBCO SOFTWARE OR FOR ANY OTHER PURPOSE.

USE OF TIBCO SOFTWARE AND THIS DOCUMENT IS SUBJECT TO THE TERMS AND CONDITIONS OF A LICENSE AGREEMENTFOUND IN EITHER A SEPARATELY EXECUTED SOFTWARE LICENSE AGREEMENT, OR, IF THERE IS NO SUCH SEPARATEAGREEMENT, THE CLICKWRAP END USER LICENSE AGREEMENT WHICH IS DISPLAYED DURING DOWNLOAD OR INSTALL-ATION OF THE SOFTWARE (AND WHICH IS DUPLICATED IN LICENSE.PDF) OR IF THERE IS NO SUCH SOFTWARE LICENSEAGREEMENT OR CLICKWRAP END USER LICENSE AGREEMENT, THE LICENSE(S) LOCATED IN THE “LICENSE” FILE(S) OFTHE SOFTWARE. USE OF THIS DOCUMENT IS SUBJECT TO THOSE TERMS AND CONDITIONS, AND YOUR USE HEREOF SHALLCONSTITUTE ACCEPTANCE OF AND AN AGREEMENT TO BE BOUND BY THE SAME.

This document contains confidential information that is subject to U.S. and international copyright laws and treaties. No part of this documentmay be reproduced in any form without the written authorization of TIBCO Software Inc.

TIB, TIBCO, TIBCO Adapter, Predictive Business, Information Bus, The Power of Now, TIBCO ActiveMatrix BusinessWorks, are eitherregistered trademarks or trademarks of TIBCO Software Inc. in the United States and/or other countries.

EJB, Java EE, J2EE, and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in theU.S. and other countries.

All other product and company names and marks mentioned in this document are the property of their respective owners and are mentionedfor identification purposes only.

THIS SOFTWARE MAY BE AVAILABLE ON MULTIPLE OPERATING SYSTEMS. HOWEVER, NOT ALL OPERATING SYSTEMPLATFORMS FOR A SPECIFIC SOFTWARE VERSION ARE RELEASED AT THE SAME TIME. SEE THE README FILE FOR THEAVAILABILITY OF THIS SOFTWARE VERSION ON A SPECIFIC OPERATING SYSTEM PLATFORM.

THIS DOCUMENT IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.

THIS DOCUMENT COULD INCLUDE TECHNICAL INACCURACIES OR TYPOGRAPHICAL ERRORS. CHANGES ARE PERIODICALLYADDED TO THE INFORMATION HEREIN; THESE CHANGES WILL BE INCORPORATED IN NEW EDITIONS OF THIS DOCUMENT.TIBCO SOFTWARE INC. MAY MAKE IMPROVEMENTS AND/OR CHANGES IN THE PRODUCT(S) AND/OR THE PROGRAM(S)DESCRIBED IN THIS DOCUMENT AT ANY TIME.

THE CONTENTS OF THIS DOCUMENT MAY BE MODIFIED AND/OR QUALIFIED, DIRECTLY OR INDIRECTLY, BY OTHERDOCUMENTATION WHICH ACCOMPANIES THIS SOFTWARE, INCLUDING BUT NOT LIMITED TO ANY RELEASE NOTES AND"READ ME" FILES.

Copyright © 2010, 2011 TIBCO Software Inc. ALL RIGHTS RESERVED, TIBCO Software Inc. Confidential Information

Page 3: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

ContentsAbout this book ............................................................................................................... xiii

Conventions ........................................................................................................... xiiiCode snippets ......................................................................................................... xivFluency community ................................................................................................. xiv

1. Introduction ................................................................................................................... 1What is Fluency? ........................................................................................................ 1Managed objects ........................................................................................................ 1

2. Technical overview ......................................................................................................... 5Concepts and terminology .......................................................................................... 5Deployment model ..................................................................................................... 7Managed objects ........................................................................................................ 8Transactions .............................................................................................................. 9Distributed computing .............................................................................................. 17High availability ....................................................................................................... 29Configuration ........................................................................................................... 39Components ............................................................................................................ 43System Management ................................................................................................ 48

3. Developing distributed applications ................................................................................ 51Architecture ............................................................................................................ 51Application scope ..................................................................................................... 52Adding a node .......................................................................................................... 54Restoring a node ...................................................................................................... 54Debugging .............................................................................................................. 54

4. Java Virtual Machine Life Cycle ...................................................................................... 55Starting and Stopping ............................................................................................... 55Shutdown Hooks ...................................................................................................... 60Managing Threads ................................................................................................... 60Unhandled Exceptions .............................................................................................. 64

5. Transactions ................................................................................................................. 67Transaction boundaries ............................................................................................. 67Transactional classes ................................................................................................ 72Transaction thread of control ..................................................................................... 83Locking and deadlocks ............................................................................................. 85Interaction with Java monitors ................................................................................... 90Compensation .......................................................................................................... 93Unhandled exception handling .................................................................................. 97JNI transactional programming ................................................................................ 100Transactional class considerations ............................................................................ 101

6. Managed objects ......................................................................................................... 103Defining a managed object ...................................................................................... 103Managed object life cycle ........................................................................................ 107Equals and Hashcode .............................................................................................. 109Extents .................................................................................................................. 109Triggers ................................................................................................................ 115Keys and Queries ................................................................................................... 116Array copy-in/copy-out ............................................................................................ 134Reflection limitations ............................................................................................... 137

7. Distributed computing ................................................................................................. 139Distributed objects ................................................................................................. 139Distributed object life cycle ...................................................................................... 142Using directed create .............................................................................................. 143

iii

Page 4: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Using cache groups ................................................................................................ 145Unavailable node exceptions .................................................................................... 148Locating a remote object ......................................................................................... 149Transaction Notifiers .............................................................................................. 153State conflict .......................................................................................................... 155Extents .................................................................................................................. 155Guidelines ............................................................................................................. 155

8. High availability .......................................................................................................... 157Defining mirrored and replicated managed objects .................................................... 157Routing .................................................................................................................. 159Partitioning application data ..................................................................................... 163Partition state change notifiers ................................................................................. 165Timers .................................................................................................................. 168Failure exposure .................................................................................................... 171

9. Configuration .............................................................................................................. 173Defining configuration objects ................................................................................. 173Accessing configuration objects ............................................................................... 177Versions ................................................................................................................ 182Notifiers ................................................................................................................ 185Runtime objects ...................................................................................................... 190

10. Components .............................................................................................................. 193Defining a component ............................................................................................. 193Example ................................................................................................................ 196

11. System management .................................................................................................. 201Defining a system management target ...................................................................... 201Logging ................................................................................................................. 212

12. Monitoring applications .............................................................................................. 215Management console .............................................................................................. 215Object monitor ....................................................................................................... 217Events ................................................................................................................... 218

13. Reference ................................................................................................................. 221Deployment tool ..................................................................................................... 221Configuring default options ...................................................................................... 226Deployment tool example ........................................................................................ 228Debugging example ................................................................................................ 228Development appliance ........................................................................................... 230Java Debug Wire Protocol ....................................................................................... 236Class resolution ...................................................................................................... 236Change log format .................................................................................................. 237

Index ............................................................................................................................. 243

iv

TIBCO ActiveSpaces Transactions ®

Page 5: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

List of Figures2.1. Deployment model ....................................................................................................... 82.2. Distributed transaction ................................................................................................ 102.3. Distributed transaction node participants ...................................................................... 112.4. Distributed Transaction Notifiers ................................................................................. 132.5. Deadlock detection ..................................................................................................... 152.6. Distributed deadlock detection .................................................................................... 162.7. Distributed behavior execution .................................................................................... 182.8. Connection failure handling ......................................................................................... 242.9. Undetected communication failure ............................................................................... 262.10. Abandoned transaction .............................................................................................. 272.11. Transaction outcome voting ....................................................................................... 282.12. Keep-alive protocol ................................................................................................... 312.13. Synchronous Implicit Commit Transaction Protocol ..................................................... 322.14. Asynchronous Implicit Commit Transaction Protocol ................................................... 332.15. Partitions ................................................................................................................. 342.16. Synchronous updates ................................................................................................ 352.17. Deferred updates ...................................................................................................... 362.18. Splitting partitions .................................................................................................... 372.19. Partition failover handling .......................................................................................... 382.20. Configuration model ................................................................................................. 392.21. Configuration life cycle .............................................................................................. 412.22. Activating Components ............................................................................................. 442.23. Deactivating Components .......................................................................................... 452.24. Component Activation Failure .................................................................................... 462.25. Component Activation ............................................................................................... 472.26. Component Deactivation ........................................................................................... 483.1. Distributed Development Architecture ......................................................................... 524.1. JVM Shutdown Sequence ............................................................................................ 575.1. Undetected deadlock .................................................................................................. 915.2. Java Monitors and transaction locking .......................................................................... 926.1. Manager login screen ................................................................................................ 1078.1. Routing example sequence diagram ............................................................................ 15912.1. Manager login screen .............................................................................................. 21612.2. Node details display ................................................................................................ 21712.3. Object Monitor access from Development Appliance information screen ...................... 21812.4. Event cache ............................................................................................................ 21912.5. Accessing event monitor .......................................................................................... 22012.6. Event monitor display .............................................................................................. 220

v

Page 6: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

vi

Page 7: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

List of Tables2.1. Node location identifiers ............................................................................................. 182.2. Cache types ............................................................................................................... 212.3. Cache policies ............................................................................................................ 212.4. HA node states ........................................................................................................... 292.5. Partition states ........................................................................................................... 342.6. State transition audits .................................................................................................. 422.7. State transition methods .............................................................................................. 435.1. @Transactional annotation properties ........................................................................... 735.2. @TransactionalJavaObject annotation properties ........................................................... 745.3. @Isolation annotation properties .................................................................................. 756.1. Managed object behaviors ......................................................................................... 1037.1. @Distributed annotation properties ............................................................................ 1417.2. @CacheGroup annotation properties .......................................................................... 1427.3. @DirectedCreate Annotation Values ........................................................................... 1429.1. Configuration object definitions .................................................................................. 17310.1. Component properties ............................................................................................. 19311.1. System management annotations .............................................................................. 20113.1. Deployment tool options .......................................................................................... 22213.2. Fluency JVM Properties .......................................................................................... 22713.3. Development appliance customization properties ....................................................... 23213.4. Change log format .................................................................................................. 237

vii

Page 8: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

viii

Page 9: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

List of Examples3.1. Distributed Development ............................................................................................ 534.1. Calling Exit ................................................................................................................ 584.2. Operator control ......................................................................................................... 594.3. Managing Threads with Join ........................................................................................ 604.4. Managing Threads with a Shutdown Hook .................................................................... 614.5. Daemon Threads ........................................................................................................ 634.6. Unhandled Exception ................................................................................................. 644.7. Unhandled Exception Output ....................................................................................... 645.1. Transaction class ........................................................................................................ 675.2. Counting example ...................................................................................................... 705.3. Counting example output ............................................................................................ 715.4. Throwable cause example ........................................................................................... 715.5. Throwable cause example output ................................................................................. 725.6. @Transactional annotation .......................................................................................... 735.7. @TransactionalJavaObject annotation ........................................................................... 745.8. @Isolation annotation .................................................................................................. 755.9. Annotation audit failure ............................................................................................... 765.10. Annotation audit failure output ................................................................................... 775.11. Annotation examples ................................................................................................. 775.12. @TransactionalJavaObject annotation example ............................................................ 795.13. Static fields ............................................................................................................... 805.14. Transactional class examples ..................................................................................... 815.15. Transaction thread of control ..................................................................................... 835.16. Thread creation ........................................................................................................ 845.17. Object locking .......................................................................................................... 855.18. Object locking output ................................................................................................ 885.19. Avoiding lock promotion ............................................................................................ 885.20. Avoiding lock promotion output ................................................................................. 905.21. Transaction notifiers ................................................................................................. 935.22. Transaction notifier output ......................................................................................... 955.23. Transaction notifier object locks ................................................................................. 965.24. Unhandled exceptions ............................................................................................... 975.25. Unhandled exception output ...................................................................................... 985.26. Required transaction exception .................................................................................. 995.27. Required Transaction Exception Output .................................................................... 1005.28. Transactional JNI programming ............................................................................... 1006.1. Managed object ........................................................................................................ 1036.2. Mirrored managed object .......................................................................................... 1046.3. Replicated managed object ......................................................................................... 1046.4. @Managed annotation ............................................................................................... 1056.5. Deleting managed objects .......................................................................................... 1086.6. Managed object extents ............................................................................................. 1096.7. Extent locking .......................................................................................................... 1106.8. Extent locking output ................................................................................................ 1126.9. Extent object locking ................................................................................................. 1126.10. Triggers ................................................................................................................. 1156.11. Managed Object with a Unique Key .......................................................................... 1166.12. @Key Annotation .................................................................................................... 1176.13. @KeyList Annotation ............................................................................................... 1186.14. Duplicate Key Exception .......................................................................................... 1196.15. Unique Query ......................................................................................................... 121

ix

Page 10: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

6.16. Non-Unique Query .................................................................................................. 1236.17. Ordered Query ....................................................................................................... 1256.18. Range Query .......................................................................................................... 1286.19. Atomic Create of Unique Keyed Object ..................................................................... 1316.20. Array copy-in/copy-out ............................................................................................ 1346.21. Array copy-in/copy-out output .................................................................................. 1376.22. Reflection behavior .................................................................................................. 1376.23. Reflection behavior output ....................................................................................... 1387.1. Distributed annotation ............................................................................................... 1407.2. @CacheGroup annotation .......................................................................................... 1417.3. @DirectedCreate annotation ...................................................................................... 1427.4. Directed create ......................................................................................................... 1437.5. Directed create output ............................................................................................... 1457.6. Cache groups ........................................................................................................... 1457.7. Cache group output .................................................................................................. 1477.8. Invalid node ............................................................................................................. 1487.9. Invalid node output ................................................................................................... 1497.10. Locating a remote object .......................................................................................... 1507.11. Locating a remote object output ................................................................................ 1527.12. Distributed Transaction Notifiers .............................................................................. 1537.13. Transaction notifiers output ..................................................................................... 1558.1. Defining mirrored and replicated managed objects ...................................................... 1578.2. Routing example ....................................................................................................... 1608.3. Routing example output ............................................................................................. 1638.4. Partitioning application data ....................................................................................... 1648.5. Partitioning application data output ............................................................................. 1658.6. Monitoring partition state changes ............................................................................. 1668.7. Partition state change output ..................................................................................... 1688.8. Highly available timers .............................................................................................. 1698.9. Highly available timer output ..................................................................................... 1719.1. Configuration object .................................................................................................. 1739.2. Overriding default configuration type .......................................................................... 1749.3. Nested configuration definition .................................................................................. 1769.4. Nested configuration file ............................................................................................ 1769.5. User configuration version 1.0 .................................................................................... 1779.6. User configuration version 2.0 .................................................................................... 1789.7. Locating configuration objects .................................................................................... 1789.8. Version object ........................................................................................................... 1829.9. Configuration notifier ................................................................................................ 1859.10. Notifier initialization and termination ........................................................................ 18810.1. Component property file .......................................................................................... 19410.2. Location of kabira.properties in JAR file ..................................................................... 19410.3. Component notifier ................................................................................................. 19510.4. NotifierTwo.java ...................................................................................................... 19710.5. Defaults.java ........................................................................................................... 19710.6. default.kcs .............................................................................................................. 19710.7. ComponentMain.java ............................................................................................... 19810.8. Example component output ...................................................................................... 19911.1. Defining a management target .................................................................................. 20111.2. @ManagementTarget annotation .............................................................................. 20211.3. @Command annotation ............................................................................................ 20211.4. @Default annotation ................................................................................................ 20311.5. @Parameter annotation ............................................................................................ 20411.6. AnEnum.java .......................................................................................................... 206

x

TIBCO ActiveSpaces Transactions ®

Page 11: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

11.7. ExampleTarget.java ................................................................................................. 20611.8. ExampleMain.java ................................................................................................... 20811.9. ExampleTargetLifecycle.java .................................................................................... 20911.10. exampletargetsecurity.kcs ...................................................................................... 21011.11. Example Target Output .......................................................................................... 21111.12. Logging example ................................................................................................... 21211.13. Node log file messages .......................................................................................... 21313.1. Type change ........................................................................................................... 22413.2. Type change - second run output .............................................................................. 22513.3. Deployment tool example ......................................................................................... 22813.4. Debugging example ................................................................................................ 22913.5. Default high availability configuration ....................................................................... 23213.6. Default security configuration ................................................................................... 23413.7. Default domain configuration ................................................................................... 23413.8. Default node configuration ....................................................................................... 23513.9. Change log ............................................................................................................. 23713.10. Change log output ................................................................................................. 239

xi

Page 12: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

xii

Page 13: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

About this bookThis guide describes how to program Fluency. It provides a technical overview of all Fluency func-tionality and provides working programming snippets on how to access the Fluency features.

It is intended for the following types of readers:

• Java developers who want to get started developing Java applications using Fluency.

• Anyone looking for a technical overview of Fluency features.

This guide is organized into three general areas:

• Conceptional description of Fluency features. This provides the technical underpinnings of howFluency features work. This information is in Chapter 2.

• Reference material for using the Deployment Tool and Development Appliance. This informationis in Chapter 13.

• Using the Fluency features from a Java program. These chapters emphasis working code snippetsfor specific features. This information is in all other chapters of this guide.

This book is part of a set of Fluency documentation, which also includes:

Fluency Quick Start — This guide describes how to quickly get started using Java IDEs to developFluency applications.

Fluency Administration Guide — This guide describes how to install, configure, and monitor aFluency deployment.

Fluency Performance Tuning Guide — This guide describes the tools and techniques to tuneFluency applications.

Fluency System Sizing Guide — This guide describes how to size system resources for Fluencyapplications.

Fluency Javadoc — The reference documentation for all Fluency APIs.

ConventionsThe following conventions are used in this book:

Bold — Used to refer to particular items on a user interface such as the Event Monitor button.

Constant Width — Used for anything that you would type literally such as keywords, data types,parameter names, etc.

Constant Width Italic — Used as a place holder for values that you should replace with anactual value.

xiii

Page 14: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Code snippetsAll of the code snippets in this book are self contained. They run unmodified using the Fluencydevelopment environment described in the section called “Development appliance” on page 230.

All of the snippets should be run through the domainmanager node. Each snippet indicates whichapplication nodes it needs to be executed against.

The conventions used for the snippets are:

• All snippet package names start with com.kabira.snippets.

• The package name is the chapter name. For example the com.kabira.snippets.distrib-utedcomputing package contains all snippets for the Distributed Computing chapter.

• Each snippet has a single public class and zero or more nested classes to support the snippet.

• The public class name is the feature or function that is being demonstrated by the snippet. Forexample, the CacheGroup class name is demonstrating distributed Cache Groups.

• Each public class has a main that runs the snippet.

• No command line arguments are required to run the snippet.

• The node(s) on which the snippet must be executed are indicated in the comments for the snippet.

• domainname = Kabira Development - run snippet on all nodes.

• domainnode = <node name> - run the snippet against the specified node.

Fluency communityThe Fluency online community is located at https://devzone.fluency.kabira.com. Theonline community provides direct access to other Fluency users and the Fluency development team.Please join us online for current discussions on Fluency development and the latest information onbug fixes and new releases.

xiv

About this book

Page 15: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

1Introduction

What is Fluency?Fluency is a transactional Java Virtual Machine (JVM) that allows organizations to develop highlyavailable, distributed, transactional applications using standard Java POJO programming model.

Fluency augments Java with these capabilities:

• Transactions - Fluency gives the ability to have truly transparent transactional Java.

• Persistence - Java objects can persist in Kabira's 64-bit shared memory object store.

• High Availability - Under catastrophic machine failure, Java objects continue to be available.

• Replication - Java objects can be replicated for scalability across multiple nodes.

Managed objectsFluency Managed Objects provide:

• Transactions

• Distribution

• Shared Memory Persistence

• Keys and Queries

• High Availability

• Replication

1

Page 16: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

TransactionsAll Fluency Managed Objects are transactional. Fluency transactions support transactional locking,deadlock detection, and isolation. Fluency supports single writer, multi-reader locking, with trans-parent lock promotion. Deadlock detection and retry is transparently handled by the Fluency JVM.Transactional isolation ensures that object state modifications are not visible outside of a transactionuntil the transaction commits.

Fluency transactions can optionally span multiple JVMs on different machines. Distributed lockingand deadlock detection is provided.

All transactional features are native in the Fluency JVM and do not require any external transactionmanager or database.

DistributionA Fluency Managed Object can be distributed. A distributed Managed Object supports transparentremote method invocation and field access. A distributed Managed Object has a single master nodeon which all behavior is executed. The master node also contains the master data for an object.

Shared memory persistenceFluency Managed Objects are always persistent in shared memory. This allows the object to livebeyond the lifetime of the JVM. Shared memory Managed Objects also support extents and triggers.

Keys and QueriesManaged Objects can optionally have one or more keys defined. An index is maintained in sharedmemory for each key defined on a Managed Object. This allows high-performance queries to beperformed against Managed Objects using a shared memory index.

High availabilityA Mirrored Managed Object has all object state transactionally copied to a backup node when theobject is modified. The backup node can take over all processing for the object when the primarynode is offline. Support is provided for restoring an object's state from the backup node to theprimary node during application execution without any service interruption.

Mirrored Managed Objects are contained in a Partition. One or more Partitions can exist on a singlenode. Each Partition has a primary and a backup node. Partitions can be migrated to different primaryand backup nodes during application execution without any service interruption. They can also bere-partitioned to distribute application load across different nodes without any service interruption.

A highly available timer service is provided to support transparent application timer notificationsacross failover and restore.

Object modifications are optionally written to the local file system on the primary and/or backupnodes in a change log to support both multi-node memory and file system redundancy.

All Fluency high-availability services are available without any external software or hardware.

2

Chapter 1. Introduction

Page 17: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

ReplicationA Replicated Managed object has all object state transactionally copied to all configured nodes whenthe object is modified. A Replicated Managed Object also has a primary and a backup node. Thisensures that there is a backup node available for replicated object modifications in the case ofprimary node failure.

3

Managed objects

Page 18: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

4

Page 19: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

2Technical overview

This chapter provides a conceptional overview of the Fluency features.

Concepts and terminologyThis section provides a high-level introduction to the key technical concepts provided by Fluency.These concepts are described in move detail in later chapters.

TransactionsFluency provides native JVM transactions for Java objects without any external databases or trans-action monitors. Fluency transactions can be local to a JVM or span multiple JVMs on one or moreFluency nodes on the same or different machines.

An atomic transaction guarantees that a series of modifications to one or more objects either alloccur (commit), or all do not occur (rollback). The state of the objects modified in the transactionsare guaranteed to be consistent once the transaction completes. Multiple transactions occurring onthe same objects are isolated from each other through transactional locking. Finally, once a trans-action completes, the changes are made durable to ensure that they can survive a system failure.

These transactional characteristics are called ACID (Atomicity, Consistency, Isolation, Durability).

Managed objectsManaged Objects are Java objects that have additional functionality provided by Fluency. The addi-tional functionality is specified through the use of annotations, inheritance, and configuration. Thereare no special APIs that need to be called to convert a Plain Old Java Object (POJO) into a FluencyManaged Object.

Managed Objects can provide one or more of the following characteristics:

• Transactionality

5

Page 20: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Distributed Computing

• Shared Memory Persistence

• Triggers

• Keys and queries

• High-Availability

• Replication

Distributed computingAll Fluency Managed Objects are distributed objects. They can be accessed across one or morenodes. A distributed object appears like a non-distributed object during development. However,during execution, when a method is invoked on the object, it may be transparently executed on aremote node.

MirroringA Mirrored Managed Object transactionally "mirrors" all changes to object state to a configuredbackup node. The changes can be maintained on the backup node in the same transaction in whichthey occurred (synchronous) or in a separate transaction (asynchronous).

All mirrored objects are associated with a Partition Identifier when they are created. The PartitionIdentifier uniquely identifies a Partition that defines the primary and backup nodes for the mirroredobject.

Mirrored objects can only be created, updated, and deleted on the currently active node for thePartition. Mirrored objects can be read on either the primary or the backup node. The Active nodefor a Partition is the configured primary node if it is active, or the backup node if the primary nodeis not currently active.

ReplicationA Replicated Managed Object supports all of the behavior of a Mirrored Managed object plus allobject state is copied to all nodes in a cluster. Replicated object state can be read on any node in thecluster.

ComponentsA component provides a mechanism to package up implementation and configuration into a singledeployable archive. A component is packaged as a JAR file. It may contain initialization and termin-ation methods that are executed when the component is initialized and terminated. It may alsocontain configuration files that are loaded and activated when the component is initialized, and de-activated and removed when the component is terminated.

Change logAll modifications to Fluency Mirrored and Replicated Managed Objects are optionally maintainedin a change log on the file system. A separate record is written to the change log for all object cre-

6

Chapter 2. Technical overview

Page 21: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

ations, updates, and deletions. The record contains the action performed on the object and the ac-tual object data.

Change logs can be enabled on the primary, backup, or both nodes through configuration data as-sociated with a Partition.

Deployment modelThe following concepts are used to describe the Fluency deployment model:

• Machine - a physical computer

• Node - a Fluency administration or application server

• Cluster - a logical grouping of Fluency nodes that communicate to support a distributed application.

• Domain - an administrative grouping of Fluency nodes for management and development.

• Domain Group - a sub-set of Fluency nodes in a Domain for management and development.

One or more Fluency nodes can run on a single machine.

A Fluency node can belong to one cluster.

A Fluency node can belong to one or more domains.

A domain group can belong to one domain.

A cluster can be managed by one or more domains. However, it is rarely useful to have a clustermanaged by more than one domain. A cluster can also span one or more domain groups.

A Fluency node can host one or more JVMs. JVMs can be started and stopped independently of anode.

7

Deployment model

Page 22: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Node

Machine

ClusterDomain

DomainGroup

JVM

Node

Machine

ClusterDomain

DomainGroup

JVM

*

1

*

1

*1

*

1

*

1

*

1

Figure 2.1. Deployment model

Managed objectsAs described above Fluency Managed Objects are backed by shared memory. They can also bemirrored and replicated to other nodes in the cluster.

Life cycleManaged Objects are not garbage collected. They must be explicitly deleted by the application.Managed Objects exist following a normal JVM or machine shutdown. They also survive node andmachine failures if they are mirrored or replicated to another machine.

ExtentsAn extent is a collection of all instances of a Managed Object. All Managed Objects have extentsmaintained. An extent can be used to find all instances of a Managed Object type at any time withouthaving to maintain the collection.

TriggersManaged Objects optionally support triggers. A trigger provides a mechanism to be notified whenfields in a Managed Object are updated or deleted.

Keys and QueriesManaged Objects can optionally have one or more keys defined using annotations. When a key isdefined on a Managed Object, an index is maintained in shared memory when Managed Objects

8

Chapter 2. Technical overview

Page 23: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

are created and deleted. An index associated with a mirrored or replicated Managed Object ismaintained on all nodes in the cluster.

Support is provided for:

• Unique and non-unique keys

• Ordered and unordered keys

Queries are supported that use the indexes defined by the keys on Managed Objects. Support isprovided for:

• Unique and non-unique queries

• Ordered and unordered queries

• Range queries

• Cardinality

• Atomic selection of an object that is created if it does not exist

• Explicit locking

TransactionsThis section describes the Fluency transaction functionality in more detail.

Local and distributed transactionsFluency transactions may be either local or distributed.

Local transactions are used on a single node even if they span multiple JVMs in a single node.

Distributed transactions are used between Fluency nodes. When a transaction spans Fluency nodesa global transaction is started on the node that initiates the distributed work. The initiating nodeacts as the transaction coordinator. There is no independent transaction coordinator in Fluency. AllFluency nodes act as a transaction coordinator for distributed work that they initiate.

9

Transactions

Page 24: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Com

mit

Node 1 Node 2 Node 3

Read Lock

Read Lock Granted

Commit

Begin

Read Lock

Read Lock Granted

Commit

Commit

Figure 2.2. Distributed transaction

Nodes may be added to a distributed transaction not only by the node that initiated the distributedtransaction, but by any node that participates in the distributed transaction.

10

Chapter 2. Technical overview

Page 25: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Com

mit(

GT

)

Node 1 Node 2 Node 3

GT

Commit (GT)

Begin LT1

Commit(LT1)

Node 4

LTn - Local Transaction

GT - Global Transaction

Begin LT2

GT Begin LT3

GT Begin LT4

GT(LT4)

GT(LT3, LT4)

GT(LT2, LT3, LT4)

Commit(GT)

Commit(GT)

Figure 2.3. Distributed transaction node participants

Figure 2.3 shows how nodes are added to a distributed transaction. In this diagram Node 1 startsa local transaction, LT1, and then initiates a global transaction, GT, to Node 2. Node 2 starts alocal transaction, LT2, on behalf of the global transaction GT and then initiates work on Node 3 in

11

Transactions

Page 26: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

the same global transaction GT. Node 3 initiates another local transaction LT3, and then initiateswork on Node 4, which starts another local transaction, LT4.

The response back from each of the nodes contains information on the local transaction was startedon the node, and any other nodes that started local transactions. This allows the initiating node, todetermine which nodes need to be committed when the global transaction is committed. This isshown in the diagram in the commit processing on Node 1 - a commit is sent to all four nodes,even though Node 1 only initiated a global transaction to Node 2.

There is no programmatic difference between local and distributed transactions. Fluency initiatesthe appropriate transaction type transparently depending on whether local or remote objects are inthe transaction. There is a difference in how deadlocks are detected. See the section called “Deadlockdetection” on page 14.

Transaction Notifiers  Applications can optionally install transaction notifiers that are calledwhen the transaction commits or rolls back. Transaction notifiers can be used to integrate with ex-ternal systems - both transactional and non-transactional. Transaction notifiers are executed on thenode on which they were installed. A distributed transaction may have transaction notifiers installedon multiple nodes by the application. In this case, the notifiers are executed on each node on whichthey were installed as part of committing or rolling back the distributed transaction.

12

Chapter 2. Technical overview

Page 27: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Com

mit

Node 1 Node 2 Node 3

Notifier installed

Commit

Begin

Notifier installed

Commit

Commit

Notifier

Called

Notifier

Called

Notifier

Called

Figure 2.4. Distributed Transaction Notifiers

LockingTransaction locks are used to maintain data consistency for the duration of a transaction. Transactionlocks are only taken on objects.

A transaction lock is taken on an object when a transactional field is accessed or modified. Thetransaction lock is released when the transaction commits or rolls back. Executing a method on anobject does not take a transaction lock (unless a transactional field is accessed in the method). Thisimplies that multiple threads can be executing the same method on the same object at the sametime.

No transaction locks are taken on extents when objects are created or deleted. This allows betterparallelism for object creation and deletion, but it does have implications to transactional isolation.See the section called “Locking and isolation” on page 110 for details.

13

Transactions

Page 28: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Fluency supports multiple reader, single writer locks. For example, multiple concurrent transactionscan read the same object fields, but only a single transaction can modify an object field.

Read locks can be promoted to a write lock if an object field is read, and then the field is set. A readlock would be taken on the initial field read and then promoted to a write lock when the field iswritten. If multiple transactions attempt to promote a read lock on the same object, all transactions,but one will generate a "promotion deadlock". A promotion deadlock causes the transaction torollback, dropping its object locks. The transaction is then replayed causing the transaction toreacquire the object locks.

Distributed objects support the same locking as objects on the local node. However, data cachingcan affect the locking policy by accessing the object data locally instead of from the remote node.Cached object data does not cause a distributed lock to occur. This can cause "state conflicts" if theobject data is modified. See the section called “Caching” on page 21.

Deadlock detectionSince transactions are running simultaneously, it is possible to have deadlocks in applications. Fluencyautomatically detects deadlocks and handles them in the following manner:

• the transaction that detected the deadlock is chosen as the "victim", this transaction is rolled backto where it started and is replayed.

• another transaction waiting on a transaction lock that was released is chosen as the "winner" andallowed to complete.

14

Chapter 2. Technical overview

Page 29: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Transaction 1 Object 1 Transaction 2

Request Readlock Request Write Lock

Grant Write Lock

Request Write Lock

Request Write Lock

Deadlock

Grant Read Lock

XRollbackTransaction 2

Object 2

Grant Write Lock

Lock Wait

Figure 2.5. Deadlock detection

Deadlock detection and resolution is transparent to the application programmer, but deadlocks areexpensive in both responsiveness and machine resources so they should be avoided.

Local transactions detect deadlocks immediately in the execution path. There is no timeout valueassociated with local transactions.

Distributed transactions use a configurable time-out value to detect deadlocks. If a lock cannot beobtained on a remote node within the configured time-out period, the distributed transaction isrolled back, releasing all locks. The transaction is then restarted.

15

Transactions

Page 30: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Abo

rt

Node 1 Node 2 Node 3

Read Lock

Read Lock Granted

Abort

Begin

Read Lock

Deadlock

Abort

Abort

Timed OutWaiting for Lock

Figure 2.6. Distributed deadlock detection

Because distributed deadlock detection is based on a time-out, applications with distributed deadlockswill perform poorly because the configured time-out has to be large enough to ensure that thereare never any false deadlocks reported during normal application processing.

IsolationFluency transactions support the following isolation levels for object fields:

• None - modifications are visible outside of the current transaction before it commits

• Serializable - modifications are only visible outside of the current transaction when it commits

16

Chapter 2. Technical overview

Page 31: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The isolation level of distributed objects can be affected by their configured cache policy. See thesection called “Caching” on page 21.

The following isolation level is supported for extents:

• Read Committed - extent iterations and cardinality will return inconsistent results in the sametransaction if other transactions create or delete objects in an extent.

Transaction loggingTo support rollback of a transaction, all object modifications must be logged. The Fluency loggingmechanism is done in memory by keeping a copy of the "before image" of any changes. Any objectreferences that are no longer referenced in a transaction are protected from garbage collection sothey are still available if the current transaction rolls back.

If the current transaction commits, all logged data is discarded and any reference locks to deletedobjects are released.

If the current transaction rolls back, the original state of all objects is restored. Any objects createdin the transaction are released to allow them to be garbage collected.

Distributed computingAny Fluency Managed Object can be a distributed object. A distributed object transparently providesremote method invocation and access to object fields across nodes. The full transactional guaranteesmade by Fluency for non-distributed objects are also true for distributed objects.

Access to a distributed object is through a normal Java object reference. All Managed Object refer-ences contain data to identify the node where the object was created.

The same instance of an object cannot exist on multiple nodes. Copies of an object's state may belocated on multiple nodes to improve performance or robustness, but the master copy is located ona single node - the node where the object was created.

An object's behavior executes on the node where the object was created. Any methods invoked onan object reference are sent to the master node and executed there.

Objects of the same type can be created on multiple nodes. This is done by installing the applicationclass files, or implementation, on multiple nodes. This is a common application architecture tosupport data partitioning and caching or service availability mechanisms.

17

Distributed computing

Page 32: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Node One Node Two

order(Node Two).cancel();

cancel()number

Order

cancel()number

Order order(Node One).cancel();

Figure 2.7. Distributed behavior execution

Figure 2.7 shows an Order class that has its implementation installed on two nodes - Node Oneand Node Two. Two instances of the Order class have been created, one on Node One and oneon Node Two. When the Order.cancel() method is executed on Node One, using the or-der(Node Two) instance, the method is executed on Node Two. The opposite is true for theorder(Node One) instance.

Location transparencyFluency provides location transparency for objects. This means that when an application accessesan object, its location is transparent—it may be local or on a remote node.

Location transparency is accomplished through the use of distributed references. All ManagedObjects created in Fluency have a distributed reference that contains the location where the objectwas created. Operations invoked on an object are routed back to the location where the object wascreated and executed on that node.

Fields are accessed on a local copy of the field data in memory. See the section called “Cach-ing” on page 21 for details on how object data is cached.

LocationsEvery Fluency node has both a location code and a node name. Location codes and node namesmust be unique across all nodes in a cluster. The default location information is:

Table 2.1. Node location identifiers

Default ValueIdentifier

Hash of node name.Location Code

The local host name.Node Name

18

Chapter 2. Technical overview

Page 33: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Both of these defaults can be changed to allow multiple Fluency nodes to run on the same host orto support a multi-homed host.

A location code is a numeric identifier that is encoded in every object reference associated withFluency Managed Objects. The location code is used by Fluency to determine the actual networklocation of the object. The location code of the node where the object was created is stored in theobject reference.

A node name is a human-readable string associated with every Fluency node. The node name isused to configure directed creates and High-Availability partitions.

Location discovery servicesThe location discovery services provide support for runtime discovery of location information. Thisdiscovery is required to allow nodes to discover all other nodes along with their location information.

The location discovery service provides runtime mapping between a location code or node nameand an actual network address. This mapping is done at runtime so network specific addresses don’tneed to be encoded in object references.

The location discovery service performs location discovery in two ways:

• static discovery using configuration information

• dynamic discovery using a UDP broadcast protocol

The system administrator can optionally configure the mapping between a node name and a locationcode/network address. This is only required if UDP broadcast cannot be used for location discovery.An example of when this would be necessary is if the remote node is across sub-net boundarieswhere broadcasts are not allowed.

If configuration information is not provided for a location name, UDP broadcast is used to performdynamic location information discovery. This has the advantage that no configuration for remotenodes has to be done on the local node - it is all discovered at runtime.

Location discovery is performed in the following cases:

• A directed create to a remote node

• A method or field is set on a remote object

When an object type is defined to use directed create, the location on which the create should occuris specified using a node name. When a create of this type is done, a location discovery request isdone by node name, to locate the network information associated with the node name if the networkinformation is not already known on the local node.

When an operation is dispatched on a remote object, a location discovery request is done by locationcode, to locate the network information associated with a location code, if the network informationis not already known on the local node.

Types and type conflictsType information for every class installed on the local node is broadcast to all other nodes whenthe local node starts up. As new types are added to the local node, their type information is broadcastto all other nodes in the cluster.

19

Distributed computing

Page 34: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

When a node receives type information for a type that is not present on the node, the node addsthat type.

When a node receives type information that is already present on the node, the node determines ifthe received type information differs from the type information which is currently installed on thenode. If the two types are the same, the node ignores the received type information. If the two typesdiffer, information about the differences is stored in a type-mismatch table. Type mismatches canhappen when different versions of the same type are installed on separate nodes.

Whenever data is marshaled for this type, either from the local node or when it is received from aremote node, the type mismatch table is checked to see if the type matches using a type identifierand the location code of the remote node. If the type identifier and location code combination isfound in the type mismatch table, a type conflict error is returned to the node that initiated thetransaction. The transaction will be rolled back and the data discarded. An event is raised indicatingthat this failure occurred.

A type mismatch error indicates an incorrectly configured system. The node(s) that have out-of-date types must be updated to ensure that there are consistent type definitions for the entire distrib-uted system.

Directed createsFluency supports creating distributed objects on specific nodes. This allows you to create an objecton any node in a cluster and the create actually happens on a specific node that may not be in thenode on which the create was done.

Annotations are used to specify a Managed Object to use the Directed Create distributed behavior.See the section called “@DirectedCreate annotation” on page 142.

A Directed Create type cannot also be a Cache Group type.

Cache groupsCache groups provide support for pushing object state to a set of network nodes. This maintains adistributed extent for the type, providing a very simple mechanism to access distributed referenceson a remote node. See the section called “Locating a remote object” on page 149 for more details.

Nodes are added to one or more cache groups by examining all types on the local node and determ-ining the cache groups for all of the installed types. This is the list of cache groups for which thisnode participates.

Cache groups are automatically maintained by Fluency. When a Fluency node is started it finds anyother nodes that are part of any of its cache groups and pulls all references for those types to thelocal node. Once the node is initialized the references are maintained by pushing updates to allnodes in the cache group as objects are created and deleted.

A node must have an implementation of the object installed to receive updates from other nodes. Ifa node does not have the implementation installed, the cache group update will not be performedand no references will be pushed to the node. A log message will be generated indicating the thata cache group is defined for the node, but no implementation installed.

Annotations are used to specify a Managed Object to use the Cache Group distributed behavior.See the section called “@CacheGroup annotation” on page 141.

20

Chapter 2. Technical overview

Page 35: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

A Cache Group type cannot also be a Directed Create type.

CachingFluency provides two distinct types of object data caching; passive, or "pull" caching, and active, or"push" caching.

The differences between these two types of caching are:

Table 2.2. Cache types

Passive caching copies field data to a remote node only when an object instance is accessedon the remote node. Passive caching is used for all distributed objects that are not part ofa cache group. This includes distributed objects using Directed Create.

Passive

Active caching automatically propagates all object creates, updates, and deletes to all remotenodes configured in a Cache Group.

Active

Once data is cached on a remote node, the data is refreshed based on the cache policies describedbelow. All field access is done using the local cached copy of data. This avoids network I/O requiredby other distribution technologies to access object field data.

In all cases, modifications to an object's fields on a remote node are written back to the node onwhich the object was originally created. The update happens in the same or a different transactionbased on whether asynchronous or synchronous transactionality is configured. See the sectioncalled “Asynchronous and synchronous updates” on page 22

Cache policies  Every distributed type has a cache policy. The cache policy controls when cacheddata is considered stale and should be read from the node on which the object was created.

The following cache polices can be defined for a type. These cache policies affect the behavior ofan object that is being accessed on a remote node. They do not affect the push caching done by aCache Group. The master node for an object is the one on which it was originally created.

Table 2.3. Cache policies

The cached copy is always considered stale. Every access to this object will cause thecached data to be refreshed.

NEVER

The cached copy is always considered valid. It is never refreshed.ALWAYS

The first time a reference is accessed, the cache is considered stale. After that the cachedcopy is always considered valid. It is never refreshed again.

ONCE

The cached copy is considered valid for a configured amount of time. The amount oftime after which it is considered stale is controlled by a cache time. If the object is ac-

TIMED

cessed after cache time has expired since it was originally read onto the node, it will berefreshed.

Refreshing a cached object implicitly takes a transaction write lock on that object.

Types that are defined as part of a cache group should have a cache policy of ALWAYS.This is because any updates made to instances of this type will be pushed out to all nodesin the cache group keeping the data in sync automatically. If the cache policy is not always,remote node caches may cause unnecessary updates when an object is accessed.

21

Distributed computing

Page 36: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Asynchronous and synchronous updates  Creates, writes, and deletes can be configuredto occur either asynchronously or synchronously with respect to the transaction in which the create,write or delete occurred.

If these operations are configured to occur asynchronously they will occur in a separate transactionon the remote node than they did on the local node. This implies that there may be data inconsistencybetween the two nodes for a period of time. There are no distributed locks taken on remote nodes.

If these operations are defined to occur synchronously they will occur in the same transaction onthe remote node as they did on the local node. This implies that there is always data consistencybetween two remote nodes. Distributed locks are taken on the remote node to ensure the dataconsistency.

Asynchronous operations may improve the overall performance of a distributed system because noremote locks are held. They also avoid the overhead associated with a distributed transaction. Thedownside is that there can be data inconsistency in a distributed system at a given point in time.This inconsistency lasts until the asynchronous work is executed on the target node.

Creates

Asynchronous creates cause an object to be created in a separate transaction on a remote node.Because the create is done in a separate transaction on the remote node there is no way for Fluencyto report a duplicate key error back to the node on which the object was created. If a duplicate keyis detected on the remote node, the create is not performed and a warning message is logged.

Reading and writing data

Object field data is transparently read from and written to a remote node when field data is accessedon a local node based on the caching policy.

Read operations are dispatched to a remote node to read field data depending on whether the cacheddata on the local node is stale or not. If the local cache is stale, a read will be done when a field isaccessed. It will complete before the get of the field data returns to the caller. All reads are done onthe remote node in the same transaction in which the field access occurs - in other words, they alwaysexecute synchronously.

When an field associated with a remote object is modified on a local node, a write is dispatched tothe remote node to update the field data on that node. This write can occur in the same, or a differenttransaction depending on whether writes are defined to execute asynchronously or synchronouslyfor the type.

If writes are defined to be performed asynchronously for a type it is possible that the target objectof the write on the remote node has been deleted. This error is detected by Fluency and the writeis discarded. A warning message is logged.

State conflicts

A state conflict is reported by Fluency when a write operation from a remote node detects that thedata on the local node has changed underneath it. This is possible in a distributed system becausethe object may be modified from multiple nodes in the system.

State conflicts are handled differently depending on whether writes are configured to be executedasynchronously or synchronously.

22

Chapter 2. Technical overview

Page 37: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

When writes are configured to execute asynchronously, the state conflict is not detected until thewrite is executed on the remote node. This is in a different transaction than the one that modifiedthe object data. If a state conflict is detected, the data is discarded. A warning message is logged.When writes are configured to execute synchronously state conflicts are handled transparently. Ifa state conflict is detected on the remote node an error is returned to the local node where the cacheis flushed, the transaction will be rolled back and replayed. The application is never aware that astate conflict occurred.

Extents  Extents have a cache policy of Always. When an extent is accessed, only object referenceson the local node are returned. References are in the local extent either because the object wascreated on the local node, or it was pushed to the local node because the node is part of a cachegroup and references are being pushed to the node.

Transient network errorsDistribution uses TCP as the underlying network protocol. In general, TCP provides reliable con-nectivity between machines on a network. However, it is possible that transient network errors canoccur that cause a TCP connection to drop. When a TCP connection is dropped, requests and re-sponses between nodes participating in a distributed transaction are not received. This error conditionis detected and handled by the distributed transaction protocol.

Transient connectivity failures are caused by:

• A non-response keep alive timeout occurring (See the section called “Detecting failednodes” on page 30).

• TCP retry timers expiring.

• Lost routes to remote machines.

These errors are usually caused by network cables being disconnected, router crashes, or machineinterfaces being disabled.

As discussed in the section called “Local and distributed transactions” on page 9, all distributedtransactions have a transaction initiator that acts as the transaction coordinator. The transactioninitiator can detect network failures when sending a request, or reading a response from a remotenode. When the transaction initiator detects the network failure, the transaction is rolled back.Other nodes in a distributed transaction can also detect network failures. When this happens, rollbackis returned to the transaction initiator, and again the transaction initiator rolls back the transaction.This is shown in Figure 2.8.

23

Distributed computing

Page 38: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Rol

lbac

k(G

T)

Node 1 Node 2 Node 3

GT

Rollback (GT)

Begin LT1

Rollback(LT1)

Node 4

LTn - Local Transaction

GT - Global Transaction

Begin LT2

GT

Begin LT3

GT(Rollback)

GT(Rollback)

Rollback(GT)

GTNode 4 down

Figure 2.8. Connection failure handling

When the transaction initiator performs a rollback because of a connection failure - either detectedby the initiator or another node in the distributed transaction, the rollback is sent to all known nodes.Known nodes are those that were located using location discovery (see the section called “Locationdiscovery services” on page 19). This must be done because the initiator does not know whichnodes are participating in the distributed transaction. Notice that a rollback is sent to all knownnodes in Figure 2.8. The rollback is retried until network connectivity is restored to all nodes.

24

Chapter 2. Technical overview

Page 39: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Transaction rollback is synchronized to ensure that the transaction is safely aborted on all particip-ating nodes, no matter the current node state.

Commit failure conditionsAny communication failures to remote nodes during a global transaction before a commit sequenceis started are detected, and an exception is thrown to the application (see the section called “Unavail-able node exceptions” on page 148). This allows the application to explicitly decide whether tocommit or rollback the current transaction. If the exception is not caught, the transaction will beautomatically rolled back.

Once a commit sequence starts for a global transaction the initiator always completes the commit.

Undetected communication failures to remote nodes do not impact the commit of the transaction.This failure scenario is shown in Figure 2.9. In this case, Node 2 failed and was restarted after alllocks were taken on Node 2, but before the commit sequence was started by the transaction initi-ator - Node 1. Once the commit sequence starts it continues to completion. The request to commitis ignored on Node 2 because the transaction state was lost when Node 2 restarted.

25

Distributed computing

Page 40: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Com

mit

Node 1 Node 2 Node 3

Read Lock

Read Lock Granted

Node 2 Cold Restart

Read Lock

Read Lock Granted

Commit

Commit

Begin

Commit

Ignored

Figure 2.9. Undetected communication failure

Transactions can only be committed or rolled back by the initiator of the transaction. This meansthat any global transaction executing on a remote node cannot commit or roll back until the nodeinitiating the transaction explicitly indicates that this should happen.

26

Chapter 2. Technical overview

Page 41: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

In normal operation this works fine. However, in the case where a node that initiated a globaltransactions fails, the transaction will remain pending on all remote nodes until the initiating nodeis restarted. If the initiating node never restarts, then the transaction is abandoned. Abandonedtransactions require operator interaction to determine the outcome and complete the transaction.

Node 1 Node 2

Read Lock

Read Lock Granted

Node 1 Fail

Begin

Figure 2.10. Abandoned transaction

Transactions are not abandoned if the node that initiated the transaction restarts. They are resolvedusing a transaction outcome voting algorithm.

When a node restarts, it sends a login message to all other nodes. If any of these nodes have apending global transaction that was initiated by the node that restarted, the node receiving the loginmessage queries all other nodes for the outcome of the transaction. If the transaction was committedon the other nodes, the transaction is committed on the node that received the login message. Ifthe transaction was aborted on the other nodes, the transaction is aborted on the node that receivedthe login message. If the transaction was not pending on the other nodes, the transaction is abortedon the node that received the login message.

Transaction outcome voting is shown in Figure 2.11. In Figure 2.11 the initiating node, Node 1,fails during the commit sequence after committing the transaction on Node 2, but before it iscommitted on Node 3. When Node 1 is restarted it sends a login message to Node 3 whichcauses Node 3 to perform the transaction outcome voting algorithm by querying Node 2 for theresolution of the global transaction. Since the transaction was committed on Node 2 it is committedon Node 3.

27

Distributed computing

Page 42: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Node 1 Node 2 Node 3

Write Lock

Write Lock Granted

Commit

Node 1 Cold Restart

Write Lock

Write Lock Granted

Commit

Begin

Node Login

Com

mit

Transaction Status?

Transaction Committed

Figure 2.11. Transaction outcome voting

To support transaction outcome voting each node participating in global transactions maintains ahistory of all committed and aborted transactions for each remote node participating in the globaltransaction. The number of historical transactions to maintain is configurable and should be based

28

Chapter 2. Technical overview

Page 43: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

on the time for the longest running distributed transaction. For example, if 1000 transactions persecond are being processed from a remote node, and the longest transaction on average is ten timeslonger than the mean, the transaction history buffer should be configured for 10,000 transactions.

For each transaction from each remote node, the following is captured:

• global transaction identifier

• node login time-stamp

• transaction resolution

The size of each transaction history record is 24 bytes.

Operator control of abandoned transactions  A removenode distribution operatorcommand (see the Fluency Administration Guide for details on operator commands) is providedto manually resolve abandoned transactions. As shown in Figure 2.10 an abandoned transaction canoccur when the initiating node fails. In this case, the operator must take explicit action to resolveall of the abandoned transactions that were initiated by the failed node.

To resolve all abandoned transactions, the removenode distribution command is targetedat any node that are still active. When the command is executed against one of the active nodes, amessage is sent to all active nodes indicating that the failed node is being removed. This will causethe same transaction outcome voting described in the section called “Commit failure condi-tions” on page 25 to be initiated. When the command completes, all abandoned transactions asso-ciated with the failed node have been resolved.

The decision on whether to use the removenode distribution operator command or to justrestart the failed node depends on the operational requirements of the application.

Using the removenode distribution command while the node being removed isrunning, or while the node is being restarted, may cause inconsistent transactional out-comes. Do not run the removenode distribution command when the node beingremoved is active or being restarted.

High availabilityA high-availability (HA) node is a Fluency node that is configured for the HA service. An HA nodemay be in one of four states, as described in the following table:

Table 2.4. HA node states

DescriptionState

Node is started but HA configuration has not been loaded.Unknown

HA configuration is loaded, but HA has not been enabled.Inactive

HA is enabled and active.Active

Connectivity has been lost to the node. The Down state will only be seen for remotenodes. A local node will never see itself in the Down state.

Down

A node in an Active state can receive requests from a router (see the section called “Rout-ing” on page 38), create, modify and delete Mirrored and Replicated Managed Objects.

29

High availability

Page 44: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

A node in an Unknown state functions as a non-HA node. An Unknown state implies that the nodehas not been configured for HA. The HA router will only route to the local node. Mirrored andReplicated Managed Objects can be created, modified or deleted, but the changes are not propagatedto other nodes.

A node in an Inactive state cannot receive requests from an HA router but it can route to othernodes. This is normal operation when a node is recovering from a failure. An Inactive node cannotcreate, modify, or delete Mirrored or Replicated Managed. The Mirrored and Replicated ManagedObjects are hosted on a backup node if the backup node is Active.

When a node is restarted it is in an Inactive state. A restore node command is required to restorethe node to Active.

Detecting failed nodesFluency supports keep-alive messages between all nodes in a cluster. Keep-alive requests are usedto actively determine whether a remote node is still reachable. Keep alive messages are sent to remotenodes using the configurable keepAliveMilliseconds time interval.

Figure 2.12 shows how a node is detected as being down. Every time a request is sent to a remotenode, a check is made to determine if the nonResponseTimeoutSeconds time interval beenexceeded since the last keep-alive message was received from the remote node. If the nonRespon-seTimeoutSeconds time interval has been exceed the remote node is marked down.

The keepAliveMilliseconds configuration value must be less than the nonRespon-seTimeoutSeconds to ensure correct operation of the keep-alive mechanism.

30

Chapter 2. Technical overview

Page 45: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Node One Node TwoNode One Node Two

keep-alive

keepAliveMilliseconds

keep-alive

Requestto Node One

Reset Time Interval

Node Onemarked Down

ResetNo ResponseInterval

NoResponse

timeoutexceeded?

Reset Time Interval

nonResponseTimeoutInterval

Yes No

Figure 2.12. Keep-alive protocol

When a node is marked down because the nonResponseTimeoutSeconds interval was exceeded,the following occurs:

• all partitions that have this node configured as their primary node are made active on their con-figured backup node.

• all route requests to a partition that have this node configured as their primary node will now berouted to the configured backup node.

Mirrored and replicated managed objectsMirrored Managed Objects have a copy of the object state transparently maintained on a backupnode. Mirrored Managed Objects can only be updated on the current active node - either the primaryor the backup if the primary node is unavailable.

Replicated Managed Objects have a copy of the object state transparently maintained on a backupnode. They also have the object state copied to all Fluency nodes in the cluster. Replicated Managed

31

High availability

Page 46: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Objects can only be updated on the current active node - either the primary or the backup if theprimary node is unavailable.

Mirrored and Replicated Managed Object modifications on backup nodes use an optimized "implicitcommit" transactional protocol for performance. There are two versions of the implicit commitprotocol - synchronous and asynchronous. In general, the synchronous implicit commit protocolshould be used. However, there are cases where Mirrored and Replicated Managed Objects arebeing read on the backup node at the same time that they are being modified on the primary node.In this case, the asynchronous implicit commit protocol can be used to avoid distributed deadlocksbecause there are no transaction locks taken on the backup node in the context of the initiatingtransaction on the primary node. There is an incremental performance cost on the backup node tosupport the asynchronous implicit commit.

The synchronous implicit commit protocol is shown in Figure 2.13. This protocol sends all of theMirrored and Replicated Managed Object creates, updates, and deletes in a single request to thebackup node along with the commit, and performs the updates to the objects on the backup nodein the commit.

Com

mit

Primary Backup

Commit Complete

Updates + Commit

Begin

Commit

Update(s)

Upd

ate(

s)

Figure 2.13. Synchronous Implicit Commit Transaction Protocol

32

Chapter 2. Technical overview

Page 47: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The asynchronous implicit commit protocol is shown in Figure 2.14. This protocol sends all of theMirrored and Replicated Managed Object creates, updates, and deletes in a single request to thebackup node along with the commit, and then performs the updates to the objects in a new transactionon the backup node. The updates are just queued on the backup node in the commit.

Com

mit

Primary Backup

Commit Complete

Updates + Commit

Begin

Commit

Update(s)

QueueUpdates

Upd

ate(

s)

Figure 2.14. Asynchronous Implicit Commit Transaction Protocol

Notice that no transaction locks are taken on the backup node as Mirrored and Replicated ManagedObjects are modified on the primary node until the commit step. This is different than a normaldistributed transaction, where remote locks are taken as objects are modified. See Figure 2.2 fordetails on standard Fluency distributed transactions.

PartitionsTo balance an application workload across multiple machines, application data is organized intopartitions. Each Mirrored and Replicated Managed Object is in a single partition. When an objectis created an application assigned partition identifier for an object defines what partition containsthe object. A partition identifier consists of a group name and a number.

33

High availability

Page 48: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

A partition is identified by a name. Partition names must be globally unique on all nodes in thecluster.

A partition group is a set of partitions that all have the same group name. The range of partitionnumbers supported by a partition group is from zero to the maximum partition number defined forall partitions in the group.

Partition numbers cannot overlap for partitions in the same partition group, and the range of partitionnumbers must cover the entire range of possible partition number values from zero to the maximumpartition number. A partition identifier uniquely identifies its associated partition by a partition groupname and a partition number falling within the range of partition numbers for a specific partition.

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 30

Name: FiveGroup: BMinimum Number: 11Maximum Number: 20

Name: FourGroup: BMinimum Number: 0Maximum Number: 10

Name: SixGroup: BMinimum Number: 21Maximum Number: 30

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 30

Name: FiveGroup: BMinimum Number: 11Maximum Number: 20

Name: FourGroup: BMinimum Number: 0Maximum Number: 10

Name: SixGroup: BMinimum Number: 21Maximum Number: 30

Figure 2.15. Partitions

Figure 2.15 defines six partitions named One through Six. There are two partition groups defined- A and B. Each partition group supports a range of partition numbers from zero to 30. A partitionidentifier that has a group of A and a number of 22 maps to partition Two.

Partitions are defined using Fluency configuration. The same partition configuration must be loadedon all nodes for correct operation.

A Fluency node can support one or more partitions.

Primary/backup nodes  All partitions have a primary and a backup node defined. If the primarynode fails, the backup node takes over maintaining the object state for the primary node. When theprimary node is brought back online it is restored from the backup node. Backup nodes can alsobe taken offline and be restored from a primary node.

Partition states  Partitions can have one of the following partition states:

Table 2.5. Partition states

DescriptionState

34

Chapter 2. Technical overview

Page 49: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Partition is active on primary node.HostedOnPrimary

Partition is active on backup node.HostedOnBackup

Partition is migrating to another node.Migrating

Partition is being restored on primary. State only seen on backup node.RestoringPrimary

Partition is being restored on backup. State only seen on primary node.RestoringBackup

Partition is being restored on primary. State only seen on primary node.PrimaryBeingRestored

Partition is being restored on backup. State only seen on backup node.BackupBeingRestored

Partition not active on any node. Both primary and backup nodes for parti-tion are unavailable.

Abandoned

Synchronous and deferred updates  Mirrored and Replicated Managed Objects may becopied to remote nodes either synchronously or deferred.

Synchronous updates cause the object data to be copied to a backup, and any replicate, nodes inthe same transaction in which it is modified. The object data is copied to the backup node when thecurrent transaction commits. Multiple updates to the same object in the same transaction will resultin only a single update to the remote nodes. Synchronous copies ensure that no data is lost duringfailures at the cost of network latency in the application transaction path.

CallerTransaction

Remote Node

Begin

Commit

Update Data

Figure 2.16. Synchronous updates

Deferred updates cause the object data to be copied to a backup, and replicate, nodes based on aconfigurable time interval. Objects are copied to remote nodes in a different transaction then theone in which they were modified. Deferred updates expose the application to data loss during failures,but it removes the network latency in the application transaction path.

35

High availability

Page 50: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

CallerTransaction

Remote Node

Begin

Commit

Local Queue

Queue Data

Begin

Commit

Update Data

Figure 2.17. Deferred updates

Splitting existing partitionsPartitions can be split into one or more partitions on an active system. This provides a mechanismfor reallocating work if a single partition becomes overloaded. After a partition has been split intoone or more partitions, the new partitions can be reallocated to new machines using partition migra-tion.

Partition splitting is accomplished by updating the HA configuration with new partition definitions.

Figure 2.18 shows partition Three split into two partitions named Three and Seven. Notice that theoriginal partition range of 21 to 30 was reallocated between the new partition Three (21-25) andSeven (26-30).

36

Chapter 2. Technical overview

Page 51: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 30

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 25

Name: SevenGroup: AMinimum Number: 26Maximum Number: 30

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 30

Name: TwoGroup: AMinimum Number: 11Maximum Number: 20

Name: OneGroup: AMinimum Number: 0Maximum Number: 10

Name: ThreeGroup: AMinimum Number: 21Maximum Number: 25

Name: SevenGroup: AMinimum Number: 26Maximum Number: 30

Figure 2.18. Splitting partitions

When a partition is split into one or more partitions, no data is copied, the affected mirrored andreplicated objects are just updated to reflect their new partition. All of the updates are completed ina single transaction to ensure that the partition splitting is atomic.

Restoring a nodeWhen a node in an HA cluster needs to be brought back online following a failure or system main-tenance it must be restored. A node restore performs the following actions:

• Deletes any mirrored or replicated object data on the node being restored. This handles the casewhere the node was just taken offline did not fail.

• Copies mirrored object data to the node for all partitions hosted on the node in one or moretransactions.

• Copies all replicated object data to the node in one or more transactions.

• Updates partition and HA state.

The amount of data copied in a single transaction is controlled by the sendObjectChunkSizeconfiguration value. See the Fluency Administration Guide for details on HA configuration.

When all of the object data copies complete all partitions that have this node as a primary areatomically changed in a single distributed transaction to be active on the restored node. The node

37

High availability

Page 52: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

state is than changed to Active in the same distributed transaction as the partition updates, andnormal HA processing continues.

Migrating a partitionPartitions support migration to different primary and backup nodes without requiring systemdowntime. Partition migration is initiated by updating the Fluency HA configuration on the currentprimary node for the partition.

When the updated configuration is loaded and activated on the primary node all object data in thepartition is copied to the new primary and/or backup node(s) in one or more transactions. Theamount of data copied in a single transaction is controlled by the sendObjectChunkSize config-uration value. See the Fluency Administration Guide for details on HA configuration.

While the copy is occurring work continues to be processed on the current node(s). When the datacopy completes, the partition state is atomically updated in a single distributed transaction to indicatethat the partition is now active on the new node(s). The object data is deleted on the node(s) fromwhich the partition moved.

The partition state will change from HostedOnPrimary to Migrating when the configurationis activated on the primary node. When the migration is complete the partition state will beHostedOnPrimary again.

Once the partition migration completes, the updated HA configuration file must be loaded on allother nodes in the HA cluster.

RoutingFluency provides transparent routing of data across nodes. Routing to a specific partition or nodeis supported. When routing to a partition, the data is sent to the currently active node for the partition.This may be the primary, or the backup node, if the primary node is unavailable.

Routing transparently handles partition failover to ensure that no data is lost during partition failover.The failover processing is done in a single transaction to ensure that it is atomic. See Figure 2.19.

Primary NodeCaller'sTransaction Backup Node

Begin

Commit

Primary Node

Route.route(...)Send Data

Primary Node Down

Send Data

Figure 2.19. Partition failover handling

38

Chapter 2. Technical overview

Page 53: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Routing is used:

• to ensure that all Mirrored and Replicated Managed Object updates occur on the active node forthe object

• to send data (see note below) to a specific node that has connectivity to an external client or system

• other application specific reasons

Any Java object that is serializable can be routed using Fluency Routing.

ConfigurationFluency supports online versioning of configuration data. This allows Fluency configuration tochange without having to restart a running application. Configuration data is a Managed Object andis stored in shared memory. Applications can define their own configuration data by defining a Javaclass. Application defined configuration data is operationally managed the same way as predefinedFluency configuration data.

Figure 2.20 defines the Fluency configuration concepts.

Name

Version

Type

Notifier

Objects

Class Name

Version

Type

Notifier

Objects

1

1 1

0..*

1

1..*

1..*

0..*

Class 1..* 1

Figure 2.20. Configuration model

These concepts are defined as:

• Type - a specific category of configuration data that is loaded in a single configuration file. Aconfiguration type consists of one or more configuration classes.

• Class - a Java configuration class. This Java class defines a new configuration object. All configur-ation classes are associated with a configuration type.

39

Configuration

Page 54: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Name - a unique name per configuration type. Multiple unique names can be associated with aconfiguration type. The configuration name is the unit of versioning.

• Version - a unique configuration version per configuration name. Multiple versions can be asso-ciated with a configuration name, but only one can be active.

• Objects - zero or more configuration objects associated with a configuration version. All of theconfiguration objects are associated with one of the configuration classes associated with the relatedconfiguration type.

• Notifier - a configuration notifier that handles configuration state changes (see the section called“Configuration notifiers” on page 42).

Configuration data is loaded into Fluency using configuration files. The detailed syntax of theseconfiguration files is described in the Fluency Administration Guide. In addition to the configur-ation data for the configuration objects, the configuration files also contain:

• Type -- type of configuration data

• Name -- configuration name

• Version -- version number of configuration file

The Type, Name, and Version information in the configuration files maps directly to the configurationconcepts described above.

The Type information in a configuration file is used to locate any configuration notifiers associatedwith the configuration data. The Name and Version are used to either create or replace a configur-ation when the configuration is activated. See the section called “Configuration life cycle” on page40 for more details.

For example, this configuration file is associated with a configuration Type of distribution, ithas a Name of myconfiguration, and it is Version 1.0.

//// This file defines version 1.0 of a distribution configuration named myconfiguration//configuration "myconfiguration" version "1.0" type "distribution"{ ...};

Configuration life cycleAll configuration can go through the life cycle shown in Figure 2.21.

40

Chapter 2. Technical overview

Page 55: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Loaded

Inactive

Active

RemovedLoaded

Inactive

Active

Removed

Figure 2.21. Configuration life cycle

The possible configuration states are:

• Loaded - configuration data has been loaded into a Fluency node. This is a transient state. Theconfiguration data automatically transitions to the Inactive state once it has been successfullyloaded.

• Inactive - configuration data is loaded into a Fluency node, but it is not the active version.

• Active - the configuration version is active.

• Removed - configuration data has been removed from the Fluency node. This is a transient state.

Only one active version is allowed for each configuration name within a type. For example if thereare two versions, version 1.0 and version 2.0, of a configuration file with a name value of myconfig-uration and a type of distribution, only one can be active at a time in a Fluency node.

An audit step occurs before any configuration state changes to ensure that the configuration changedoes not cause runtime application failures. If an audit fails, the configuration state change does notoccur and the application is left in the previous known good state.

Replacing a version  When one version of a configuration type and name is active, and a newversion is activated, the old version is replaced. That is, the old version is deactivated and the new

41

Configuration

Page 56: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

version is activated as a single Fluency transaction. For example, loading and activating version 2.0to replace version 1.0 takes place as follows:

1. Configuration type distribution and name myconfiguration version 1.0 is active.

2. Configuration type distribution and name myconfiguration version 2.0 is loaded, passesaudit, and is activated.

3. Configuration type distribution and name myconfiguration version 1.0 is now inactive,and configuration type distribution and name myconfiguration version 2.0 is active.

Because the configuration replacement is done in a single Fluency transaction, there is no disruptionto a running application.

Deactivating a version  Deactivating a configuration version does not restore any previouslyactive version. Another version must be activated, or loaded and activated, as a separate step. (Untilthis is done, there is no active version.) Nor does deactivating a version unload it; it must be explicitlyremoved to achieve this. Until removed, a deactivated version remains available to be reactivatedagain without having to reload the configuration data.

Configuration notifiersApplications may install configuration notifiers to respond to configuration events that are raisedas the configuration transitions through its life cycle. See the section called “Notifiers” on page 185for details on how configuration notifiers are installed. Configuration notifiers are associated witha configuration type. Multiple notifiers can be installed for a configuration type. If multiple configur-ation notifiers are installed, the order in which they are called is undefined.

Configuration notifiers support:

• auditing of configuration data and application state before a state change occurs

• modifying application behavior based on a configuration state change

Audit notifier methods should ensure that the configuration state transition being audited can occursuccessfully. If the state transition cannot occur successfully, either because of invalid configurationdata values or the current state of the application, the audit method reports a failure. If an audit fails,the configuration state change does not occur.

Table 2.6. State transition audits

DescriptionState Transition

Configuration load audit. This audit occurs after the configuration data is loadedinto memory.

load

Configuration activate audit. This audit method is called when there is no previousversion of the configuration data with the specified type and name active.

activate

Configuration replace audit. This audit method is called when there is a previousversion of the specified type and name active.

replace

Configuration deactivation audit.inactive

Configuration remove audit.remove

42

Chapter 2. Technical overview

Page 57: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Following a successful audit (except for load), a notifier method is called to perform applicationspecific behavior associated with the configuration state transition. The application state changemethods cannot fail - all validation should have been done by the associated audit method.

Table 2.7. State transition methods

DescriptionState

Configuration data successfully loaded.load

Configuration activation succeeded. This method is called when there is no previous versionof the configuration data with the specified type and name active.

active

Replace existing configuration data. This method is called when there is a previous versionof the specified type and name active.

replace

Configuration data successfully deactivated.inactive

Notice that there is no method associated with removing configuration data. Configuration dataremoval is handled without any application involvement, other than auditing that the configurationdata can be removed.

ComponentsA component is a JAR file that contains a property file named kabira.properties. Componentsmay optionally contain configuration files and notifiers. The configuration files and notifiers arespecified in the kabira.properties file. The order in which the configuration files are loadedand activated, and the notifiers executed, is also specified in the kabira.properties file.

When the Fluency JVM starts, all components are automatically activated in the order they arefound in the class path. All component activation completes before main is called. The activationof all components occurs in a single Fluency transaction.

43

Components

Page 58: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Start Transaction

Commit Transaction

Call main

Activate Component B

Activate Component A

start

end

Start Transaction

Commit Transaction

Call main

Activate Component B

Activate Component A

Figure 2.22. Activating Components

When the JVM exits, the components are deactivated in the reverse order in which they were activ-ated. All component deactivation occurs in a single Fluency transaction.

44

Chapter 2. Technical overview

Page 59: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Shutdown JVM

Deactivate ComponentA

Commit Transaction

Deactivate ComponentB

Start Transaction

start

end

Shutdown JVM

Deactivate ComponentA

Commit Transaction

Deactivate ComponentB

Start Transaction

Figure 2.23. Deactivating Components

The failure of any component activation during JVM startup causes the Fluency transaction to berolled back and the JVM startup to fail. The rollback of the Fluency transaction causes:

• the deactivation and unloading of any configuration files loaded and activated by previously suc-cessful component activations.

45

Components

Page 60: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Start Transaction

Rollback Transaction

JVM Startup Fails

Activate Component B

Activate Component A

start

end

Start Transaction

Rollback Transaction

JVM Startup Fails

Activate Component B

Activate Component A

Pass

Fail

Figure 2.24. Component Activation Failure

ActivationThese steps are taken to activate a component:

1. Read the kabira.properties file for the component.

2. Create an instance of each specified notifier and store the reference to prevent it from beinggarbage collected.

3. Call the pre-configuration initialization method for each notifier.

4. Load and activate each specified configuration file.

5. Call the post-configuration initialization method for each notifier.

46

Chapter 2. Technical overview

Page 61: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Read kabira.properties

Load and activateconfiguration files

Call post-configurationinitialization notifier

methods

Call pre-configurationinitialization notifier

methods

Create notifierinstances

start

end

Read kabira.properties

Load and activateconfiguration files

Call post-configurationinitialization notifier

methods

Call pre-configurationinitialization notifier

methods

Create notifierinstances

Figure 2.25. Component Activation

DeactivationThese steps are taken to deactivate a component:

1. Call the pre-configuration termination method for each notifier.

2. Deactivate and unload each configuration file in the reverse order in which they were loaded andactivate.

3. Call the post-configuration termination method for each notifier.

4. Release each notifier instance in the reverse order in which they were created.

The execution order of notifier deactivation methods and JVM shutdown hooks is un-defined.

47

Components

Page 62: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Call pre-configurationtermination notifier

methods

Release notifierinstances

Call post-configurationtermination notifier

methods

Deactivate and removeconfiguration files

start

end

Call pre-configurationtermination notifier

methods

Release notifierinstances

Call post-configurationtermination notifier

methods

Deactivate and removeconfiguration files

Figure 2.26. Component Deactivation

System ManagementFluency system management is done using any of the following:

• a web browser

• a Java Management Extensions (JMX) console

See Chapter 12 for details.

Fluency applications can extend the standard Fluency management features. Application managementfeatures are automatically visible using the standard Fluency system management tools.

An application adds system management features by implementing a Target. A Target is a groupingof common management functions. A Target has one or more Commands. Each Command providesa specific management function.

A Command can optionally return one or more rows of data. Each row of data must have the samenumber of columns. The first row returned contains the column names.

48

Chapter 2. Technical overview

Page 63: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Commands can execute synchronously or asynchronously. A synchronous Command completesits function before it returns. An asynchronous Command continues to execute after returning.

When a Command is executed by Fluency, it is in a transaction. The transaction is committed afterthe Command returns. This is true for both synchronous and asynchronous Commands. An exceptionthrown by a Command causes the transaction to be rolled back. A new transaction must be startedwhen an asynchronous command calls a method on a Target after returning from the initial invocationby Fluency.

LoggingFluency JVMs install a default log handler that routes all application logging to the Fluency eventservice (See the Fluency Administration Guide for details). This causes all application loggingto be available in the following:

• node log files

• domain event cache

• Kabira manager event monitor

• JMX notification

The Fluency log handler is installed as part of JVM initialization using a Fluency component. Whenthe component is loaded by the JVM, the log handler explicitly removes all default log handlers in-stalled by the JVM.

The Fluency log handler supports logging from inside or outside of a transaction. In both casesapplication logging is sent synchronously to the event service. When logging is done from withina transaction, the log messages are sent to the event service even if the transaction rolls-back.

SecuritySystem management commands are protected by access control rules. The access control rules areenforced before a command is executed on a target. If the principal executing the command doesnot have access to the requested command, an error is returned. The command implementation isnever executed in this case.

Access control rules are configured for each system management target independently.

49

System Management

Page 64: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

50

Page 65: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

3Developing distributed applications

This chapter describes how to develop distributed applications with Fluency. Fluency makes it easyto develop distributed applications using standard Java development tools, by transparently managingthe deployment and execution of applications on multiple nodes.

The Fluency features provided to support distributed application development are:

• deploying applications to one or more nodes in an application domain.

• partitioning applications using domain groups within an application domain.

• dynamically adding a node to an application domain.

• automatically restoring an application to a node that is restarted in an application domain.

• application output available in the development tool for all application nodes.

ArchitectureDistributed development of Fluency applications relies on a Domain Manager node to coordinatethe deployment and execution of applications to multiple nodes.

To support distributed development the Fluency Deployment Tool (See the section called “Deploy-ment tool” on page 221) is configured to connect to a Domain Manager node. The Domain Managernode coordinates all communication to the application nodes.

51

Page 66: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Node A

DomainManager

"MyDomain"

Node B Node C

DeploymentTool

Java ClassFiles

Node A

DomainManager

"MyDomain"

Node B Node C

DeploymentTool

Java ClassFiles

main

mainmain

main

main

domainname = MyDomain

Domain Group - MyGroup

Get Class X

Get Class Y

Get Class Z

Get Class XGet Class YGet Class Z

Figure 3.1. Distributed Development Architecture

When an application is executed the main entry point for the application is loaded and executed onall target nodes for the application. The same application is loaded on all application nodes. If theapplication requires different behavior on different nodes, application logic must provide this altern-ative behavior.

Once main is started on each application node, each node requests class files as needed based onapplication execution. This implies that different class files are executed on each node. The standardFluency class resolution rules are used to locate class files. See the section called “Class resolu-tion” on page 236 for details.

For example in Figure 3.1, Node A requests class X from the client, node B requests class Y, andnode C requests class Z.

The Domain Manager monitors the execution of the application on all nodes. The deployment toolruns until all application nodes exit. Individual nodes can exit, and new ones can join the distributedapplication while the program is being executed.

Application scopeThe application execution scope is controlled using these Deployment Tool parameters:

52

Chapter 3. Developing distributed applications

Page 67: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• domainname - execute the application main on all nodes in the domain.

• domaingroup - execute the application main on all nodes in a domain group.

• domainnode - execute the application main on a single node.

For example using Figure 3.1:

• domainname = MyDomain - executes main on Node A, Node B, and Node C.

• domaingroup = MyGroup - executes main on Node A and Node B.

• domainnode = Node C - execute mains on node C only.

The example below is run twice - once with domainname = Kabira Development and oncewith domainnode = primary. The results are shown.

Example 3.1. Distributed Development

// $Revision: 1.5 $

package com.kabira.snippets.development;

/** * Snippet to show program execution on multiple Fluency nodes * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * <li> <b>domainnode</b> = primary * </ul> */public class DistributedDevelopment{ /** * Main entry point * * @param args Not used */ public static void main(String [] args) { System.out.println("Welcome to Fluency"); }}

Here is the output using domainname = Fluency Development.

[primary] Welcome to Fluency[replica] Welcome to Fluency[backup] Welcome to FluencyINFO: Application [com.kabira.snippets.development.DistributedDevelopment0] running on node [primary] exited with status [0]INFO: Application [com.kabira.snippets.development.DistributedDevelopment0] running on node [replica] exited with status [0]INFO: Application [com.kabira.snippets.development.DistributedDevelopment0] running on node [backup] exited with status [0]INFO: Run of distributed application [com.kabira.snippets.development.DistributedDevelopment0] complete.

Here is the output using domainnode = primary.

[primary] Welcome to FluencyINFO: Application [com.kabira.snippets.development.DistributedDevelopment1] running on

53

Application scope

Page 68: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

node [primary] exited with status [0]INFO: Run of distributed application [com.kabira.snippets.development.DistributedDevelopment1] complete.

See the section called “Deployment tool example” on page 228 for details on running this examplefrom the command line.

Adding a nodeWhen a new node is joins a domain that is currently executing an application, the application is de-ployed to the new node transparently. Any application data required for that node should be eitherReplicated or Mirrored Managed Objects so that the data is available on the new node.

Restoring a nodeA node can remove itself from the distributed application by leaving the domain. A node can leavea domain because it is shutdown, an error condition, or it is explicitly removed from a domain. TheDeployment Tool is notified that a node left the distributed application, however, execution continues.

A node that removed itself from a distributed application can rejoin the distributed application byjoining the domain again. When the node is active in the domain again, it is treated the same as anew node being added to the domain as described in the section called “Adding a node” on page 54.

DebuggingA Java debugger can be remotely attached to any of the application nodes participating in a distributedapplication. These Deployment Tool parameters can be used to control debugging of distributedapplications:

• remotedebug - enable remote debug port on all target application nodes.

• suspend - suspend all target application nodes before executing main.

When using suspend to control execution of main on target application nodes, the debugger mustbe connected to each application node to continue application execution. If the debugger is notconnected to an application node, the application will never continue executing on that node.

A complete example of attaching to a Fluency application with a debugger from the command lineis in the section called “Debugging example” on page 228.

54

Chapter 3. Developing distributed applications

Page 69: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

4Java Virtual Machine Life Cycle

This chapter describes how to control the life cycle of a Fluency Java Virtual Machine (JVM).

Starting and StoppingWhen a Fluency JVM is first started it executes the application's main entry point passing in anyspecified application parameters. When the main method returns the JVM exits.

package programming.fluency.jvmlifecycle;

public class A { public static void main(String[] args) { // // Returning from main - causes the JVM to exit // System.out.println("returning from main"); }}

When main exits, Fluency shuts down the JVM. The node waits for a configurable ( abortTimeoutdeployment specification property) number of seconds for transactional work to complete beforeforcing down the JVM. If the node has to force down the JVM, the node must be restarted.

Generally transactional work will automatically complete, either by committing or rolling back.However, long lived transactions, or transactions blocked waiting for external resources, may exceedthe configurable abortTimeout value and cause the JVM to be forced down. The node must berestarted when this occurs. To assure that a JVM exits cleanly make sure that an application'stransactions complete within the configured abortTimeout value.

These steps are taken during JVM shutdown:

• A shutdown timer is started to wait for all transactions to complete. The duration of the shutdowntimer is 75% of the abortTimeout value.

55

Page 70: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Executes any JVM shutdown hooks.

• New transactions are blocked from starting.

• Active transactions are aborted and not replayed when they access a transactional resource (e.g.a Managed Object).

These steps are shown in Figure 4.1.

56

Chapter 4. Java Virtual Machine Life Cycle

Page 71: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Application JVM Node

Return from main

Call shutdown hooks

Start JVM shutdown

Shutdown timer started

Block new transactions

Transactions blocked

Wait Until NoActive Transactions

Begin transactionXBlocked

JVM Shutdown complete

Timer

Start shutdown timer(75% of abortTimer)

Shutdown timer started

Stop shutdown timer

Shutdown timer stopped

All transactionscomplete

Access transactionlresource XAborted

57

Starting and Stopping

Page 72: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 4.1. JVM Shutdown Sequence

There is one other timer used to ensure that a clean JVM termination occurs. This is the target JVMresolution timer. The duration of this timer is controlled by the noDestinationTimeoutSecondsconfiguration value. This timer controls how long a method call will block waiting for the targetJVM to be active. The target JVM may be on the local or a remote node. If the method cannot beexecuted within the value of noDestinationTimeoutSeconds, the current transaction isaborted. During shutdown this transaction will not be restarted, ensuring that the JVM exits cleanlyin this case. See the Fluency Administration Guide for details on configuring the noDestina-tionTimeoutSeconds value.

Calling Runtime.getRuntime().exit() or System.exit() also causes the Fluency JVMto exit. The value passed to the exit() method in both cases is used as the return code from theJVM.

Example 4.1 on page 58 will cause the Fluency JVM exit.

Example 4.1. Calling Exit// $Revision: 1.6 $

package com.kabira.snippets.vmlifecycle;

/** * Calling exit to return a non-zero return code to deployment tool * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Exit{ /** * Main entry point * @param args Not used */ public static void main(String args []) { // // This will return a value of -1 to the deployment client // System.out.println("Calling exit with a value of -1"); Runtime.getRuntime().exit(-1); }}

## Output from IDE connection if exit is called#INFO: Application [com.kabira.snippets.vmlifecycle.Exit] running on node [primary] exited with status [-1]INFO: Run of distributed application [com.kabira.snippets.vmlifecycle.Exit] complete.FATAL: Distributed application failed on [1] nodes.INFO: Application [com.kabira.snippets.vmlifecycle.Exit] exited with status [-1].

Operator controlA Fluency JVM can also be shut down by an operator command external to the application. An ap-plication can use JVM shutdown hooks to detect the operator command and exit from main when

58

Chapter 4. Java Virtual Machine Life Cycle

Page 73: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

the command is detected. Support is provided for detecting when an operator has shutdown theJVM. Example 4.2 on page 59 shows a snippet that blocks in main until the operator shuts downthe JVM.

Example 4.2. Operator control// $Revision: 1.6 $

package com.kabira.snippets.vmlifecycle;

import com.kabira.platform.Transaction;import com.kabira.platform.swbuiltin.EngineServices;

/** * Shutting down the JVM based on an external operator command * * This snippet will block until the JVM it is executing in is * manually shutdown using the JVM administrative command. * * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Shutdown{ private static Boolean m_shouldStop = false;

/** * Main entry point * @param args Not used * @throws InterruptedException Sleep interrupted */ public static void main(String args[]) throws InterruptedException { // // Wait until operator requests JVM to exit // while (m_shouldStop == false) { System.out.println("Waiting for operator...");

Thread.sleep(5000);

new Transaction("Wait for Stop") { protected void run() { m_shouldStop = EngineServices.isStopping(); } }.execute(); }

// // Operator requested JVM to exit // System.out.println("Operator shutdown JVM"); }}

59

Starting and Stopping

Page 74: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Shutdown HooksJVM shutdown hooks are called in these cases:

• when the main method returns.

• an unhandled Java exception in the main thread.

• an operator initiated shutdown of an engine containing a JVM.

• a deployment tool development client initiates a JVM shutdown by disconnecting.

• an application calls com.kabira.platform.swbuiltin.EngineServices.stop(0).

It is legal to do transactional work in a shutdown hook. During JVM shutdown, a shutdown hookthat is not in a transaction will not prevent the JVM from shutting down cleanly if it does not completebefore other JVM shutdown tasks complete. See the section called “Starting and Stopping” on page55 for details.

See Example 4.4 on page 61 for an example of using JVM shutdown hooks.

Managing ThreadsTo cleanly shut down an application, all application created threads should exit when main returns.The following approaches are used to manage application threads to ensure a clean applicationshutdown:

1. Do not return from main until all application threads exit.

2. Use a JVM shutdown hook to determine when to exit application threads.

3. Mark all application threads as daemon threads.

Example 4.3 on page 60 shows the use of Thread.join() to block in main until the applicationthread exits.

Example 4.3. Managing Threads with Join// $Revision: 1.4 $

package com.kabira.snippets.vmlifecycle;

/** * Using join to coordinate thread termination * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Join { /** * Application thread */ static public class MyThread extends Thread { @Override

60

Chapter 4. Java Virtual Machine Life Cycle

Page 75: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

public void run() { System.out.println("hello from the thread"); } } /** * Main entry point * @param args Not used */ public static void main(String[] args) { // // Create and start a new thread // MyThread t = new MyThread();

t.run();

// // Wait for the thread to return before exiting main // try { t.join(); } catch (InterruptedException ex) { // handle interrupted exception }

// // Returning from main - causes the JVM to exit // System.out.println("returning from main"); }}

Example 4.4 on page 61 shows the use of a JVM shutdown hook to coordinate shutdown of applic-ation threads.

Example 4.4. Managing Threads with a Shutdown Hook// $Revision: 1.6 $

package com.kabira.snippets.vmlifecycle;

/** * Shutdown hook snippet. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ShutdownHook { /** * Application thread */ public static class MyThread extends Thread { volatile boolean done = false;

@Override public void run() {

61

Managing Threads

Page 76: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

while (done == false) { try { System.out.println("thread sleeping...");

Thread.sleep(4000); } catch (InterruptedException ex) { // Handle exception } } System.out.println("thread exiting"); } } /** * Shutdown hook thread */ public static class ShutdownHookThread extends Thread { ShutdownHookThread(MyThread myThread) { m_myThread = myThread; }

private MyThread m_myThread;

@Override public void run() { System.out.println("VM shutting down");

m_myThread.done = true; } } /** * Main entry point * @param args Not used */ public static void main(String[] args) { // // Create a thread // MyThread t = new MyThread();

// // Set up a shutdown hook // ShutdownHookThread s = new ShutdownHookThread(t); Runtime.getRuntime().addShutdownHook(s);

// // Start the user thread // t.start();

// // Return from main - causes the JVM to call the // installed shutdown hook and to exit the JVM // System.out.println("returning from main"); }}

62

Chapter 4. Java Virtual Machine Life Cycle

Page 77: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 4.5 on page 63 shows how a thread can be marked as a daemon thread. Daemon threadscan be used by an application if the thread termination does not need to be coordinated with theapplication being shut down.

Example 4.5. Daemon Threads// $Revision: 1.4 $

package com.kabira.snippets.vmlifecycle;

/** * Using daemon threads * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Daemon { /** * Application thread */ public static class MyThread extends Thread { @Override public void run() { try { System.out.println("thread sleeping...");

Thread.sleep(5000); } catch (InterruptedException ex) { // Handle exception } } }

/** * Main entry point * @param args Not used */ public static void main(String[] args) { // // Create a new thread // MyThread t = new MyThread();

// // Mark the thread as a daemon thread // t.setDaemon(true);

// // Start the thread // t.run();

// // Returning from main - causes the JVM to exit // System.out.println("returning from main");

63

Managing Threads

Page 78: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

}}

Unhandled ExceptionsUnhandled exceptions cause the current thread to exit. If the current thread is the thread in whichmain was executed, the JVM will exit with a non-zero exit code. See the section called “Unhandledexception handling” on page 97 for unhandled exception handling when a transaction is active.

Example 4.6 on page 64 below shows an unhandled exception in the main thread.

Example 4.6. Unhandled Exception// $Revision: 1.5 $

package com.kabira.snippets.vmlifecycle;

/** * An unhandled exception in main * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class UnhandledException{

/** * Unhandled exception */ public static class MyException extends java.lang.Error { /** * Serialization UID */ public final static long serialVersionUID = 1L; }

/** * Main entry point * @param args Not used */ public static void main(String[] args) { // // Throw an unhandled exception - non-zero exit code returned // from main // throw new MyException(); }}

When Example 4.6 on page 64 is run the following output is generated:

Example 4.7. Unhandled Exception Output[primary] Java main class com.kabira.snippets.vmlifecycle.UnhandledException.main exited with an exception.[primary] Java exception occurred: com.kabira.snippets.vmlifecycle.UnhandledException$MyException[primary] at com.kabira.snippets.vmlifecycle.UnhandledException.main(UnhandledException.java:41)

64

Chapter 4. Java Virtual Machine Life Cycle

Page 79: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:47)INFO: Application [com.kabira.snippets.vmlifecycle.UnhandledException2] running on node [primary] exited with status [-1]INFO: Run of distributed application [com.kabira.snippets.vmlifecycle.UnhandledException2] complete.

65

Unhandled Exceptions

Page 80: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

66

Page 81: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

5Transactions

Fluency optionally provides transactional behavior for any Java class. Transaction boundaries aredefined using the com.kabira.platform.Transaction class. Annotation is used to specify which classesare transactional.

Transaction boundariesTransaction boundaries are defined using the com.kabira.platform.Transaction class:

Example 5.1. Transaction classpackage com.kabira.platform;

public abstract class Transaction{ /** * Execute method return values */ public enum Result { /** Transaction committed */ COMMIT,

/** Transaction rolled back */ ROLLBACK }

/** * Invalid Transaction State Exception * * Exception thrown if execute() is called with a transaction * already active, or the transaction services are not available. */ public static class InvalidTransactionState extends java.lang.Error {

/** * Serialization version

67

Page 82: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

*/ public final static long serialVersionUID = 1L;

InvalidTransactionState(String message) { super(message); } }

/** * Rollback Exception * * Exception thrown in the run method to rollback the transaction. * * If constructed with a cause, the cause is propagated through the * execute() call via the InvocationRunException exception. */ public static class Rollback extends java.lang.Exception { /** * Serialization version */ public final static long serialVersionUID = 1L;

/** * Create a rollback exception */ public Rollback() { super(); }

/** * Create a rollback exception that is propagated to the caller. * @param cause The throwable causing the exception */ public Rollback(Throwable cause) { super(cause); }

/** * Create a rollback exception that is propagated to the caller. * @param message Message to include in exception * @param cause The throwable causing the exception */ public Rollback(String message, Throwable cause) { super(message, cause); } }

/** * InvocationRunException Exception * * Exception thrown by the execute method when the enclosed * <code>run</code> throws a Rollback exception with a cause. */ public static class InvocationRunException extends java.lang.RuntimeException { /** * Serialization version */ public final static long serialVersionUID = 1L;

/**

68

Chapter 5. Transactions

Page 83: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Create an exception that is propagated to the caller. * @param message Message to include in exception * @param cause The throwable causing the exception */ public InvocationRunException(String message, Throwable cause) { super(message, cause); } }

public Transaction() { }

/** * User defined method that is run in the context of a transaction. * * @exception com.kabira.platform.Transaction.Rollback * Thrown if the transaction should be rolled back * and all changes discarded. */ protected abstract void run() throws Transaction.Rollback;

/** * Executes the user defined method within a transaction. Any * deadlocks are transparently retried. * * @throws InvalidTransactionState * If a transaction is already active, or the transaction services * are not available. * @throws InvocationRunException * The execution of the run method resulted in an exception * that was propagated. */ public final Result execute() throws InvalidTransactionState, InvocationRunException {

... }}

An application implements the abstract run method to execute application code in a transaction. Atransaction is implicitly started when the execute method is called. The execute method callsthe application provided run method and executes the application code in a transaction. A transactionis terminated in the following ways:

• application code returns from the run method

• application throws a Transaction.Rollback exception from the run method

• a deadlock is detected (the transaction is transparently replayed)

• an unhandled exception

An application can explicitly control the outcome of a transaction by throwing the Transac-tion.Rollback exception in the run method. The Transaction.Rollback exception causesthe current transaction to rollback. Returning normally from the run method causes the transactionto commit.

The Transaction.Rollback exception has two variants - with and without a Throwable cause.

69

Transaction boundaries

Page 84: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

A Transaction.Rollback exception that does not contain a Throwable cause exception istransparently caught by the Transaction class, the transaction is rolled back, and Result.ROLL-BACK is returned from the Transaction.execute() method.

A Transaction.Rollback exception that contains a Throwable cause exception is caught bythe Transaction class, the transaction is rolled back, and the exception is rethrown by theTransaction class as an InvocationRunException. The cause of the InvocationRunExcep-tion is set to the Throwable exception that was set in the Transaction.Rollback exception.This provides a mechanism for application code to communicate the cause of a rollback to the callerof the Transaction.execute() method.

Unhandled exceptions in a run method cause the transaction to be rolled back. They are then re-thrown unmodified.

Example 5.2 on page 70 shows a simple counting program that demonstrates a field value beingrolled back.

Example 5.2. Counting example// $Revision: 1.7.2.1 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Transactional;import com.kabira.platform.annotation.TransactionalJavaObject;

/** * A simple counting program showing transactional consistency * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */@Transactionalpublic class Consistency extends Transaction{ private boolean m_commit; private int m_count = 0;

/** * Main entry point * @param args Not used */ public static void main(String [] args) { Consistency consistency = new Consistency();

consistency.m_commit = true; consistency.execute(); System.out.println(consistency.m_count);

consistency.m_commit = true; consistency.execute(); System.out.println(consistency.m_count);

consistency.m_commit = false; consistency.execute(); System.out.println(consistency.m_count); }

/**

70

Chapter 5. Transactions

Page 85: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override @TransactionalJavaObject(true) public void run() throws Transaction.Rollback { m_count += 1;

if (m_commit == true) { return; } else { throw new Transaction.Rollback(); } }}

When run, this simple program outputs (annotation added):

Example 5.3. Counting example output## Initial call to execute that commits#1

## Second call to execute that commits#2

## Third call to execute that rolls back - field restored to value before call#2

Example 5.4 on page 71 shows the use of a Throwable cause to communicate rollback informationto the caller of the Transaction.execute().

Example 5.4. Throwable cause example// $Revision: 1.5 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;

class Cause extends Throwable{ final static long serialVersionUID = 1L;

Cause(String message) { super (message); }}

/** * Rollback a transaction with a Throwable exception * <p> * <h2> Target Nodes</h2>

71

Transaction boundaries

Page 86: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <ul> * <li> <b>domainnode</b> = primary * </ul> */public class RollbackWithCause{ /** * Main entry point * @param args Not used */ public static void main(String [] args) { try { new Transaction("Rollback") { @Override protected void run() throws Rollback { Cause cause = new Cause("rollback because of error"); throw new Transaction.Rollback(cause); } }.execute(); } catch (Transaction.InvocationRunException ex) { System.out.println("INFO: " + ex.getCause().getMessage()); } }}

When run, this simple program outputs:

Example 5.5. Throwable cause example output

[primary] INFO: rollback because of error

Transactional classesA Java class is made transactional in the following ways:

• it has an @Transactional annotation

• it extends a transactional class

• it is contained by a transactional class

All fields in a transactional class are transactional unless explicitly changed using the @Isolationannotation (see the section called “@Isolation annotation” on page 75). This explicitly includes:

• primitive types

• object references

• array references

All field modifications using a reference in a transactional field are transactional, while all modifica-tions using a reference in a non-transactional field are non-transactional.

Transactional class support must be explicitly enabled using the @TransactionalJavaObjectannotation. See the section called “@TransactionalJavaObject annotation” on page 74 for details.

72

Chapter 5. Transactions

Page 87: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

@Transactional annotationThe @Transactional annotation marks a Java class as transactional. When an instance of a Javaclass with the @Transactional annotation is created, read, or modified in a Fluency transaction,it has transactional behavior. The @Transactional annotation is defined as:

Example 5.6. @Transactional annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** * Mark a class transactional */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Transactional{ /** * Define the transaction context for a class */ public static enum Context { /** a transaction is required to use type */ REQUIRED,

/** type can be used with or without a transaction */ OPTIONAL, } Context context() default Context.OPTIONAL;

/** * Define whether inherited fields are excluded from */ public static enum InheritedFields { /** * Inherited fields are not transactional */ EXCLUDE,

/** * Inherited fields are transactional */ INCLUDE, } InheritedFields inheritedFields() default InheritedFields.INCLUDE;}

Table 5.1. @Transactional annotation properties

CommentsValuesProperty

The Context property defines whethera transaction is required for instances

REQUIRED - class instances can only becreated, read, modified, or deleted in a

Context

of a class. All Fluency Managed Objectshave a REQUIRED transaction Context.

transaction. OPTIONAL - class instances canoptionally be in a transaction when instancesare created, read, modified, or deleted.

73

Transactional classes

Page 88: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The InheritedFields property controlswhether inherited fields are included

EXCLUDE - all inherited fields are not in-cluded in transactional behavior. INCLUDE

Inherited-Fields

or excluded from transactional behavi-or.

- all inherited fields are included in transac-tional behavior.

Attempting to create, read, modify, or delete an instance of a Context.REQUIRED class outsideof a transaction will cause a com.kabira.platform.NoTransactionError to be thrown bythe JVM.

All object and array references are implicitly annotated with @Transactional(Context.OP-TIONAL).

Transactionality is propagated to contained references in a transactional class. This applies to bothobject and array references.

@TransactionalJavaObject annotationThe @TransactionalJavaObject annotation indicates whether a transaction should supportJava classes that are annotated as @Transactional. The default behavior for transactions is tonot support the use of @Transactional objects. When the @TransactionalJavaObjectannotation has a value of true, the use of @Transactional objects is enabled.

This annotation has no affect on the transactional characteristics of @Managed objects.

@Transactional objects are disabled by default as they add a performance cost to transactionexecution. They should only be enabled if needed.

The @TransactionalJavaObject annotation is defined as:

Example 5.7. @TransactionalJavaObject annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** * Disable @Transactional objects */

@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public @interface TransactionalJavaObject{ /** * If true, access to transactional java objects are supported. */ boolean value();}

Table 5.2. @TransactionalJavaObject annotation properties

CommentsValuesProperty

74

Chapter 5. Transactions

Page 89: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Defines whether the transaction should support @Transactional objects.Default value is false.

true or falsevalue

Attempting to read or modify an instance of a @Transactional object with @Transactional-JavaObject set to false will cause a java.lang.IllegalAccessException to be thrownby the JVM.

The java.lang.IllegalAccessException is thrown when a field is accessed.Creating an @Transactional object will not cause the exception to be thrown.@Transactional objects created in a transaction are guaranteed to not be garbagecollected until the transaction commits or rolls back. However, no transactional locks aretaken on the create, which is why the exception is not thrown until a field is accessed.

@Isolation annotationThe @Isolation annotation controls the transaction isolation of fields. When a field with the@Isolation annotation in an instance of a Java class is read or modified in a Fluency transaction,it uses the isolation level defined by the @Isolation annotation. The @Isolation annotation isdefined as:

Example 5.8. @Isolation annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** * Define the transaction isolation of a field */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Isolation{ /** * Define isolation level */ public static enum Level { /** the field uses a serializable isolation level */ SERIALIZABLE,

/** field is non-transactional */ TRANSIENT } Level level() default Level.SERIALIZABLE;}

Table 5.3. @Isolation annotation properties

ValuesProperty

SERIALIZABLE - single write, multi-reader locking is used for the field. TRANSIENT -no transactional locking or logging is used for the field.

Level

75

Transactional classes

Page 90: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Annotation auditsWhen a class is loaded into the Fluency JVM the Class Loader performs the following annotationaudits:

• The @Transactional Context property cannot be OPTIONAL if a class extends a super-classwith an @Tranasactional Context of REQUIRED. It is illegal to relax transactional require-ments in an inheritance hierarchy.

• The @Transactional InheritedFields property cannot be EXCLUDE if the class extendsa super-class with an @Transactional annotation.

• The @Isolation annotation cannot be specified on a static field.

• The @Isolation Level property cannot be specified as TRANSIENT on a field in a ManagedObject class. See the section called “Defining a managed object” on page 103.

When an audit failure occurs the class is not loaded and an audit failure message is reported.

Example 5.9 on page 76 shows an annotation audit failure.

Example 5.9. Annotation audit failure// $Revision: 1.8 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;import com.kabira.platform.annotation.Transactional;

/** * Snippet showing auditing of invalid transaction annotations. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Audit{ /** * A managed object * <p> * Cannot relax transactional requirements. This class will fail annotation * audit and fail to load */ @Transactional(context=Transactional.Context.OPTIONAL) @Managed public static class MyObject { };

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Audit") { @Override protected void run() throws Rollback

76

Chapter 5. Transactions

Page 91: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ new MyObject(); } }.execute(); }}

When this example is run the following is output:

Example 5.10. Annotation audit failure outputINFO: Application [com.kabira.snippets.transactions.Audit] running on node [primary] exited with status [-1][primary] Class com.kabira.snippets.transactions.Audit$MyObject failed class audit; [Cannot define Transactional context to be Optional if the superclass defines it Required.]

[@Managed annotation implies transaction context is required, and cannot be overridden.][primary] Java main class com.kabira.snippets.transactions.Audit.main exited with an exception.[primary] java.lang.NoClassDefFoundError: com/kabira/snippets/transactions/Audit$MyObject[primary] at com.kabira.snippets.transactions.Audit.run(Audit.java:56)[primary] at com.kabira.platform.Transaction.execute(Transaction.java:286)[primary] at com.kabira.snippets.transactions.Audit.main(Audit.java:45)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:49)INFO: Run of distributed application [com.kabira.snippets.transactions.Audit] complete.FATAL: Distributed application failed on [1] nodes.INFO: Application [com.kabira.snippets.transactions.Audit] exited with status [-1].

Annotation examplesThe example below shows:

• use of the @Transactional annotation

• use of the @Isolation annotation

• behavior of the Transactional.InheritedFields.EXCLUDE property value

• inheriting transactional behavior through extends

• use of the @TransactionalJavaObject annotation

Example 5.11. Annotation examples// $Revision: 1.8.2.1 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Isolation;import com.kabira.platform.annotation.Transactional;import com.kabira.platform.annotation.TransactionalJavaObject;

/** * Annotation examples * <p> * <h2> Target Nodes</h2>

77

Transactional classes

Page 92: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Annotation{ /** * A POJO object */ public static class POJO { String s; }

/** * POJO child * <p> * This class must execute in a transaction */ @Transactional( context=Transactional.Context.REQUIRED, inheritedFields=Transactional.InheritedFields.EXCLUDE) public static class POJOChild extends POJO { String t;

@Isolation(level=Isolation.Level.TRANSIENT) String u; }

/** * A grand child of a POJO object * <p> * This class is transactional because it extends POJOChild */ public static class POJOGrandChild extends POJOChild { String v; }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Transactional POJO") { @Override @TransactionalJavaObject(true) protected void run() throws Rollback { POJOGrandChild grandChild = new POJOGrandChild();

// // This is not transactional since inheritedFields // property is EXCLUDE // grandChild.s = "s value";

// // This is transactional // grandChild.t = "t value";

// // This is not transactional because of @Isolation annotation

78

Chapter 5. Transactions

Page 93: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// grandChild.u = "u value";

// // This is transactional // grandChild.v = "v value"; } }.execute(); }}

Example 5.12 on page 79 shows the effect of the @TransactionalJavaObject annotation.

Example 5.12. @TransactionalJavaObject annotation example// $Revision: 1.2 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Transactional;import com.kabira.platform.annotation.TransactionalJavaObject;

/** * Class must have an active transaction context */@Transactional(context=Transactional.Context.REQUIRED)class POJO{ String value;}

@TransactionalJavaObject(true)class TransactionalPOJO extends Transaction{ @Override protected void run() throws Rollback { POJO pojo = new POJO();

// // This works because transactional POJOs are enabled // pojo.value = "works"; }}

@TransactionalJavaObject(false)class DisableTransactionalPOJO extends Transaction{ @Override protected void run() throws Rollback { POJO pojo = new POJO();

// // This will throw a java.lang.IllegalAccessException // exception because POJO requires a transaction and // transactional POJOs are disabled // pojo.value = "boom"; }}

/**

79

Transactional classes

Page 94: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Disabling transactional POJO example * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class TransactionDisabled{ /** * Main entry point * @param args Not used */ public static void main(String [] args) { new TransactionalPOJO().execute(); new DisableTransactionalPOJO().execute(); };}

Running this example generates the following output:

[primary] java.lang.IllegalAccessError: tried to modify field value in class com.kabira.snippets.transactions.POJO with field callbacks disabled[primary] at com.kabira.snippets.transactions.DisableTransactionalPOJO.run(TransactionDisabled.java:46)[primary] at com.kabira.platform.Transaction.execute(Transaction.java:310)[primary] at com.kabira.snippets.transactions.TransactionDisabled.main(TransactionDisabled.java:67)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:49)

Static fieldsStatic fields are always non-transactional.

Changing the Rollback.m_count field in the Example 5.2 on page 70 example to a static fieldwill change the sample output to (annotation added):

Example 5.13. Static fieldspublic class Rollback extends Transaction{ private boolean m_commit;

// // m_count field is now static // private static int m_count = 0;

...}

## Initial call to execute that commits#1

80

Chapter 5. Transactions

Page 95: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

## Second call to execute that commits#2

## Third call to execute that rolls back - field is not restored since# it is non-transactional#3

Transactional class examplesThe example below shows:

• Behavior of object references in fields

• Behavior of array references in fields

• Behavior of accessing references using a local variable

Example 5.14. Transactional class examples// $Revision: 1.8.2.1 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Isolation;import com.kabira.platform.annotation.Transactional;import com.kabira.platform.annotation.TransactionalJavaObject;

/** * Transactional field examples * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Transactions{ /** * Class may be executed inside or outside of a transaction */ public static class Optional { long m_long;

/** * Set field * * @param value Value to set */ public void setField(long value) { m_long = value; } };

/** * Class must have an active transaction context */

81

Transactional classes

Page 96: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

@Transactional(context=Transactional.Context.REQUIRED) public static class Required { private Optional m_v1; private long m_longs[][]; @Isolation(level=Isolation.Level.TRANSIENT) private Optional m_transientV1; private static long m_longstatic;

Required() { super(); m_v1 = new Optional(); m_longs = new long[10][30]; }

/** * Update fields */ public void update() { // // This is transactional - modifying // contents of reference using a local variable // Optional v1 = m_v1; v1.m_long = 5;

// // This is transactional - reference replaced // with a new reference // m_v1 = new Optional();

// // This is transactional - assignment through // a transactional field. // m_v1.m_long = 5;

// // This is transactional - update using method // in transaction scope // m_v1.setField(4);

// // This is transactional - array update through // a transactional field // m_longs[5][20] = 27;

// // This is non-transactional - reference replaced // with a new reference in a non-transactional field // m_transientV1 = new Optional();

// // This is non-transactional - assignment to // a non-transactional field. // m_transientV1.m_long = 8;

// // This is non-transactional - assignment to // a static field

82

Chapter 5. Transactions

Page 97: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// m_longstatic = 10; } }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Required Transaction") { @Override @TransactionalJavaObject(true) protected void run() throws Rollback { new Required().update(); } }.execute(); }}

Transaction thread of controlOnce a transaction is started all methods called from the run method are in the transaction. Forexample:

Example 5.15. Transaction thread of control// $Revision: 1.7 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;

/** * Thread of control snippet * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ThreadOfControl{ /** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Thread of Control") { @Override protected void run() throws Rollback { methodOne(); } }.execute(); }

private static void methodOne() {

83

Transaction thread of control

Page 98: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // This is executing in a transaction // methodTwo(); }

private static void methodTwo() { // // This is also executing in a transaction // // ... }}

The thread of control of a transaction can span threads, JVMs, and nodes. Executing a method on aremote object extends the transaction to the remote node transparently. Application programscannot assume that a transaction executes in a single thread.

If a new thread is created in a transaction, the new thread is not executing in a transaction when itstarts. The creation of a thread is also not transactional. Specifically if a thread is started in a trans-action and the transaction rolls back the thread is still running.

Example 5.16. Thread creation// $Revision: 1.7 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;

/** * Starting threads in a transaction * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Threads{ /** * An application thread */ public static class MyThread extends Thread { @Override public void run() { System.out.println("new thread not in a transaction"); } }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Threads") { @Override protected void run() throws Rollback { //

84

Chapter 5. Transactions

Page 99: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// Create a new daemon thread // MyThread myThread = new MyThread(); myThread.setDaemon(true);

// // The thread is started even if the transaction rolls back. // The thread run method is not in a transaction // myThread.start(); } }.execute(); }}

Locking and deadlocksTransaction locks are taken in the following cases on a transactional class:

• Managed Object creation - write lock taken

• Managed Object deletion - write lock taken

• Fields accessed - write lock taken on set, read lock taken on get

Non-managed objects do not take write locks on creation.

Read locks are promoted to write locks if object fields are first read and then modified.

Transaction locks are held until the current transaction commits or aborts.

Example 5.17. Object locking// $Revision: 1.8 $package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.annotation.Managed;

/** * Snippet showing transaction locking * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Locking extends Transaction{ /** * MyObject Managed Object */ @Managed public static class MyObject { private MyObject() { }

;

85

Locking and deadlocks

Page 100: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Create MyObject * * @param name Initialize name field */ public MyObject(String name) { this.name = name; } /** * Name */ public String name; /** * Lock field */ public boolean lock; }

/** * Transaction to create an instance of MyObject */ public static class CreateTransaction extends Transaction { private MyObject m_a;

/** * Transaction run method */ @Override protected void run() { m_a = new MyObject("existing"); } }

/** * Transaction to delete an instance of MyObject */ public static class DeleteTransaction extends Transaction { private MyObject m_a;

/** * Transaction run method */ @Override protected void run() { // // Cache a reference to the object before deleting it // MyObject myObject = m_a; String name = myObject.name;

if (Transaction.hasWriteLock(myObject) == false) { System.out.println(name + ": does not have a write lock"); }

// // Deleting an object takes a write lock // ManagedObject.delete(m_a);

if (Transaction.hasWriteLock(myObject) == true) {

86

Chapter 5. Transactions

Page 101: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

System.out.println(name + ": now has a write lock"); } } } private MyObject m_a;

/** * Main entry point * @param args Not used */ public static void main(String[] args) { Locking locking = new Locking(); CreateTransaction createTransaction = new CreateTransaction(); DeleteTransaction deleteTransaction = new DeleteTransaction();

createTransaction.execute();

locking.m_a = createTransaction.m_a; locking.execute();

deleteTransaction.m_a = createTransaction.m_a; deleteTransaction.execute(); }

/** * Transaction run method */ @Override protected void run() { MyObject a = new MyObject("created");

if (Transaction.hasWriteLock(a) == true) { System.out.println(a.name + ": has a write lock"); }

// // This object does not have a write lock because it was created // outside of this transaction. Reading the name field will // take a read lock. // if (Transaction.hasWriteLock(m_a) == false) { System.out.println(m_a.name + ": does not have a write lock"); } if (Transaction.hasReadLock(m_a) == true) { System.out.println(m_a.name + ": now has a read lock"); }

// // Take a write lock by setting the lock attribute. This // promotes the read lock taken above when name was read. // m_a.lock = true;

if (Transaction.hasWriteLock(m_a) == true) { System.out.println(m_a.name + ": now has a write lock"); } }}

When Example 5.17 on page 85 is run it generates the following output:

87

Locking and deadlocks

Page 102: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 5.18. Object locking output[primary] created: has a write lock[primary] existing: does not have a write lock[primary] existing: now has a read lock[primary] existing: now has a write lock[primary] existing: does not have a write lock[primary] existing: now has a write lock

Deadlocks are handled transparently and do not have to be explicitly handled by the application.When a deadlock occurs, the Transaction class detects the deadlock, rolls back the currenttransaction and restarts a new transaction by calling the run method again.

Explicit lockingIt is possible to explicitly transaction lock objects. Explicit transaction locking is useful to avoid lockpromotions. A lock promotion happens when an object has a read lock and then the object is modified.This is usually caused by first reading a field value and then modifying the object.

These mechanisms are available to explicitly lock objects:

• Transaction.readLockObject - explicitly read lock an object

• Transaction.writeLockObject - explicitly write lock an object

• ManagedObject.extent(..., LockMode objectLock) - explicitly lock objects duringextent iteration

• explicitly lock an object during queries

The example below show how to avoid a lock promotion.

Example 5.19. Avoiding lock promotion// $Revision: 1.6.2.1 $package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Transactional;import com.kabira.platform.annotation.TransactionalJavaObject;

/** * Explicit object locking. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class LockPromotion extends Transaction{ /** * A transactional POJO */ @Transactional public static class POJO { String input; String output; }

88

Chapter 5. Transactions

Page 103: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Control program execution */ public enum Action { /** * Promote a read lock */ PROMOTE, /** * Take a write lock - avoiding lock promotion */ WRITELOCK } private POJO m_b1; private Action m_action;

/** * Main entry point * @param args Not used */ public static void main(String[] args) { LockPromotion lockPromotion = new LockPromotion();

lockPromotion.m_b1 = new POJO();

lockPromotion.m_action = Action.PROMOTE; lockPromotion.execute();

lockPromotion.m_action = Action.WRITELOCK; lockPromotion.execute(); }

/** * Report locks held on objects * @param msg message to include in lock report */ public void reportLock(String msg) { System.out.println(msg + " B1: read lock = " + Transaction.hasReadLock(m_b1) + ", write lock = " + Transaction.hasWriteLock(m_b1)); }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override @TransactionalJavaObject(true) protected void run() throws Rollback { if (m_action == Action.PROMOTE) { reportLock("promote: enter");

// // Accessing input takes a read lock // String i = m_b1.input; reportLock("promote: read");

// // Read lock is promoted to write lock. Note this

89

Locking and deadlocks

Page 104: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// also happens when the following is executed: // // m_b1.output = m_b1.input; // m_b1.output = i; reportLock("promote: write"); } else { assert (m_action == Action.WRITELOCK);

reportLock("writelock: enter");

// // Explicitly take write lock to avoid promotion // Transaction.writeLockObject(m_b1);

// // Accessing input will already have write lock // String i = m_b1.input; reportLock("writelock: read");

// // No promotion of locks happen // m_b1.output = i; reportLock("writelock: write"); } }}

When Example 5.19 on page 88 is run it outputs the following (annotation added):

Example 5.20. Avoiding lock promotion output[primary] promote: enter B1: read lock = false, write lock = false

## Read lock is taken when field on B1 is read#[primary] promote: read B1: read lock = true, write lock = false

## Write lock is taken when field on B1 is set#[primary] promote: write B1: read lock = true, write lock = true

[primary] writelock: enter B1: read lock = false, write lock = false

## Explicitly write lock B1 causes both the read and write lock# to be taken on B1#[primary] writelock: read B1: read lock = true, write lock = true[primary] writelock: write B1: read lock = true, write lock = true

Interaction with Java monitorsJava monitors are integrated with Fluency transactions to ensure that they do not deadlock withtransaction locks. Figure 5.1 shows an undetected deadlock between a Java monitor and a transactionlock. These undetected deadlocks are avoiding using the mechanisms described in this section.

90

Chapter 5. Transactions

Page 105: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Thread 1 Object 1 Thread 2

Monitor Lock

Request Write Lock

Grant Write Lock

Request Write Lock

Request Monitor Lock

Wait Write Lock

Grant Monitor Lock

Wait Monitor Lock

X UndetectedDeadlock

Figure 5.1. Undetected deadlock

Monitors can still deadlock with themselves inside or outside of a transaction so standard monitordeadlock avoidance techniques should be used.

To avoid transaction and monitor deadlocks Fluency performs the following steps when acquiringtransaction locks on any object:

1. Object monitor not held on the object, perform normal transaction locking.

2. Object monitor held on the object, attempt to get transaction lock.

3. If transaction lock uncontested (can acquire without waiting), take transaction lock.

4. If transaction lock contested (a wait would be required to acquire the lock), rollback the currenttransaction

These rules are shown in the sequence diagram in Figure 5.2.

91

Interaction with Java monitors

Page 106: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Thread 1 Object 1 Thread 2

Monitor Lock

Request Write Lock

Grant Write Lock

Transaction Commit

Release Write Lock

Request Write Lock

Request Write Lock

Rollback Transaction

Release Monitor Lock

Request Write Lock

Wait Write Lock

Grant Write Lock

Transaction Commit

Release Write Lock

Grant Write Lock

92

Chapter 5. Transactions

Page 107: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 5.2. Java Monitors and transaction locking

The implications of this monitor and transaction deadlock avoidance approach is that there may befalse transaction rollbacks when monitors are used in transactions with contested transaction locks.

In general, monitors are not needed in a transactional system because transaction isolation providesthe same data integrity guarantees with much better concurrency and ease of use.

CompensationWhen a failure occurs compensation must be done to ensure that any work that was completedbefore the failure is restored to its initial state. Transactional resources are automatically restoredto their initial state by rolling back any changes when a transaction aborts. Fluency supports explicitcontrol over the resolution of a transaction with the Transaction.Rollback exception. Thismechanism can be used to recover from failures when a transaction is running.

When non-transactional resources (e.g. a file or network connection) are modified during a transactionand an error is detected, or the transaction rolls back, application code must be written to restorethe non-transactional resource to their initial state.

Fluency supports notification of transaction resolution using the com.kabira.platform.swbuilt-in.TransactionNotifier class. This class provides onRollback and onCommit methodsthat can be implemented as required to manage non-transactional resources. Multiple transactionnotifiers can be created during the same transaction. The appropriate method is called for eachnotifier instance created when the transaction completes. The order in which multiple notifiers iscalled is undefined so there should be no order assumptions in the notifiers. A notifier that is createdin a transaction can be deleted before the transaction completes. In this case, the notifier is notcalled when the transaction completes.

Example 5.21. Transaction notifiers// $Revision: 1.7 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.swbuiltin.TransactionNotifier;

/** * Snippet showing transaction notifiers * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Notifiers extends Transaction{ /** * Transaction notifier */ public static class Compensation extends TransactionNotifier { String name;

/** * Rollback notifier */ @Override

93

Compensation

Page 108: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

public void onRollback() { // // Perform application specific rollback processing // System.out.println(name + ": onRollback called");

// // Do not need to call delete. The notifier instance // deletes itself. // }

/** * Commit notifier */ @Override public void onCommit() { // // Perform application specific commit processing // System.out.println(name + ": onCommit called");

// // Do not need to call delete. The notifier instance // deletes itself. // } } Transaction.Result result;

/** * Main entry point * @param args Not used */ public static void main(String [] args) { Notifiers notifiers = new Notifiers();

notifiers.result = Result.COMMIT; notifiers.execute();

notifiers.result = Result.ROLLBACK; notifiers.execute(); }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Transaction.Rollback { op1(); op2(); op3();

if (result == Result.ROLLBACK) { throw new Transaction.Rollback(); } }

/**

94

Chapter 5. Transactions

Page 109: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Operation 1 * <p> * Create a transaction notifier to compenstate for this operation */ public void op1() { Compensation compensation = new Compensation(); compensation.name = "op1"; }

/** * Operation 2 * <p> * Create a transaction notifier to compenstate for this operation */ public void op2() { Compensation compensation = new Compensation(); compensation.name = "op2"; } /** * Operation 3 * <p> * Create a transaction notifier to compenstate for this operation */ public void op3() { Compensation compensation = new Compensation(); compensation.name = "op3"; }}

When Example 5.21 on page 93 is run it outputs (annotation added):

Example 5.22. Transaction notifier output## commit compensation methods#[primary] op1: onCommit called[primary] op2: onCommit called[primary] op3: onCommit called

## rollback compensation methods#[primary] op1: onRollback called[primary] op2: onRollback called[primary] op3: onRollback called

Transaction notifier restrictionsThe onCommit and onRollback methods in a transaction notifier cannot take any new transactionlocks. All transaction locks must be taken before the onCommit or onRollback methods arecalled. This restriction also precludes any objects with extents from being created or deleted inthese methods because an object create takes an implicit write lock.

Incorrect usage of commit and rollback notifiers can cause a Fluency node to exit with afatal error.

Objects with extents can be deleted in the onCommit or onRollback methods if they are alreadywrite-locked.

95

Compensation

Page 110: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

See the section called “Explicit locking” on page 88.

The example below shows both legal and illegal object creates in the onCommit method.

Running Example 5.23 on page 96 with the new Extent() line uncommented will causea node to exit with the following fatal exception.

Attempted to create a new programming.fluency.transactions.Extent object from within a commit trigger.

Example 5.23. Transaction notifier object locks// $Revision: 1.9 $package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;import com.kabira.platform.swbuiltin.TransactionNotifier;

/** * Snippet showing illegal transaction locking in notifiers * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class NotifierLocks{ /** * Managed objects have an extent */ @Managed public static class Extent { };

/** * Non-managed objects do not have an extent */ public static class NoExtent { };

/** * Transaction notifier that takes an illegal lock */ public static class IllegalLock extends TransactionNotifier { /** * Commit notifier */ @Override public void onCommit() { System.out.println("IllegalLock: onCommit called");

// // Attempt to create a new extented object // at commit time - this is illegal since an // implicit write lock is taken on the extent. // // Uncommenting this line will cause the Fluency node to // exit with a fatal error. //

96

Chapter 5. Transactions

Page 111: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// new Extent(); } }

/** * Transaction notifier that takes a legal lock */ public static class LegalLock extends TransactionNotifier { /** * Commit notifier */ @Override public void onCommit() { System.out.println("LegalLock: onCommit called");

// // Create a new object that does not have an extent. // This is legal because no write locks are taken. // new NoExtent(); } }

/** * Main entry point * @param args Not used */ public static void main(String[] args) { new Transaction("Locking") { @Override protected void run() throws Rollback { new LegalLock(); new IllegalLock(); } }.execute(); }}

Unhandled exception handlingUnhandled exceptions in a transaction cause the current transaction to rollback and the currentthread to exit. If the current thread is the thread in which main was executed, the JVM will exit.Any installed transaction notifiers are called before the thread exits (including the main thread).Example 5.24 on page 97 shows an unhandled exception in the main thread.

Example 5.24. Unhandled exceptions// $Revision: 1.7 $

package com.kabira.snippets.transactions;

import com.kabira.platform.Transaction;import com.kabira.platform.swbuiltin.TransactionNotifier;

/** * Snippet on unhandled exceptions * <p> * <h2> Target Nodes</h2> * <ul>

97

Unhandled exception handling

Page 112: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <li> <b>domainnode</b> = primary * </ul> */public class UnhandledExceptions{ /** * An unhandled exception */ public static class UnhandledException extends java.lang.Error { /** * Serialization UID */ public final static long serialVersionUID = 1L; }

/** * Transaction notifier */ public static class Notifier extends TransactionNotifier { /** * Rollback notifier */ @Override public void onRollback() { // // Perform application specific rollback processing // System.out.println("onRollback called"); } } /** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Unhandled Exception") { @Override protected void run() throws Rollback { // // Create a transaction notifier // new Notifier();

// // Throw an unhandled exception - transaction rolled back // throw new UnhandledException(); } }.execute(); }}

When Example 5.24 on page 97 is run it outputs (annotation added):

Example 5.25. Unhandled exception output## Application onRollback method called before JVM exits#[primary] onRollback called

98

Chapter 5. Transactions

Page 113: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[primary] Java main class com.kabira.snippets.transactions.UnhandledExceptions.main exited with an exception.[primary] com.kabira.snippets.transactions.UnhandledExceptions$UnhandledException[primary] at com.kabira.snippets.transactions.UnhandledExceptions.run(UnhandledExceptions.java:80)[primary] at com.kabira.platform.Transaction.execute(Transaction.java:286)[primary] at com.kabira.snippets.transactions.UnhandledExceptions.main(UnhandledExceptions.java:63)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:49)

Transaction required exceptionAttempting to use a class that has a @Transactional(context=Transactional.Context.RE-QUIRED) annotation outside of a transaction will cause the following exception to be thrown:

java.lang.IllegalAccessError

Example 5.26 on page 99 will cause this exception to be thrown.

Example 5.26. Required transaction exception// $Revision: 1.7 $

package com.kabira.snippets.transactions;

import com.kabira.platform.annotation.Managed;

/** * Snippet showing transaction required behavior * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class TransactionRequired{ /** * Transaction required class */ @Managed public static class Required { }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { // // Attempting to use a transactional required class // outside of a transaction // new Required(); }}

When Example 5.26 on page 99 is run it outputs (annotation added):

99

Unhandled exception handling

Page 114: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 5.27. Required Transaction Exception Output## java.lang.IllegalAccessError thrown because class Required requires a transaction#[primary] Java main class com.kabira.snippets.transactions.TransactionRequired.main exited with an exception.[primary] Java exception occurred: java.lang.IllegalAccessError: no active transaction[primary] at com.kabira.platform.ManagedObject._createSMObject(Native Method)[primary] at com.kabira.platform.ManagedObject.<init>(ManagedObject.java:112)[primary] at com.kabira.snippets.transactions.TransactionRequired$Required.<init>(TransactionRequired.java)[primary] at com.kabira.snippets.transactions.TransactionRequired.main(TransactionRequired.java:45)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:47)

JNI transactional programmingThe Java Native Interface is transactional. This means that:

• all memory allocated, read, modified, or deleted using JNI APIs is transactional - it is logged andlocked.

• transactional isolation is provided for field data.

All JNI code that accesses transactional resources must check for deadlock exceptions after eachcall and return to the caller. This is done the same way as all other exception handling in JNI.

Example 5.28. Transactional JNI programmingstatic void JNICALLJava_com_kabira_platform_someClass_someNative(JNIEnv *env, jclass){ doSomeWork(env);

// // Check for an exception - this could be a deadlock // if (env->ExceptionCheck()) { // propagate exception to caller return; }

doMoreWork(env);

if (env->ExceptionCheck()) ...}

Accessing an object that requires a transaction without an active transaction is not detected.This programming error will cause unpredictable behavior in the application.

All native resources such as file descriptors, sockets, or heap memory are not transactional.

100

Chapter 5. Transactions

Page 115: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Transaction notifiers can be used to support transaction safe management of non-transactional re-sources. The onCommit or onRollback methods can be implemented as native methods to performthis management. See the section called “Compensation” on page 93.

Transactional class considerationsThis section summarizes some high-level guidelines for using transactional classes. These are nothard and fast rules, but guidelines that should be evaluated in a specific application context.

• Avoid (or at least minimize) the use of Java monitors in transactions.

• Avoid deadlocks. When locking multiple objects always lock them in the same order. Concurrentlylocking objects in different orders can result in deadlocks. Fluency detects and handles thesedeadlocks transparently, but it is less expensive to avoid them.

• Avoid promotion deadlocks. When an object is going to be modified (written) within a transaction,take the write lock first, instead of the read lock. This avoids the possibility of promotion deadlockbetween multiple transactions. Again Fluency detects and handles these deadlocks transparently,but it is less expensive to avoid them.

• Avoid resource contention. Avoid adding single points of contention to your application. If yourapplication executes multiple threads concurrently insure that each thread uses separate resources.

• Attempt to minimize the duration of transaction locks to avoid lock contention. For example,blocking with transaction locks held waiting for data from an external source, or sleeping withtransaction locks held is generally a bad thing.

• Attempt to do all I/O outside of a transaction when the external system is not transactional. Ifthis cannot be avoided, use asynchronous I/O if available, to avoid blocking in a synchronousI/O operation with an active transaction.

101

Transactional class considerations

Page 116: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

102

Page 117: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

6Managed objects

This chapter describes how to define and use Fluency Managed Objects.

Defining a managed objectA Fluency Managed Object is defined using annotation. Mirrored and replicated objects are definedusing inheritance. The table below summarizes the behavior for each Managed Object type.

Table 6.1. Managed object behaviors

BehaviorIdentification Mechanism

Shared Memory Persistence, Distributed@Managed annotation

Shared Memory Persistence, High AvailabilityMirroring

extends com.kabira.plat-form.ha.MirroredObject

Shared Memory Persistence, High AvailabilityMirroring, Replication

extends com.kabira.platform.ha.Rep-licatedObject

Managed Objects have an @Transactional(Context=REQUIRED) transaction annotation -they can only be manipulated in a Fluency transaction. See the section called “@Transactional an-notation” on page 73 for more details on transaction annotation.

Here is an example of a Managed Object that is persisted in shared memory.

Example 6.1. Managed object// $Revision: 1.2 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.annotation.*;

/** * Defining a managed object

103

Page 118: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */@Managedpublic class Manage{ /** * Name is stored in shared memory */ public String name;}

Distribution is added to the above object using annotation. See Chapter 7.

Here is an example of a Mirrored Managed Object that is persisted in shared memory.

Example 6.2. Mirrored managed object// $Revision: 1.5 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ha.*;

/** * Defining a mirrored object * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Mirrored extends MirroredObject{ /** * Create a new object */ public Mirrored() { super ("fluency", 0); }

/** * Name is transactionally mirrored on backup node and persisted * in shared memory */ public String name;}

Here is an example of a Replicated Managed Object that is replicated to all nodes and persisted inshared memory.

Example 6.3. Replicated managed object// $Revision: 1.6 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ha.*;

/** * Defining a replicated object

104

Chapter 6. Managed objects

Page 119: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Replicated extends ReplicatedObject{ /** * Create a Replicated object */ public Replicated() { super ("fluency", 0); }

/** * Name is replicated to all configured nodes, mirrored to * a backup node and persisted in shared memory */ public String name;}

@Managed annotationThe @Managed annotation is defined as:

Example 6.4. @Managed annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** * Marks a class as being Fluency Managed - a shared memory * backed class. Any class that extends a Managed class is * also considered Managed. *<p> * ManagedObject subtypes are audited for the following restrictions: * <ul> * <li>do not implement <code>finalize</code>.</li> * <li>no static fields.</li> * <li>all member fields must be mappable to shared memory.</li> * </ul> * <p> * See the ManagedObject class for utility methods to manage * extents, cardinality, and lifecycle of Managed Objects. * * @see com.kabira.platform.ManagedObject */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Managed{ /** * Mark a class transactional. Managed classes must * be Transactional, with context = REQUIRED and * inheritedFields = INCLUDE. */ Transactional transactionality() default @Transactional( context = Transactional.Context.REQUIRED, inheritedFields = Transactional.InheritedFields.INCLUDE);}

105

Defining a managed object

Page 120: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The transactionality property cannot be changed.

Supported field and array typesThe supported types for fields and array elements in Managed Objects are:

• Primitive Java types (int, long, char, etc.).

• Primitive wrapper classes (Integer, Long, Character, etc.)

• java.lang.String

• java.util.Date

• Enumerations

• Managed Objects

RestrictionsManaged Objects have the following restrictions:

• they cannot have any static fields (static final fields are allowed).

• finalize cannot be implemented.

• all fields must be a supported type.

• all array fields must be of a supported type.

• @Managed cannot be specified on interfaces.

• @Managed cannot be used on classes that extend Enum or Throwable.

• @Managed cannot be combined with @Transactional.

• A @Managed class can be defined as an inner class only if it is marked static. The followingclass is legal:

class Outer { @Managed public static class Inner {...}}

• the size of a string field is limited by the maximum supported shared memory allocation size.This size may be found by running the following console command and looking in the Largestsupport allocation size line of the output.

106

Chapter 6. Managed objects

Page 121: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 6.1. Manager login screen

• the number of elements in an array field of primitive types is limited by the maximum supportedshared memory allocation size divided by the number of bytes in the primitive type.

• the number of elements in an array of strings field is limited by the maximum supported sharedmemory allocation size divided by 32.

• the number of elements in an array of arrays field is limited by the maximum supported sharedmemory allocation size divided by 84.

• the number of elements in an array of ManagedObject field is limited by the maximum supportedshared memory allocation size divided by 24.

Distributed Managed Objects have these additional restrictions:

• method return values can only be a supported type.

• method parameters can only be a supported type.

• constructor parameters can only be a supported type.

• arrays used for method return values, method parameters, and constructor parameters can beany supported type except for Managed Objects.

Managed Object restrictions are audited when the class is loaded. If any Managed Objects in theclass fail audit a java.lang.ClassNotFoundException is thrown.

If a method does not support distribution because one of the Distributed Managed Object restrictionsare violated, the class will load. A warning event will be raised. If the method or constructor is calledon a remote object a java.lang.UnsupportedOperationException is thrown.

Managed object life cycleAll creates, reads, updates, and deletes of Managed Objects must be done in a transaction. Creatingan object in a transaction that rolls back removes the object from shared memory. Deleting an objectin a transaction that rolls back leaves the object in shared memory.

107

Managed object life cycle

Page 122: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Managed Objects are not garbage collected by the JVM. Although the proxy Java object that refer-ences the Managed Object may be garbage collected, the shared memory state of the object remains.Managed Objects must be explicitly deleted by calling the delete method.

Example 6.5. Deleting managed objects// $Revision: 1.8 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.annotation.Managed;

/** * Deleting a managed object * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Delete{ /** * A managed object */ @Managed public static class MyObject { };

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Delete Object") { @Override protected void run() throws Rollback { MyObject e = new MyObject();

// // Delete instance in shared memory // ManagedObject.delete(e); } }.execute(); }}

After the delete method is called on a Managed Object using the Java reference to invoke methodsor access a field will cause this exception to be thrown.

java.lang.NullPointerException

The ManagedObject.isEmpty() method can be used to test whether the shared memorybacking a Java reference has been deleted.

108

Chapter 6. Managed objects

Page 123: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Equals and HashcodeIf an @Managed class does not define an equals() method, one is automatically added to the classdefinition when the class is loaded. The generated equals() method will return true if two objectsreference the same shared memory object.

If an @Managed class does not define a hashCode() method, one is automatically added to theclass definition when the class is loaded. The generated hashCode() method will generate a hashvalue from the shared memory location of the object.

ExtentsManaged Objects automatically maintain an extent. The extent makes it possible to find all instancesof a Managed Object at any time. Applications should not rely on any ordering of objects in an extent.

Example 6.6. Managed object extents// $Revision: 1.9 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;

/** * Using a managed object extent * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Extent{ /** * A managed object */ @Managed public static class MyObject { MyObject (int number) { super(); this.number = number; } int number; }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Extent") { @Override protected void run() throws Rollback { int j;

109

Equals and Hashcode

Page 124: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // Create objects in shared memory // for (j = 0; j < 10; j++) { new MyObject(j); }

// // Iterate the extent deleting all of the created objects // for (MyObject myObject : ManagedObject.extent(MyObject.class)) { System.out.println(myObject.number); ManagedObject.delete(myObject); } } }.execute(); }}

Locking and isolationExtents support a transaction isolation of READ COMMITTED. This means that a write lock is nottaken on an extent when an object is created or destroyed. This does imply that two extent iterationsof the same extent in a transaction may return different results if other transactions have committedbetween the two iterations.

The specific extent isolation supported is:

• creates are always visible in the transaction in which they occur

• deletes are visible in the transaction in which they occur on objects that were created in the sametransaction

• deletes are visible after the transaction commits on objects that were created in a separate trans-action

Example 6.7 on page 110 demonstrates these rules.

Example 6.7. Extent locking// $Revision: 1.9 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Managed;

/** * Extent locking * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Locking extends Transaction{

110

Chapter 6. Managed objects

Page 125: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * A managed object */ @Managed public static class MyObject { }

/** * Control program execution */ public enum Action { /** * Create objects in a separate transaction */ CREATE, /** * Create and delete objects in the same transaction */ BOTH, /** * Delete objects in a separate transaction */ DELETE }

private Action m_action; private String m_message;

/** * Main entry point * @param args Not used */ public static void main(String [] args) { Locking locking = new Locking();

locking.m_action = Action.BOTH; locking.m_message = "Same Transaction"; locking.execute();

locking.m_action = Action.CREATE; locking.m_message = "Separate Transactions"; locking.execute();

locking.m_action = Action.DELETE; locking.m_message = "Separate Transactions"; locking.execute(); }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { int i;

if ((m_action == Action.BOTH) || (m_action == Action.CREATE)) { for (i = 0; i < 10; i++) { new MyObject(); } }

111

Extents

Page 126: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

if ((m_action == Action.BOTH) || (m_action == Action.CREATE)) { System.out.println(m_message); System.out.println(ManagedObject.cardinality(MyObject.class) + " objects in extent after create"); }

if (m_action == Action.BOTH || m_action == Action.DELETE) { for (MyObject j1 : ManagedObject.extent(MyObject.class)) { ManagedObject.delete(j1); }

System.out.println(ManagedObject.cardinality(MyObject.class) + " objects in extent after delete"); } }}

When Example 6.7 on page 110 is run it outputs (annotation added):

Example 6.8. Extent locking output## Both creates and deletes are reflected because both are done# in the same transaction#[primary] Same Transaction[primary] 10 objects in extent after create[primary] 0 objects in extent after delete

## Deletes are not reflected until the tranasction commits because# creates occurred in a separate transction#[primary] Separate Transactions[primary] 10 objects in extent after create[primary] 10 objects in extent after delete

There are two extent methods supported for Managed Objects- one that explicitly takes a trans-action lock on returned objects and one that does not take a transaction lock on returned objects.If no transaction lock is taken on objects returned from extent iteration, a transaction lock is takenwhen a field in the object is accessed or the object is explicitly locked (see the section called “Explicitlocking” on page 88).

As discussed above, there is no lock taken on an extent when objects are created or deleted. Thecombination of no extent locking, and locks optionally not being taken on objects returned fromextent iteration, may cause deleted object references being returned from an extent. This is shownin Example 6.9 on page 112.

Example 6.9. Extent object locking// $Revision: 1.9 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.annotation.Managed;import java.util.logging.Level;import java.util.logging.Logger;

112

Chapter 6. Managed objects

Page 127: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Demonstrate extent iteration with object deletion. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ObjectLocking{ /** * A managed object */ @Managed public static class MyObject { };

/** * Life cycle thread * <p> * This thread creates and deletes Managed Objects in shared memory. * Sleep to introduce some variability */ public static class LifeCycleThread extends Thread { private static final int NUMBERITERATIONS = 10; @Override public void run() { int i; for (i = 0; i < NUMBERITERATIONS; i++) { try { new LifeCycleTransaction( LifeCycleTransaction.Action.CREATE).execute(); Thread.sleep(1000); new LifeCycleTransaction( LifeCycleTransaction.Action.DELETE).execute(); } catch (InterruptedException ex) { Logger.getLogger( LifeCycleThread.class.getName()).log( Level.SEVERE, null, ex); } } } }

/** * Life cycle transaction * <p> * Transaction to create and delete Managed Objects */ public static class LifeCycleTransaction extends Transaction { private static final int COUNT = 100;

/** * Control transaction behavior */ public enum Action { /** * Create managed objects */ CREATE,

113

Extents

Page 128: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Delete managed objects */ DELETE }

LifeCycleTransaction (Action action) { m_action = action; }

private Action m_action;

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { // // Create managed Managed Objects // if (m_action == Action.CREATE) { int i;

for (i = 0; i < COUNT; i++) { new MyObject(); } } else { assert ( m_action == Action.DELETE );

// // Iterate extent - test for deleted objects, delete // ones that are not already deleted by another thread // for (MyObject k : ManagedObject.extent(MyObject.class)) { if (ManagedObject.isEmpty(k) == false) { ManagedObject.delete(k); } } } }

} private static final int NUMBERTHREADS = 15;

/** * Main entry point * @param args Not used * @throws java.lang.InterruptedException */ public static void main(String [] args) throws InterruptedException { int i; LifeCycleThread threads[] = new LifeCycleThread[NUMBERTHREADS];

for (i = 0; i < NUMBERTHREADS; i++) { threads[i] = new LifeCycleThread();

114

Chapter 6. Managed objects

Page 129: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

threads[i].start(); }

// // Wait for all of the threads to exit // for (i = 0; i < NUMBERTHREADS; i++) { threads[i].join(); } }}

TriggersTriggers are defined on Managed Objects by implementing interfaces. The interfaces used are:

• com.kabira.platform.UpdateTrigger - add an update trigger to the Managed Object.

• com.kabira.platform.DeleteTrigger - add a delete trigger to the Managed Object.

Update triggers are invoked after every field modification. The modified field data is available in theupdate trigger. Delete triggers are invoked when the Managed Object is deleted. The object is stillvalid when the delete trigger is called.

Example 6.10. Triggers// $Revision: 1.1 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.DeleteTrigger;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.UpdateTrigger;import com.kabira.platform.annotation.Managed;

/** * Unique key query * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Triggers{ /** * A managed object that implements update and delete triggers */ @Managed public static class MyObject implements DeleteTrigger, UpdateTrigger { /** * Create MyObject */ public MyObject() { }

String value;

@Override public void uponDelete()

115

Triggers

Page 130: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ System.out.println("uponDelete: Deleting object"); }

@Override public void uponUpdate() { System.out.println("uponUpdate: " + this.value); } }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Triggers") { @Override protected void run() throws Rollback { MyObject myObject = new MyObject();

myObject.value = "one"; myObject.value = "two";

ManagedObject.delete(myObject); } }.execute(); }}

When this example is run it outputs:

uponUpdate: oneuponUpdate: twouponDelete: Deleting object

Keys and QueriesKeys are defined on Managed Objects using annotations. The annotation to define a key capturesthis information:

• Name of key

• List of one or more fields making up the key

• Property indicating whether a key is unique

• Property indicating whether a key is ordered

Here is an example of defining a unique unordered key on a Managed Object.

Example 6.11. Managed Object with a Unique Key// $Revision: 1.3 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

116

Chapter 6. Managed objects

Page 131: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Defining a managed object with a single unique key. Key fields * must be declared as final. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */@Managed@Key( name = "ByName", fields = { "name" }, unique = true, ordered = false)public class Keys{

Keys(String name) { this.name = name; } final String name;}

Key fields can be inherited from parent classes. Key fields must be defined as non-static final.Any field type supported in Managed Objects can be a key field.

Once a key is defined on a Managed Object, an index is maintained in shared memory for that key.This index is used to perform queries against the Managed Object by specifying the key values thatshould be used in the query. For example queries see the section called “Queries” on page 120.

@Key and @KeyList AnnotationsTwo annotations are used to define keys:

• @Key - define a single key

• @KeyList - define multiple keys

A single key can be defined using the @KeyList annotation, but the @Key annotation is providedto support more concise single key definitions.

Here is the definition of the @Key annotation.

Example 6.12. @Key Annotation

package com.kabira.platform.annotation;

import java.lang.annotation.*;

/** This annotation defines a single key for a Managed class. */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Key{ /** The name of this key on the given type. Key names must be unique

117

Keys and Queries

Page 132: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* for a single type (including inherited keys). */ String name();

/** An ordered list of the fields that make up this key. The fields * must be defined in this class or in a superclass. */ String[] fields();

/** If true, the runtime will enforce that only one instance will contain * the key data. */ boolean unique() default true;

/** If true, the key data will be managed as an ordered set. */ boolean ordered() default false;}

Here is the definition of the @KeyList annotation.

Example 6.13. @KeyList Annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** This annotation is used to define multiple keys on a single Managed class. */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface KeyList{ Key[] keys();}

Key RestrictionsManaged Object keys have the following restrictions:

• @Key and @KeyList cannot be used on the same class.

• @KeyList must be of non-zero length (at least one @Key must be defined).

• @Key and @KeyList can only be used on a class marked @Managed or @Distributed, orextending a managed class.

• All fields defined in each @Key annotation must exist in the class, or in a superclass.

• All key fields must be declared final and non-static.

• The key name must be unique within its class and among all inherited keys.

Key restrictions are audited when the class is loaded. If any key definitions in the class fail audit, ajava.lang.ClassNotFoundException is thrown.

118

Chapter 6. Managed objects

Page 133: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Duplicate KeysIt is not possible to create multiple instances of a uniquely keyed Managed Object. Creating a secondinstance of a uniquely keyed Managed Object will cause this exception:

com.kabira.platform.ObjectNotUniqueError

When a duplicate key exception is thrown it indicates that the object was not created.

See the section called “Atomic Create or Select” on page 130 for the safe way to create uniquelykeyed objects in the Fluency multi-threaded environment.

Example 6.14 on page 119 shows the handling of a duplicate key exception.

Example 6.14. Duplicate Key Exception// $Revision: 1.5 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.ManagedObject;import com.kabira.platform.ObjectNotUniqueError;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

/** * Duplicate keys * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class DuplicateKey{ /** * A managed object with a unique key */ @Managed @Key ( name = "ByNumber", fields = { "number" }, unique = true, ordered = false ) public static class MyObject {

/** * Create MyObject * * @param number Initialize number field */ public MyObject(int number) { this.number = number; }

final int number; }

119

Keys and Queries

Page 134: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Duplicate Object") { @Override protected void run() throws Rollback { // // Create object with a key value of 1 // MyObject myObject = new MyObject(1);

// // Create another object with the same key value // try { new MyObject(1); } catch (ObjectNotUniqueError ex) { System.out.println(ex.getMessage()); }

ManagedObject.delete(myObject); } }.execute(); }}

When this example is run it outputs:

[primary] Duplicate found for key 'com.kabira.snippets.managedobjects.DuplicateKey$MyObject::ByNumber' in com.kabira.snippets.managedobjects.DuplicateKey$MyObject, instance 1247018:5286456:2001:2. Duplicate is com.kabira.snippets.managedobjects.DuplicateKey$MyObject, instance 1247018:5286456:2001:1. Key data:[primary] [[primary] [primary] number = 1[primary] ]

QueriesThe following classes provide the query interface for managed objects.

• com.kabira.platform.KeyManager<T> - Factory to create query objects.

• com.kabira.platform.KeyQuery<T> - Query object. Used to define and execute queries.

• com.kabira.platform.KeyFieldValueList - Used to define key name/value pairs.

• com.kabira.platform.KeyFieldValueRangeList - Used to define key name/value pairsthat have a range.

These classes are generally used in this order to define and execute a query.

120

Chapter 6. Managed objects

Page 135: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

1. Create a KeyManager<T> object.

2. Create a KeyQuery<T> object.

3. Create a KeyFieldValueList object.

4. Add key name/value pairs to the KeyFieldValueList object to define the query values.

5. Define the query using the KeyQuery<T> and the KeyFieldValueList objects.

6. Execute the query using the KeyQuery<T> object.

Once a query is defined, it can be used multiple times.

The sections below show common query examples.

Locking and Isolation  Indexes defined by keys support a transaction isolation of SERIALIZ-ABLE. This means that all updates to an index are transactionally isolated from all other transactions.Any modifications to an index caused by the creation or deletion of a keyed Managed Object is notvisible outside of the current transaction until it commits.

The specific isolation rules for indexes are as follows:

• Creates are always visible in the transaction in which they occur

• Deletes are always visible in the transaction in which they occur

• Creates are visible outside of the transaction in which they were executed after the transactioncommits

• Deletes are visible outside of the transaction in which they were executed after the transactioncommits

The locking of objects returned from queries is explicit. When a query is executed the specificlocking that should be applied to the objects in the query can be specified in the query API.

Unique

Example 6.15 on page 121 demonstrates how to define and use a single unique key to perform aquery.

Example 6.15. Unique Query// $Revision: 1.6 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

/** * Unique key query

121

Keys and Queries

Page 136: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class UniqueKey{ /** * A managed object with a unique key */ @Managed @Key ( name = "ByNumber", fields = { "number" }, unique = true, ordered = false ) public static class MyObject {

/** * Create MyObject * * @param number Initialize number field * @param description Initialize description field */ public MyObject(int number, String description) { this.number = number; this.description = description; }

final int number; final String description; }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Unique Key") { @Override protected void run() throws Rollback { // // Create some keyed objects // new MyObject(1, "one"); new MyObject(2, "two");

// // Create required query objects // KeyManager<MyObject> keyManager = new KeyManager<MyObject>(); KeyQuery<MyObject> keyQuery = keyManager.createKeyQuery( MyObject.class, "ByNumber"); KeyFieldValueList keyFieldValueList = new KeyFieldValueList();

// // Define the query to find object 1 // keyFieldValueList.add("number", 1);

122

Chapter 6. Managed objects

Page 137: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

keyQuery.defineQuery(keyFieldValueList);

// // Perform the query - the returned object has a write lock // MyObject myObject = keyQuery.getSingleResult(LockMode.WRITELOCK); System.out.println(myObject.description); ManagedObject.delete(myObject);

// // Redefine the query to find object 2. Clear the previous value // before reusing the keyFieldValueList // keyFieldValueList.clear(); keyFieldValueList.add("number", 2); keyQuery.defineQuery(keyFieldValueList);

// // Perform the query - the returned object has a write lock // myObject = keyQuery.getSingleResult(LockMode.WRITELOCK); System.out.println(myObject.description); ManagedObject.delete(myObject); } }.execute(); }}

When this example is run it outputs:

[primary] one[primary] two

Non-Unique

Example 6.16 on page 123 demonstrates how to define and use a single non-unique key to performa query. Non-unique keys must use a for loop to iterate over all possible instances.

Example 6.16. Non-Unique Query// $Revision: 1.7 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

/** * Non-unique key query * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class NonUniqueKey{

123

Keys and Queries

Page 138: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * A managed object with a non-unique key */ @Managed @Key ( name = "ByGroup", fields = { "group" }, unique = false, ordered = false ) public static class MyObject {

/** * A non-unique, unordered object * @param group Group key * @param description Description */ public MyObject(int group, String description) { this.group = group; this.description = description; }

final int group; final String description; }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Non-Unique Key") { @Override protected void run() throws Rollback { // // Create some keyed objects. Notice that a duplicate // key value is specified. // new MyObject(1, "first one"); new MyObject(1, "second one"); new MyObject(2, "third one");

// // Create required query objects // KeyManager<MyObject> keyManager = new KeyManager<MyObject>(); KeyQuery<MyObject> keyQuery = keyManager.createKeyQuery( MyObject.class, "ByGroup"); KeyFieldValueList keyFieldValueList = new KeyFieldValueList();

// // Define the query to find all objects with a key value of 1 // keyFieldValueList.add("group", 1); keyQuery.defineQuery(keyFieldValueList);

// // Perform the query - we need to use a for loop to iterate over // the objects. We take a write lock as we execute the query. // for (MyObject myObject : keyQuery.getResults(LockMode.WRITELOCK))

124

Chapter 6. Managed objects

Page 139: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ System.out.println(myObject.description); ManagedObject.delete(myObject); } } }.execute(); }}

When this example is run it outputs:

[primary] second one[primary] first one

Ordered

Ordered indexes allow sorting of selected objects in either ascending or descending order. Theyalso support finding the minimum and maximum values in an index. Ordered queries can be doneon unique and non-unique keys. They are also supported on multi-field keys. This allows the resultset to be selectively ordered based on a partial key values.

Example 6.17 on page 125 demonstrates how to define a multi-field unique key to perform orderedqueries.

Example 6.17. Ordered Query// $Revision: 1.8 $package com.kabira.snippets.managedobjects;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyOrderedBy;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

/** * Unique ordered key query * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Ordered{ /** * A managed object with a unique multi-part key */ @Managed @Key(name = "ByGroupDescription", fields = { "group", "description" }, unique = true, ordered = true) public static class MyObject { /**

125

Keys and Queries

Page 140: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* A non-unique ordered object * @param group Group * @param description Description */ public MyObject(int group, String description) { this.group = group; this.description = description; } final int group; final String description; }

/** * Main entry point * @param args Not used */ public static void main(String[] args) { new Transaction("Ordered Query") { @Override protected void run() throws Rollback { // // Create some keyed objects. These objects are unique because // both the group and description field are part of the key // new MyObject(1, "a"); new MyObject(1, "b"); new MyObject(1, "c"); new MyObject(2, "d"); new MyObject(2, "e"); new MyObject(2, "f"); // // Create required query objects // KeyManager<MyObject> keyManager = new KeyManager<MyObject>(); KeyQuery<MyObject> keyQuery = keyManager.createKeyQuery( MyObject.class, "ByGroupDescription"); KeyFieldValueList keyFieldValueList = new KeyFieldValueList();

// // Define the query to find all objects with a key value of 1 // Notice that no field value is specified for the description // field. This will cause all objects with a group value of // 1 to be sorted on the description field. // keyFieldValueList.add("group", 1); keyQuery.defineQuery(keyFieldValueList);

// // Get the maximum value in group 1 // System.out.println("Maximum Group 1 Value:"); MyObject mo = keyQuery.getMaximumResult(LockMode.READLOCK); System.out.println("\t" + mo.description);

// // Get the minimum value in group 1 // System.out.println("Minimum Group 1 Value:"); mo = keyQuery.getMinimumResult(LockMode.READLOCK); System.out.println("\t" + mo.description);

// // Perform an ordered descending query on group 1 taking

126

Chapter 6. Managed objects

Page 141: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// a write lock // System.out.println("Descending Group 1 Query:"); for (MyObject myObject : keyQuery.getResults( KeyOrderedBy.DESCENDING, LockMode.WRITELOCK)) { System.out.println("\t" + myObject.description); }

// // Perform an ordered ascending query on group 1 taking // a write lock // System.out.println("Ascending Group 1 Query:"); for (MyObject myObject : keyQuery.getResults( KeyOrderedBy.ASCENDING, LockMode.WRITELOCK)) { System.out.println("\t" + myObject.description); }

// // Repeat the queries for Group 2 // keyFieldValueList.clear(); keyFieldValueList.add("group", 2); keyQuery.defineQuery(keyFieldValueList);

System.out.println("Maximum Group 2 Value:"); mo = keyQuery.getMaximumResult(LockMode.READLOCK); System.out.println("\t" + mo.description);

System.out.println("Minimum Group 2 Value:"); mo = keyQuery.getMinimumResult(LockMode.READLOCK); System.out.println("\t" + mo.description);

System.out.println("Descending Group 2 Query:"); for (MyObject myObject : keyQuery.getResults( KeyOrderedBy.DESCENDING, LockMode.WRITELOCK)) { System.out.println("\t" + myObject.description); }

System.out.println("Ascending Group 2 Query:"); for (MyObject myObject : keyQuery.getResults( KeyOrderedBy.ASCENDING, LockMode.WRITELOCK)) { System.out.println("\t" + myObject.description); }

// // Remove all of the objects // for (MyObject myObject : ManagedObject.extent(MyObject.class)) { ManagedObject.delete(myObject); } } }.execute(); }}

When this example is run it outputs:

[primary] Maximum Group 1 Value:[primary] c[primary] Minimum Group 1 Value:

127

Keys and Queries

Page 142: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[primary] a[primary] Descending Group 1 Query:[primary] c[primary] b[primary] a[primary] Ascending Group 1 Query:[primary] a[primary] b[primary] c[primary] Maximum Group 2 Value:[primary] f[primary] Minimum Group 2 Value:[primary] d[primary] Descending Group 2 Query:[primary] f[primary] e[primary] d[primary] Ascending Group 2 Query:[primary] d[primary] e[primary] f

Range

The example shows how to perform range queries on an ordered index.

Example 6.18. Range Query// $Revision: 1.6 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.KeyComparisonOperator;import com.kabira.platform.KeyFieldValueRangeList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyOrderedBy;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;

/** * Range query * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Range{ /** * A managed object with a unique multi-part key */ @Managed @Key ( name = "ByNumberDescription", fields = { "number", "description" }, unique = true, ordered = true )

128

Chapter 6. Managed objects

Page 143: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

public static class MyObject {

/** * Create MyObject * * @param number Initialize number field * @param description Initialize description field */ public MyObject(int number, String description) { this.number = number; this.description = description; }

final int number; final String description; }

/** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Range Query") { @Override protected void run() throws Rollback { // // Create some keyed objects. These objects are unique because // both the number and description field are part of the key // new MyObject(1, "a"); new MyObject(1, "b"); new MyObject(1, "c"); new MyObject(2, "a"); new MyObject(2, "b"); new MyObject(3, "a"); new MyObject(4, "a"); new MyObject(5, "a");

// // Create required query objects // KeyManager<MyObject> keyManager = new KeyManager<MyObject>(); KeyQuery<MyObject> keyQuery = keyManager.createKeyQuery( MyObject.class, "ByNumberDescription"); KeyFieldValueRangeList keyFieldValueRangeList = new KeyFieldValueRangeList();

// // Define the query to find all objects with a number value < 3 // keyFieldValueRangeList.add("number", 3, KeyComparisonOperator.LT); keyQuery.defineQuery(keyFieldValueRangeList);

System.out.println("All objects with number < 3:"); for (MyObject myObject : keyQuery.getResults(LockMode.NOLOCK)) { System.out.println( "\t" + myObject.number + ":" + myObject.description); }

// // Define the query to find all objects with a number between 1 and 5,

129

Keys and Queries

Page 144: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// then sort them in descending order // keyFieldValueRangeList.clear(); keyFieldValueRangeList.add("number", 1, KeyComparisonOperator.GT); keyFieldValueRangeList.add("number", 5, KeyComparisonOperator.LT); keyQuery.defineQuery(keyFieldValueRangeList);

System.out.println("All objects > 1 and < 5 - Descending:"); for (MyObject myObject : keyQuery.getResults( KeyOrderedBy.DESCENDING, LockMode.NOLOCK)) { System.out.println( "\t" + myObject.number + ":" + myObject.description); }

for (MyObject myObject : ManagedObject.extent(MyObject.class)) { ManagedObject.delete(myObject); } } }.execute(); }}

When this example is run it outputs:

[primary] All objects with number < 3:[primary] 1:a[primary] 1:b[primary] 1:c[primary] 2:a[primary] 2:b[primary] All objects > 1 and < 5 - Descending:[primary] 4:a[primary] 3:a[primary] 2:b[primary] 2:a

Atomic Create or Select

Often an application wants to atomically select a unique object if it exists, and if it does not exist, tocreate the instance. The query interface provides a mechanism to do this using theKeyQuery<T>.getOrCreateSingleResult method. This method always returns an object tothe caller.

The KeyQuery<T>.getOrCreateSingleResult method works even when multiple threads may beselecting the same instance simultaneously. If multiple threads are attempting to perform a selectfor an object that does not exist, one of the threads will create the new instance, and all other threadswill block until the transaction in which the object was created commits. The other threads are re-leased after the transaction completes and the select will return the new instance.

The lock mode specified in the the KeyQuery<T>.getOrCreateSingleResult method is onlyused if the object already exists. It is ignored if the object was created. Newly created objects alwayshave a transactional write lock.

See the section called “Constructors” on page 133 for details on constructor execution when an objectis created by the KeyQuery<T>.getOrCreateSingleResult method.

Example 6.19 on page 131 demonstrates how to always locate a unique instance, either by selectingor instantiating the object.

130

Chapter 6. Managed objects

Page 145: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 6.19. Atomic Create of Unique Keyed Object// $Revision: 1.6 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.Managed;import com.kabira.platform.annotation.KeyField;

/** * Atomically creating a uniquely keyed object * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class AtomicCreate extends Transaction{

/** * A managed object with a unique key */ @Managed @Key(name = "ByNumber", fields = { "number" }, unique = true, ordered = false) public static class MyObject {

/** * Create MyObject and initialize description * * @param aNumber Initialize number field * @param aDescription Initialize description field */ public MyObject( @KeyField(fieldName = "number") int aNumber, @KeyField(fieldName = "description")String aDescription) { this.number = aNumber; this.description = aDescription; }

/** * Create MyObject with default description * * @param number Initialize number field */ public MyObject( @KeyField(fieldName = "number") int number) { this.number = number; this.description = "default description"; } final int number;

131

Keys and Queries

Page 146: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

final String description; }

/** * Main entry point * @param args Not used */ public static void main(String[] args) { new AtomicCreate().execute(); }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { // // Create object with a key value of 1 // MyObject myObject = new MyObject(1, "start of world");

// // Create required query objects // KeyManager<MyObject> keyManager = new KeyManager<MyObject>(); KeyQuery<MyObject> keyQuery = keyManager.createKeyQuery( MyObject.class, "ByNumber"); KeyFieldValueList keyFieldValueList = new KeyFieldValueList(); KeyFieldValueList additionalFields = new KeyFieldValueList();

// // Define the query to find object 1 // keyFieldValueList.add("number", 1); keyQuery.defineQuery(keyFieldValueList);

// // Set up additionalFields // additionalFields.add("description", "create new object");

// // Atomically select or create a new object. This will return // the original object created above since a key value of 1 is // being used. This can be seen because the value of the description // field is the value that was set when the object was created. // // This method always returns a result and never throws // an ObjectNotUniqueError exception. // myObject = keyQuery.getOrCreateSingleResult( LockMode.WRITELOCK, additionalFields); System.out.println("description: " + myObject.description); ManagedObject.delete(myObject);

// // Reset the query to use a value of 2 // keyFieldValueList.clear(); keyFieldValueList.add("number", 2); keyQuery.defineQuery(keyFieldValueList);

//

132

Chapter 6. Managed objects

Page 147: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// This will return a new object instance because no object exists // with a key value of 2. The description field is set to the value // defined in additionalFields parameter. // // The object is created using the constructor that passes // in description. // // This method always returns a result and never throws // an ObjectNotUniqueError exception. // myObject = keyQuery.getOrCreateSingleResult( LockMode.WRITELOCK, additionalFields); System.out.println("description: " + myObject.description); ManagedObject.delete(myObject);

// // Reset the query to use a value of 3 // keyFieldValueList.clear(); keyFieldValueList.add("number", 3); keyQuery.defineQuery(keyFieldValueList);

// // This will return a new object instance because no object exists // with a key value of 3. // // The object is created using the constructor without a description // parameter. // // This method always returns a result and never throws // an ObjectNotUniqueError exception. // myObject = keyQuery.getOrCreateSingleResult(LockMode.WRITELOCK, null); System.out.println("description: " + myObject.description); ManagedObject.delete(myObject); }}

When this example is run it outputs (annotation added):

## Object created with new#[primary] description: start of world

## Object created with getOrCreateSingleResult using constructor with description parameter#[primary] description: create new object

## Object created with getOrCreateSingleResult using constructor without description parameter#[primary] description: default description

Constructors

The KeyQuery<T>.getOrCreateSingleResult method may create a new object. To createthe object a constructor is called on the object being created. Keyed objects have constructors thatat a minimum take parameters to initialize the key fields. The constructor may also take additionalparameters for other application specific initialization.

133

Keys and Queries

Page 148: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The @KeyField annotation is used to map constructor parameters to object fields. The @KeyFieldannotation must be specified for all parameters in the constructor. An exception is thrown if a@KeyField annotation is missing on any constructor parameters at runtime.

Here is the definition of the @KeyField annotation:

package com.kabira.platform.annotation;

import java.lang.annotation.*;

/** This annotation describes the mapping between constructor arguments * and the key field that the argument sets. */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public @interface KeyField{ /** The field name this parameter maps to. */ String fieldName();}

See Example 6.19 on page 131 for an example of the @KeyField annotation.

If the @KeyField annotation is not specified on any of the object constructors, no con-structor is called when KeyQuery<T>.getOrCreateSingleResult creates an object.The key fields are correctly updated, but any behavior in the constructor is not executed.

Array copy-in/copy-outWhen a field in a Managed Object is accessed, transactional locking and logging occur. This is truefor primitive types, arrays, and objects.

Arrays can also be copied into a local array variable to avoid transactional locking or logging. Thiscopy occurs implicitly if an array is passed into a method for execution. Shared memory backingan array is only modified when elements in the array are modified using the object reference con-taining the array. These cases are shown in the example below.

Array copies are a useful performance optimization when a large number of elements in an arrayare being modified in a single transaction.

Example 6.20. Array copy-in/copy-out// $Revision: 1.8 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;

/** * Array copy-in/copy-out * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Array extends Transaction{ /**

134

Chapter 6. Managed objects

Page 149: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* A managed object */ @Managed public static class MyObject { int value; }

/** * A managed object containing other managed objects */ @Managed public static class MyObjectContainer { /** * Create a new object */ public MyObjectContainer() { super();

sharedMemoryArray = new int[10]; int i; for (i = 0; i < 10; i++) { sharedMemoryArray[i] = i; }

objectArray = new MyObject[2]; for (i = 0; i < 2; i++) { MyObject f2 = new MyObject(); f2.value = i; objectArray[i] = f2; } } int [] sharedMemoryArray; MyObject [] objectArray; } /** * Main entry point * @param args Not used */ public static void main(String [] args) { Array array = new Array(); array.execute(); }

/** * Transaction run method * */ @Override protected void run() { MyObjectContainer f = new MyObjectContainer();

// // Read lock f and make of copy of sharedMemoryArray in localArray // int localArray[] = f.sharedMemoryArray;

// // This does not modify shared memory // localArray[2] = 6;

135

Array copy-in/copy-out

Page 150: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

System.out.println("localArray: " + localArray[2] + " sharedMemoryArray: " + f.sharedMemoryArray[2]);

// // This modifies shared memory and takes a write lock on f // f.sharedMemoryArray[2] = 7;

System.out.println("localArray: " + localArray[2] + " sharedMemoryArray: " + f.sharedMemoryArray[2]);

// // This does not change the value of sharedMemoryArray in // shared memory // modifyIntArray(localArray);

System.out.println("localArray: " + localArray[0] + " sharedMemoryArray: " + f.sharedMemoryArray[0]);

// // This does not modify the value of sharedMemoryArray in shared // memory. It takes a read lock on f. // modifyIntArray(f.sharedMemoryArray);

System.out.println("localArray: " + localArray[0] + " sharedMemoryArray: " + f.sharedMemoryArray[0]);

// // This copies the value of localArray into shared memory // and takes a write lock on f. // f.sharedMemoryArray = localArray;

System.out.println("localArray: " + localArray[0] + " sharedMemoryArray: " + f.sharedMemoryArray[0]);

// // This copies only the object references in objectArray to a local // array // MyObject localF2Array[] = f.objectArray;

// // This updates shared memory through the object reference copied // into the local array // localF2Array[0].value = 8; System.out.println("f2.value: " + f.objectArray[0].value); }

/** * Modify the array passed as a parameter * @param arg Array to modify */ public void modifyIntArray(int [] arg) { arg[0] = 5; }}

When Example 6.20 on page 134 is run it outputs (annotation added):

136

Chapter 6. Managed objects

Page 151: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 6.21. Array copy-in/copy-out output## Modify local array with a value of 6#[primary] localArray: 6 sharedMemoryArray: 2

## Modify shared memory with a value of 7#[primary] localArray: 6 sharedMemoryArray: 7

## Modify local array with a value of 5#[primary] localArray: 5 sharedMemoryArray: 0

## Modify shared memory array passed to a method with a value of 5#[primary] localArray: 5 sharedMemoryArray: 0

## Copy local array into shared memory array#[primary] localArray: 5 sharedMemoryArray: 5

## Modify shared memory using an object reference in a local array#[primary] f2.value: 8

Reflection limitationsManaged Objects support java.lang.reflect except for modification of an array element. Arrayelement modifications are not updated in shared memory. Example 6.22 on page 137 shows thisbehavior.

Example 6.22. Reflection behavior// $Revision: 1.8 $

package com.kabira.snippets.managedobjects;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;import java.lang.reflect.Array;

/** * This snippet is used to demonstrate reflection limitations * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Reflection{ /** * A managed object */ @Managed public static class MyObject {

137

Reflection limitations

Page 152: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

MyObject() { super();

intArray = new int [10]; int i;

for (i = 0; i < 10; i++) { intArray[i] = i; } } int [] intArray; } /** * Main entry point * @param args Not used */ public static void main(String [] args) { new Transaction("Reflection") { @Override protected void run() throws Rollback { MyObject i = new MyObject();

// // Read the 5th element // System.out.println("intArray[5] == " + Array.getInt(i.intArray, 5));

// // Modify the 5th element // Array.setInt(i.intArray, 5, 0);

// // Read the 5th element - still 5 // System.out.println("intArray[5] == " + Array.getInt(i.intArray, 5)); } }.execute(); }}

When run Example 6.22 on page 137 outputs (annotation added):

Example 6.23. Reflection behavior output## Original value of 5th element of intArray#[primary] intArray[5] == 5

## 5th element still contains a value of 5 even after being set to 0 by Reflection API#[primary] intArray[5] == 5

138

Chapter 6. Managed objects

Page 153: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

7Distributed computing

This chapter describes how to add distributed computing features to your application.

Distributed objectsAll Fluency Managed Objects are distributed objects. The default behavior of Fluency distributedobjects is modified using annotations. If the default behavior does not need to be modified, there isno need to add an annotation to get distributed object behavior.

The annotations that impact the default distributed behavior are:

• @Distributed - change default caching behavior

• @CacheGroup - configure a class to be part of a cache group.

• @DirectedCreate - configure a Directed Create class.

These annotations are described in detail below.

It is also possible to override the annotation values using configuration data at runtime. This config-uration is described in the Fluency Administration document.

@Distributed annotationThe @Distributed annotation is used to override the default caching behavior for a class. The@Distributed annotation implies an @Managed annotation. It is legal, but redundant, to specifyboth the @Distributed and @Managed annotation.

The @Distributed annotation is defined as:

139

Page 154: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 7.1. Distributed annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** Mark a class as Distributed, and provide initial configuration * values for distribution type config. */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Distributed{ /** Defines the legal cache policies for distributed objects. */ public static enum CacheType { /** The cached copy is never considered valid. Every * access to this object will cause the cached data * to be refreshed. */ NEVER,

/** The cached copy is always considered valid. It is * never refreshed. */ ALWAYS,

/** The first time an object is accessed, the cache * is considered stale. After that the cached copy is * always considered valid. It is never refreshed again. */ ONCE,

/** The cached copy is considered valid for a configured * amount of time (the cache timeout). If the object is * accessed after the cache timeout has elapsed since the * last time it was read onto the node, it will be refreshed. */ TIMED };

/** The cache policy controls when cached data is considered * stale and should be read from the node on which the object * was created. Default value is CacheType.ALWAYS. * * Refreshing a stale object implicitly takes a transaction write * lock on that object. */ CacheType cacheType() default CacheType.ALWAYS;

/** Refresh time in seconds; only valid if cacheType is CacheType.TIMED. */ long cacheTimeSeconds() default 0L;

/** A value of true enables asynchronous writes. Default false. */ boolean asyncWrite() default false;

/** A value of true enables asynchronous destroys. Default false. */ boolean asyncDestroy() default false;

/** Cache groups provide support for pushing cache data * to a configured cache group by mapping the cache group to a

140

Chapter 7. Distributed computing

Page 155: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* set of network nodes. By default, the cache group is disabled. */ CacheGroup cacheGroup() default @CacheGroup( enabled = false, groupName = "", asyncCreate = false);

/** Directed create causes all object creates to be directed * to the node indicated by nodeName. By default, * directed create is disabled. */ DirectedCreate directedCreate() default @DirectedCreate( enabled = false, nodeName = "");}

The configuration attributes supported by the distribution configuration interfaces are summarizedin the tables below.

Table 7.1. @Distributed annotation properties

CommentsValuesProperty

Control cache policy of distributed object.Enumeration - NEVER, AL-WAYS, ONCE, or TIMED

cacheType

Refresh time in seconds. Only valid if cacheTypeis TIMED.

longcacheTimeSeconds

true or false. A value of true enables asyn-chronous writes.

booleanasyncWrite

true or false. A value of true enables asyn-chronous destroys.

booleanasyncDestroy

Enable distributed cache group behavior. See thesection called “@CacheGroup annota-tion” on page 141.

@CacheGroup annotationcacheGroup

Enable directed create behavior. See the sectioncalled “@DirectedCreate annotation” on page 142.

@DirectedCreate an-notation

directedCreate

@CacheGroup annotationThe @CacheGroup annotation is used to define a class to be part of a Cache Group. The@CacheGroup annotation is defined as:

Example 7.2. @CacheGroup annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** This annotation describes cache group configuration for a distributed * type that will use a cache group. */ @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface CacheGroup{ /** Must be set true to enable the cache group. Default true. */ boolean enabled() default true;

141

Distributed objects

Page 156: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** The name of the cache group with which this type is associated. */ String groupName();

/** A value of true enables asynchronous creates. Default false. */ boolean asyncCreate() default false;}

Table 7.2. @CacheGroup annotation properties

CommentsValueProperty

Cache group name in which this object participates.StringgroupName

true or false. A value of true enables asynchronous creates.booleanasyncCreate

@DirectedCreate annotationThe @DirectedCreate annotation is used to define a class to be part of a Cache Group. The@DirectedCreate annotation is defined as:

Example 7.3. @DirectedCreate annotationpackage com.kabira.platform.annotation;

import java.lang.annotation.*;

/** This annotation describes initial configuration for a distributed * type that will use directed creates. When enabled, directed create * causes all object creates to be directed to the specified node. */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface DirectedCreate{ /** Must be set true to enable directed create. Default true. */ boolean enabled() default true;

/** The node name to be used for all object creates. */ String nodeName();}

Table 7.3. @DirectedCreate Annotation Values

CommentsValueProperty

A string value containing the node name used for all object creates.StringnodeName

Distributed object life cycleDistributed objects have the same life cycle as any Managed Object. See the section called “Managedobject life cycle” on page 107 for details.

However, if an object maintains a reference to a distributed object, that object can be deleted on aremote node and the local object now has a stale reference. This stale reference is not detecteduntil a field or a method on the reference is invoked. In this case the following exception is thrown.

142

Chapter 7. Distributed computing

Page 157: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

//// Invalid distributed reference detected//java.lang.NullPointerException

Using directed createExample 7.4 on page 143 shows how to configure and create a Directed Create type. There is nodifference between creating a Directed Create type and a non-directed create type - both use newto create a new instance.

Example 7.4. Directed create// $Revision: 1.13 $

package com.kabira.snippets.distributedcomputing;

import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Distributed;import com.kabira.platform.swbuiltin.EngineServices;

/** * Directed Create distributed objects. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * </ul> */public class DirectedCreate extends Transaction { private Action m_action; private boolean m_done;

DirectedCreate() { m_done = false; }

/** * Control program execution */ enum Action { /** * Create objects */ CREATE,

/** * Wait on replica node for all creates to complete */ WAIT }

/** * Directed create object */ @Distributed( directedCreate= @com.kabira.platform.annotation.DirectedCreate(nodeName="replica"))

143

Using directed create

Page 158: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

public static class DirectedCreateObject { /** * Create a new object */ public DirectedCreateObject() { super(); createdOn = EngineServices.getNodeName(); }

/** * Node on which object was created */ public String createdOn; }

/** * Main entry point * * @param args Not used * @throws InterruptedException Thread interrupted */ public static void main(String [] args) throws InterruptedException { DirectedCreate directedCreate = new DirectedCreate();

directedCreate.m_action = Action.CREATE; directedCreate.execute();

while (directedCreate.m_done == false) { directedCreate.m_action = Action.WAIT; directedCreate.execute(); Thread.sleep(1000); } }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { String nodeName = EngineServices.getNodeName(); if (m_action == Action.CREATE) { System.out.println("Executing on: " + nodeName);

DirectedCreateObject a = new DirectedCreateObject();

System.out.println("Object was created on: " + a.createdOn); } else { assert ( m_action == Action.WAIT );

// // Only wait on replica node // if (nodeName.equals("replica") == false) { m_done = true; return; }

144

Chapter 7. Distributed computing

Page 159: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // Wait until an object is created from each node: // int cardinality = 0; for (DirectedCreateObject dc : ManagedObject.extent( DirectedCreateObject.class, LockMode.READLOCK)) { cardinality++; } m_done = (cardinality >= 3); } }}

When Example 7.4 on page 143 is run it creates instances of A on the replica node. Here is theoutput:

Example 7.5. Directed create output[replica] Executing on: replica[replica] Object was created on: replica[primary] Executing on: primary[backup] Executing on: backup[primary] Object was created on: replica[backup] Object was created on: replica

Using cache groupsExample 7.6 on page 145 shows how to configure and create an object in a Cache Group. There isno difference between creating a type in a Cache Group and a type not in a cache group - both usenew to create a new instance.

Example 7.6. Cache groups// $Revision: 1.11 $package com.kabira.snippets.distributedcomputing;

import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Distributed;import com.kabira.platform.swbuiltin.EngineServices;

/** * Snippet for distributed cache group objects * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * </ul> */public class CacheGroup extends Transaction { /** * Object that is part of a cache group */ @Distributed( cacheGroup= @com.kabira.platform.annotation.CacheGroup(groupName="fluency")) public static class CachedObject

145

Using cache groups

Page 160: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ /** * Node on which the object was created */ public String createdOn; }

/** * Control program action */ public enum Action { /** * Create cache group object on local node */ CREATE,

/** * Wait for all nodes to create objects */ WAIT,

/** * Display all objects in extent */ DISPLAY }

private Action m_action; private boolean m_done = false;

/** * Main entry point * * @param args Not used * @throws java.lang.InterruptedException */ public static void main(String [] args) throws InterruptedException { CacheGroup cacheGroup = new CacheGroup();

cacheGroup.m_action = Action.CREATE; cacheGroup.execute();

cacheGroup.m_action = Action.WAIT;

System.out.print("Waiting"); while (cacheGroup.m_done == false) { cacheGroup.execute(); System.out.print("."); Thread.sleep(1000); } System.out.println("done");

cacheGroup.m_action = Action.DISPLAY; cacheGroup.execute(); }

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback {

146

Chapter 7. Distributed computing

Page 161: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

String nodeName = EngineServices.getNodeName();

// // Create object on local node // if (m_action == Action.CREATE) { new CachedObject().createdOn = nodeName;

System.out.println("Created object on: " + nodeName); } else if (m_action == Action.WAIT) { int cardinality = 0; for (CachedObject c : ManagedObject.extent( CachedObject.class, LockMode.READLOCK)) { cardinality++; }

m_done = (cardinality >= 3); } else { assert ( m_action == Action.DISPLAY );

// // The extent contains references for remote objects // pushed to the local node // for (CachedObject cachedObject : ManagedObject.extent(CachedObject.class)) { System.out.println("Found on " + nodeName + ": " + cachedObject.createdOn);

} } }}

When Example 7.6 on page 145 is run it outputs the following (annotation added and status messagesdeleted). The actual order of the messages may differ depending on execution timing.

Example 7.7. Cache group output## A cache group distributed object was created on replica node#[replica] Created object on: replica[replica] Waiting..

## A cache group distributed object was created on backup#[backup] Created object on: backup[backup] Waiting..

## A cache group distributed object was created on primary#[primary] Created object on: primary[primary] Waiting..

## The backup node saw all three distributed objects#

147

Using cache groups

Page 162: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[backup] Found on backup: replica[backup] Found on backup: primary[backup] Found on backup: backup

## The primary node saw all three distributed objects#[primary] Found on primary: primary[primary] Found on primary: replica[primary] Found on primary: backup

## The replica node saw all three distributed objects#[replica] Found on replica: replica[replica] Found on replica: primary[replica] Found on replica: backup

Unavailable node exceptionsAttempting to access a distributed object from a remote node when the node is down will cause thisexception to be thrown:

java.lang.VirtualMachineError

A remote node is detected to not be down when the following action is attempted on a distributedreference:

• method invocation

• object deletion

• field modification

• field access when the local cache is stale

Example 7.8 on page 148 shows the behavior using a directed create type that is configured for aninvalid node name.

Example 7.8. Invalid node// $Revision: 1.11 $

package com.kabira.snippets.distributedcomputing;

import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Distributed;

/** * Snippet showing error handling for a node down condition. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class NodeDown{ /** * Directed create type configured for an invalid node

148

Chapter 7. Distributed computing

Page 163: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

*/ @Distributed( directedCreate= @com.kabira.platform.annotation.DirectedCreate(nodeName="invalid")) static public class UnavailableNode { }

/** * Main entry point * * @param args Not used */ public static void main (String [] args) { new Transaction("Node Down") { @Override protected void run() throws Rollback { // // Create an object on a node that is unavailable // new UnavailableNode(); } }.execute(); }}

When Example 7.8 on page 148 is run it outputs the following:

Example 7.9. Invalid node output[primary] Java main class com.kabira.snippets.distributedcomputing.NodeDown.main exited with an exception.[primary] Java exception occurred: java.lang.VirtualMachineError: sendTwoWay: sendRequest() to remote node invalid failed.[primary] at com.kabira.platform.ManagedObject._createSMObject(Native Method)[primary] at com.kabira.platform.ManagedObject.<init>(ManagedObject.java:112)[primary] at com.kabira.snippets.distributedcomputing.NodeDown$UnavailableNode.<init>(NodeDown.java)[primary] at com.kabira.snippets.distributedcomputing.NodeDown.run(NodeDown.java:52)[primary] at com.kabira.platform.Transaction.execute(Transaction.java:190)[primary] at com.kabira.snippets.distributedcomputing.NodeDown.main(NodeDown.java:43)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[primary] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)[primary] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)[primary] at java.lang.reflect.Method.invoke(Method.java:597)[primary] at com.kabira.platform.MainWrapper.invokeMain(MainWrapper.java:47)INFO: Application [com.kabira.snippets.distributedcomputing.NodeDown1] running on node [primary] exited with status [-1]

Locating a remote objectTo initiate distributed computing a reference to a remote object must be obtained. Fluency providesthe following mechanisms to access remote object references:

• Directed create

• Cache Groups

149

Locating a remote object

Page 164: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Remote method invocation

An external directory can also be used to store Fluency object references, but this requires 3rd-partysoftware and additional configuration complexity.

Directed create can be used to create a factory object on a remote node. This factory object canprovide a method that returns a distributed object instance from a remote node. This object instancecan then be used on the local node as required to access remote services.

Cache groups can also be used to allow each node in a Fluency cluster to publish an object that ispushed to all other nodes. These pushed object references can then be found on all nodes usingthe extent. Example 7.10 on page 150 shows how a cache group can be used to provide remote accessto all nodes in a cluster.

Example 7.10. Locating a remote object// $Revision: 1.16 $

package com.kabira.snippets.distributedcomputing;

import com.kabira.platform.LockMode;import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.Transaction.Rollback;import com.kabira.platform.annotation.Distributed;import com.kabira.platform.annotation.Managed;import com.kabira.platform.swbuiltin.EngineServices;

/** * Accessing an initial reference from a remote node. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * </ul> */public class InitialReferences extends Transaction { /** * Distributed object that accesses node name */ @Managed public static class Reference { /** * Return node name on which object was created. * @return Node name of node */ public String getNodeName() { return EngineServices.getNodeName(); } }

/** * Node */ @Distributed( cacheGroup= @com.kabira.platform.annotation.CacheGroup(groupName="fluency")) public static class Node { /**

150

Chapter 7. Distributed computing

Page 165: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Return an object created on the local node * @return Object reference */ public Reference getReference() { InitialReferences.m_count++; return new Reference(); } }

/** * Control program execution */ public enum Action { /** * Create object */ CREATE,

/** * Wait for all nodes to create objects */ WAITCREATE,

/** * Query node name */ QUERY,

/** * Wait for all nodes to complete */ WAITDONE

}

private Action m_action; private boolean m_done = false; private static int m_count = 0;

/** * Main entry point * * @param args Not used * @throws InterruptedException Interrupted sleep */ public static void main (String [] args) throws InterruptedException { InitialReferences ir = new InitialReferences();

ir.m_action = Action.CREATE; ir.execute();

System.out.println("Waiting for creates"); ir.m_action = Action.WAITCREATE; while (ir.m_done == false) { ir.execute(); Thread.sleep(1000); } System.out.println("Creates done");

ir.m_done = false; ir.m_action = Action.QUERY; ir.execute();

151

Locating a remote object

Page 166: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

System.out.println("Waiting for nodes to complete"); ir.m_action = Action.WAITDONE; while (ir.m_done == false) { ir.execute(); Thread.sleep(1000); } System.out.println("Nodes done");

}

/** * Transaction run method * * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { if (m_action == Action.CREATE) { new Node(); } else if (m_action == Action.WAITCREATE) { int cardinality = 0; for (Node n : ManagedObject.extent(Node.class, LockMode.READLOCK)) { cardinality++; } m_done = (cardinality >= 3); } else if (m_action == Action.WAITDONE) { if (InitialReferences.m_count < 3) { return; } m_done = true; }

else { assert ( m_action == Action.QUERY );

for (Node node : ManagedObject.extent(Node.class)) { // // Get the node name on which the Reference object // was created. // System.out.println("Node: " + node.getReference().getNodeName()); } } }}

When Example 7.10 on page 150 is executed it outputs the following (annotation added):

Example 7.11. Locating a remote object output[replica] Waiting for creates[replica] Creates done[replica] Node: replica[replica] Node: backup

152

Chapter 7. Distributed computing

Page 167: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[replica] Node: primary[replica] Waiting for nodes to complete[backup] Creates done[backup] Node: replica[backup] Node: backup[backup] Node: primary[backup] Waiting for nodes to complete[primary] Node: replica[primary] Node: backup[primary] Node: primary[primary] Waiting for nodes to complete[replica] Nodes done[backup] Nodes done[primary] Nodes done

Transaction NotifiersTransaction notifiers installed into a distributed transaction are executed on the node on which theywere installed. Example 7.12 on page 153 shows transaction notifiers being installed on a remotenode in the context of a distributed transaction.

Example 7.12. Distributed Transaction Notifiers// $Revision: 1.1.2.1 $

package com.kabira.snippets.distributedcomputing;

import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Distributed;import com.kabira.platform.annotation.DirectedCreate;import com.kabira.platform.swbuiltin.EngineServices;import com.kabira.platform.swbuiltin.TransactionNotifier;

/** * Transaction notifiers in a distributed transaction * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * </ul> */public class DistributedTransactions{ private static class Notifier extends TransactionNotifier { public Notifier(final String sourceNode) { super(); m_sourceNode = sourceNode; }

@Override public void onCommit() { System.out.println( "Transaction initiated from node (" + m_sourceNode + ") " + "commit notifier on node (" + EngineServices.getNodeName() +")"); }

private final String m_sourceNode; }

private static class Waiter extends Transaction

153

Transaction Notifiers

Page 168: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ @Override protected void run() throws Rollback { if (EngineServices.getNodeName().equals("replica") == false) { m_done = true; return; }

if (ManagedObject.cardinality(DirectedCreateObject.class) == 3) { m_done = true; } else { m_done = false; } }

Boolean getDone() { return m_done; }

private Boolean m_done = false; }

/** * Directed create object */ @Distributed( directedCreate= @DirectedCreate(nodeName="replica")) private static class DirectedCreateObject { @SuppressWarnings("ResultOfObjectAllocationIgnored") void createNotifier(final String sourceNode) { new Notifier(sourceNode); } }

@SuppressWarnings("SleepWhileHoldingLock") public static void main(String [] args) throws InterruptedException { // // Create a directed create object and install a transaction notifier // new Transaction() { @Override protected void run() throws Rollback { new DirectedCreateObject().createNotifier(EngineServices.getNodeName());

}

}.execute();

// // Wait for all three nodes to complete // Waiter waiter = new Waiter();

while (waiter.getDone() == false) {

154

Chapter 7. Distributed computing

Page 169: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

waiter.execute(); Thread.sleep(1000); } }}

When Example 7.12 on page 153 is executed it outputs the following:

Example 7.13. Transaction notifiers output[replica] Transaction initiated from node (replica) commit notifier on node (replica)[replica] Transaction initiated from node (backup) commit notifier on node (replica)[replica] Transaction initiated from node (primary) commit notifier on node (replica)

State conflictA state conflict is reported by Fluency when a write operation from a remote node detects that thedata on the local node has changed underneath it. This is possible in a distributed system becausean object may be modified from multiple nodes in the system. This exception is thrown when a stateconflict is detected:

com.kabira.platform.StateConflictError

This exception should never be caught by the application. It is used by Fluency to managed stateconflicts as described below.

State conflicts are handled differently depending on whether writes are configured to be executedasynchronously or synchronously.

When distributed writes (See the section called “@Distributed annotation” on page 139 above) areconfigured to execute asynchronously, the state conflict is not detected until the write is executedon the remote node. This is in a different transaction than the one that modified the object data. Ifa state conflict is detected, the update is discarded on the remote node with a log message.

When writes are configured to execute synchronously state conflicts are handled transparently byFluency. If a state conflict is detected on a remote node an error is returned to the local node wherethe cache is invalidated so that the next field access will cause the object data to be refreshed. Thetransaction is then rolled back and replayed. The application is never aware that a state conflict oc-curred.

ExtentsGlobal extents are maintained if an object type is configured in a cache group. As object instancesare pushed out to all nodes in a cache group, the extent on the node is updated to contain referencesto all instances in the distributed system.

If an object type is not configured as part of a cache group, the extent on a node only contains theinstances that have been created on that node, or pulled to the node in some other way (directedcreate, remote operation invocation, name service, factory, etc.).

GuidelinesHere are some general guidelines for distributed programming with Fluency.

155

State conflict

Page 170: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• All modifications to a distributed object should be done on one node. This reduces the chance ofstate conflicts which cause performance degradation. The best way to enforce this is to usemethods to perform field updates. The method will execute on the master node transparently.

• Eliminate distributed deadlocks from an application. Distributed deadlock detection uses a timeoutto detect a deadlock. This implies that a distributed transaction will wait the entire value of thetimeout value before a deadlock is reported. During this period of time the transaction is stalled.

• Factories or directed create should be used to create an object instance on a specific node.

• Cache Groups should be used to discover remote references for nodes in a cluster.

• Evaluate which nodes application classes must be installed on. Types configured for cache groupsrequire that the application class be installed on all nodes that participate in the cache group.Applications that use directed creates and factories do not require the application component tobe installed on all nodes in the distributed network, just the nodes on which the object will becreated.

156

Chapter 7. Distributed computing

Page 171: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

8High availability

This chapter describes how to add Mirrored and Replicated Managed Objects to your application.See the Fluency Administration Guide for details on how high availability is configured.

To integrate Mirrored and Replicated Objects into an application, the following steps must be taken:

• Configure the cluster and partitions

• Define the Mirrored and Replicated application objects

A router can also be optionally integrated into the application to support cross node routing of re-quests and responses.

Defining mirrored and replicated managedobjects

Mirrored and Replicated Managed Objects are defined by extending from the appropriate parenttype.

Example 8.1 on page 157 shows how a Mirrored Managed Object and a Replicated Managed Objectare defined and created.

Example 8.1. Defining mirrored and replicated managed objects// $Revision: 1.10 $

package com.kabira.snippets.highavailability;

import com.kabira.platform.Transaction;import com.kabira.platform.ha.MirroredObject;import com.kabira.platform.ha.ReplicatedObject;

/**

157

Page 172: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* Creating mirrored and a replicated managed object. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class HighAvailability{ /** * Mirrored Managed Object * <p> * This is a Mirrored Managed Object that will be created in * Partition group "fluency" with a partition number of 0. */ public static class Mirrored extends MirroredObject { Mirrored() { super ("fluency", 0); } }

/** * Replicated Managed Object * <p> * This is a Replicated Managed Object that will be created in * Partition group "fluency" with a partition number of 0. */ public static class Replicated extends ReplicatedObject { Replicated() { super ("fluency", 0); } }

/** * Main entry point * * @param args Not used */ public static void main (String [] args) { new Transaction("High Availability") { @Override protected void run() throws Rollback { // // Create a mirrored managed object // new Mirrored();

// // Create a replicated managed object // new Replicated(); } }.execute(); }}

158

Chapter 8. High availability

Page 173: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Object life cycleMirrored and Replicated Managed objects have the same life cycle as any Managed Object. See thesection called “Managed object life cycle” on page 107 for details.

RoutingUpdates to Mirrored or Replicated Managed Objects must occur on the current active master nodefor the object. The Route and DeliveryNotifier classes provide the mechanism to transparentlyroute data between nodes to ensure that object updates are done on the current active master fora Mirrored or Replicated Managed Object. The routing functionality can also be used by applicationsfor application-specific reasons that do not involve modification of Mirrored or Replicated ManagedObjects.

The Route class delivers application-specified data to a DeliveryNotifier by name. The nameof the DeliveryNotifier must be unique on a node. However, it does not have to be uniqueacross all nodes in the cluster. The named DeliveryNotifier that is the target of a route requestcan exist on the local or any remote node. The location of the DeliveryNotifier is transparentto the application using the Route class.

During application initialization delivery notifiers should be created on all nodes that will be thetarget of route requests.

The Route class supports:

• routing to the current active master node for a partition

• routing to a specific node

These routing services allow an application to easily return a response to a node that initiated a re-quest by sending some data to an application.

Example 8.2 on page 160 shows the use of the Route class and a DeliveryNotifier to sendsome application-specific data between two nodes. The initial routing is done by a partition identifierand the response is returned using the source node name.

Replica Node Primary Node

Route.toPartition () DeliveryNotifier.deliverToPartition ()Synchronous

Route.toNode ()DeliveryNotifier.deliverToNode ()

Synchronous

Figure 8.1. Routing example sequence diagram

159

Routing

Page 174: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 8.2. Routing example// $Revision: 1.11 $

package com.kabira.snippets.highavailability;

import java.util.logging.Level;import java.util.logging.Logger;import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.ha.DeliveryNotifier;import com.kabira.platform.ha.PartitionId;import com.kabira.platform.ha.Route;import com.kabira.platform.ha.RoutingError;import com.kabira.platform.swbuiltin.EngineServices;

/** * Routing application data to active node for a partition * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainname</b> = Kabira Development * </ul> */public class Routing{ /** * Routing notifier */ public static class Notifier extends DeliveryNotifier { Notifier(String name) { super (name); }

/** * Partition delivery notifier * * @param sourceNodeName Source node name * @param targetPartition Target partition * @param data Data from source node * @throws RoutingError Error was detected */ @Override public void deliverToPartition( String sourceNodeName, PartitionId targetPartition, Object data) throws RoutingError { String request = " Request: " + (String) data; String nodes = "Source Node: " + sourceNodeName + " Target Node: " + EngineServices.getNodeName();

System.out.println(nodes + request);

// // Return a response to the source node // Route.toNode(Routing.notifierName, sourceNodeName, "How are you?");

// // Let main know we are done // Routing.done = true; }

160

Chapter 8. High availability

Page 175: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Node delivery notifier * * @param sourceNodeName Source node name * @param data Data from source node * @throws RoutingError Error was detected */ @Override public void deliverToNode( String sourceNodeName, Object data) throws RoutingError { String response = " Response: " + (String) data; String nodes = "Source Node: " + sourceNodeName + " Target Node: " + EngineServices.getNodeName();

System.out.println(nodes + response);

// // Let main know we are done // Routing.done = true; } }

static final String notifierName = "mynotifier"; static volatile boolean done = false; private static String m_engineName; private static Notifier m_notifier;

/** * Main entry point * @param args Not used * @throws com.kabira.platform.ha.RoutingError * @throws java.lang.InterruptedException */ public static void main(String [] args) throws RoutingError, InterruptedException { Routing routing = new Routing();

// // Create routing notifier // new Transaction("Create Routing Notifier") { @Override protected void run() throws Rollback { m_notifier = new Notifier(notifierName); } }.execute();

routeRequest();

// // Wait here until done - we retry the send request // on the replica node. this handles the case where // the primary node has not created a notifier yet // while (done == false) { Thread.sleep(2000);

if (routing.m_engineName.equals("replica") == true) {

161

Routing

Page 176: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

routeRequest(); } }

// // Delete routing notifier // new Transaction("Delete Routing Notifier") { @Override protected void run() throws Rollback { ManagedObject.delete(m_notifier); m_notifier = null; } }.execute();

System.out.println(routing.m_engineName + " exiting"); }

private static void routeRequest() { new Transaction("Route Request") { @Override protected void run() throws Rollback { m_engineName = EngineServices.getNodeName();

// // If backup node we can exit immediately // if (m_engineName.equals("backup") == true) { Routing.done = true; return; }

// // Route a message only from the replica node // if (m_engineName.equals("replica") == false) { return; }

System.out.println("Routing request");

// // Route a request to the pre-configured partition // PartitionId partitionId = new PartitionId();

partitionId.group = "fluency"; partitionId.number = 0;

String request = "Hello?";

try { Route.toPartition(notifierName, partitionId, request); } catch (RoutingError ex) { Logger.getLogger( Routing.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);

162

Chapter 8. High availability

Page 177: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

} } }.execute(); }}

When Example 8.2 on page 160 is run it generates the following output (annotation added and in-formational messages removed) in Example 8.3 on page 163. The actual output may vary based onexecution timing differences.

Example 8.3. Routing example output## Request sent from replica to primary node#[replica] Routing request

## Backup main is exiting. The code executing on the backup node does not# participate in the routing example#[backup] backup exiting

## This is the replica node receiving the response from the primary. It is output# before the primary message because of the way output is received from remote nodes#[replica] Source Node: primary Target Node: replica Response: How are you?

## The replica is exiting after receiving the response from the primary node#[replica] replica exiting

## This is the primary node receiving the request from the replica#[primary] Source Node: replica Target Node: primary Request: Hello?

## The primary node is exiting after sending a response to the replica node#[primary] primary exiting

Partitioning application dataApplication data can be partitioned into one or more partitions by specifying the Partition group andnumber when a Mirrored or Replicated Managed Object is created. The com.kabira.plat-form.ha.Mirrored and com.kabira.platform.ha.ReplicatedObject classes definethese public constructors:

public ReplicateObject( java.lang.String partitionGroup, // Partition group in which to create object long partitionNumber) // Partition number to use for object

public MirroredObject( java.lang.String partitionGroup, // Partition group in which to create object long partitionNumber) // Partition number to use for object

The Partition specified when an object is created must be configured on the local node. See theFluency Administration Guide for details on configuring partitions.

163

Partitioning application data

Page 178: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The decision on which partition should be associated with a Mirrored or Replicated Managed objectis based on an application specific criteria. For example all customers on the west coast should bein a partition named fluency, while all customers on the east coast should be in a partition namedprimary.

Example 8.4. Partitioning application data// $Revision: 1.14 $package com.kabira.snippets.highavailability;

import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.LockMode;import com.kabira.platform.ha.MirroredObject;import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.annotation.Key;

/** * This snippet shows application partitioning of data. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class PartitionData{ /** * Partitioned Managed Object */ @Key(name = "ByIdentifier", fields = { "identifier" }, unique = true, ordered = false) public static class Mirrored extends MirroredObject { final String identifier;

Mirrored(String partitionGroup, String identifier) { super(partitionGroup, 0);

this.identifier = identifier;

System.out.println( "Assigning object " + identifier + " to group: " + partitionGroup); } }

/** * Main entry point * * @param args Not used */ public static void main(String[] args) { new Transaction("Partition Data") { @Override protected void run() throws Rollback

164

Chapter 8. High availability

Page 179: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ // // Create Fred in the fluency partition group // Mirrored fred = new Mirrored("fluency", "Fred");

// // Create Barney in the primary partition group // Mirrored barney = new Mirrored("primary", "Barney");

// // Find Fred and Barney // KeyManager<Mirrored> km = new KeyManager<Mirrored>(); KeyQuery<Mirrored> kq = km.createKeyQuery( Mirrored.class, "ByIdentifier");

KeyFieldValueList fvl = new KeyFieldValueList(); fvl.add("identifier", "Fred"); kq.defineQuery(fvl); fred = kq.getSingleResult(LockMode.READLOCK);

fvl = new KeyFieldValueList(); fvl.add("identifier", "Barney"); kq.defineQuery(fvl); barney = kq.getSingleResult(LockMode.READLOCK);

System.out.println(fred.identifier + " is in " + fred.partitionGroup); System.out.println(barney.identifier + " is in " + barney.partitionGroup);

// // Delete fred and barney // ManagedObject.delete(fred); ManagedObject.delete(barney); } }.execute(); }}

When Example 8.4 on page 164 is run it outputs the information in Example 8.5 on page 165.

Example 8.5. Partitioning application data output[primary] Assigning object Fred to group: fluency[primary] Assigning object Barney to group: primary[primary] Fred is in fluency[primary] Barney is in primary

Partition state change notifiersIn certain cases an application may need to be notified when a partition state changes. This is sup-ported using:

public abstract class com.kabira.platform.ha.PartitionStateNotifier{ abstract void stateTransition( Partition partition, PartitionState oldState, PartitionState newState);}

165

Partition state change notifiers

Page 180: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

An application can create an instance of a PartitionStateNotifier on each node where it isinterested in notifications of Partition state changes. The stateTransition method will be calledfor each state change for all partitions to which it is registered.

Example 8.6 on page 166 shows a simple implementation that monitors partition state changes.

Example 8.6. Monitoring partition state changes// $Revision: 1.14 $package com.kabira.snippets.highavailability;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.ha.Partition;import com.kabira.platform.ha.PartitionState;import com.kabira.platform.ha.PartitionStateNotifier;

/** * Snippet on handling partition state changes. * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class StateChange{ /** * Partition state change notifier */ public static class Notifier extends PartitionStateNotifier { /** * Start transition notifier * * @param partition Partition * @param oldState Previous state * @param newState New state */ @Override public void stateTransition( final Partition partition, final PartitionState oldState, final PartitionState newState) { String message = "Partition: " + partition.name + " transitioning " + "from " + oldState + " to " + newState + " now hosted on " + partition.primaryNodeName; System.out.println(message); } }

private static boolean m_onLocalNode = true; private static Partition m_partition; private static Notifier m_notifier;

166

Chapter 8. High availability

Page 181: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Main entry point * @param args Not used * @throws java.lang.InterruptedException */ public static void main(String[] args) throws InterruptedException { // // Create and install partition notifier // new Transaction("Create Partition Notifier") { @Override protected void run() throws Rollback { m_notifier = new Notifier();

// // Get the partition we are interested in // KeyManager<Partition> km = new KeyManager<Partition>(); KeyQuery<Partition> kq = km.createKeyQuery( Partition.class, "ByName"); KeyFieldValueList fvl = new KeyFieldValueList();

fvl.add("name", "fluency"); kq.defineQuery(fvl); m_partition = kq.getSingleResult(LockMode.READLOCK);

// // Register our notifier // m_partition.setStateNotifier(m_notifier); } }.execute();

// // Wait here for Partition to failover to remote node // waitForPartition(true, "Waiting for partition to failover");

// // Wait here for Partition to be restored from remote node // waitForPartition(false, "Waiting for partition to be restored");

// // Clean up partition notifier // new Transaction("Remove Partition Notifier") { @Override protected void run() throws Rollback { m_partition.clearStateNotifier(m_notifier); ManagedObject.delete(m_notifier); m_notifier = null; } }.execute(); }

// // Wait for partition to change state // private static void waitForPartition(final Boolean waitValue, final String message) throws InterruptedException

167

Partition state change notifiers

Page 182: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ while (m_onLocalNode == waitValue) { new Transaction("Wait for State Change") { @Override protected void run() throws Rollback { m_onLocalNode = m_partition.isHostedOnLocalNode(); } }.execute();

System.out.println(message); Thread.sleep(10000); } }}

When Example 8.6 on page 166 is run it outputs the (annotation added) information in Ex-ample 8.7 on page 168.

Example 8.7. Partition state change outputWaiting for partition to failover

## fluency partition was failed over to the backup node#Partition: fluency transitioning from Migrating to HostedOnPrimary now hosted on backupWaiting for partition to failover

## fluency partition was restored to the primary node#Partition: fluency transitioning from Migrating to HostedOnPrimary now hosted on primaryWaiting for partition to be restored

TimersFluency provides support for highly available timers. A highly available timer provides transparentfail-over to a backup node if the primary node fails. It also provides transparent timer services duringnode restoration and migration. The timer services are implemented as a notifier. An applicationinherits from the timer notifier interface and provides an implementation of the timerNotifieroperation to use the timer service.

An application defined mirrored object is specified when creating a timer. This mirrored object ispassed back to the timerNotifier method when it is called. This provides a mechanism for anapplication to provide context for each timer that is started. The timer and application definedmirrored object must both be created in the same partition.

If the timer and the application mirrored object are created in different partitions acom.kabira.platform.DataError error exception is thrown when the timer isstarted.

HA timers are transactional. If a timer is executing on a primary node but it does not commit beforea primary node failure, the timer will be executed on the backup node following fail-over.

HA timers are provided by the kabira.platform.ha.TimerNotifier class.

168

Chapter 8. High availability

Page 183: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The TimerNotifier is a mirrored object. It has a primary and a backup node and is associatedwith a partition. The timer can be controlled only on the current active node for the partition associ-ated with the timer. The timer notifier will also only trigger on the currently active node. The objectparameter to the timerNotifier operation must also be a Mirrored Managed object in the samepartition as the timer notifier. This is required so that this object is available on both the primaryand backup nodes for the timer.

The ha::TimerId is a unique identifier for the timer on both the primary and backup nodes. Theapplication can rely on this identifier being the same on both nodes. Timers are started using thenumber of seconds from the current time, i.e. a relative, not an absolute time. The timer fires whenthis time expires. The relative time is transmitted to the backup node for a timer and the currenttime on the backup node is used to calculate when the timer should fire. This minimizes the impactof clock drift between the primary and backup nodes. However, it is strongly recommended thatclocks be synchronized between the primary and backup nodes.

Failover and migrationWhen a primary node fails, any pending timers are automatically restarted on the backup node.One-shot timers will only be executed on the backup node if they have not executed on the primarynode before the failure. They will be executed at the initially scheduled time. A recurring timer willexecute on the backup node at the next scheduled time. It will then continue to execute on thebackup node until the primary node is restored. If a recurring timer was missed due to a delaybetween the primary failure and the backup node taking on the work, these scheduled timer execu-tions will be dropped - there are no "makeup" executions for recurring timers.

When a primary node is restored, any active timers on the backup node will be cancelled on thebackup node and restarted on the primary node. The same notifier execution rules as described forfail-over above apply.

Migrating a partition that contains active timers will cause the timer to be canceled on the oldprimary node and restarted on the new primary node. The same is true if the backup node was mi-grated. The same notifier execution rules as described for fail-over above apply.

Timer exampleExample 8.8 on page 169 shows how a highly available timer is created and terminated.

Example 8.8. Highly available timers// $Revision: 1.12 $

package com.kabira.snippets.highavailability;

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.ha.MirroredObject;import com.kabira.platform.ha.TimerNotifier;

/** * This snippet shows how to use HA timers * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Timer

169

Timers

Page 184: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ /** * Timer notifier * <p> * Timer notifier must be in same partition as the object passed * to the notifier. */ public static class Notifier extends TimerNotifier { /** * Create new timer notifier */ public Notifier() { super ("fluency", 0); }

/** * Timer notifier * * @param timerId Timer identifier * @param object Timer context object */ @Override public void timerNotify(String timerId, MirroredObject object) { TimerContext c1 = (TimerContext) object; c1.count += 1;

System.out.println("Timer Id:" + timerId + " Value: " + c1.count); } }

/** * Context passed to timer notifier */ public static class TimerContext extends MirroredObject { TimerContext() { super ("fluency", 0); } int count; }

/** * Main entry point * @param args Not used * @throws java.lang.InterruptedException */ public static void main(String [] args) throws InterruptedException { Timer timer = new Timer();

new Transaction("Start Timer") { @Override protected void run() throws Rollback { Notifier notifier = new Notifier(); TimerContext c1 = new TimerContext();

System.out.println("Starting one second recurring timer"); notifier.startRecurring(1, c1); } }.execute();

170

Chapter 8. High availability

Page 185: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // Wait for timer to fire a few times // Thread.sleep(10000);

new Transaction("Stop Timer") { @Override protected void run() throws Rollback { // // Stop timer - just delete the notifier // for (Notifier notifier : ManagedObject.extent(Notifier.class)) { System.out.println("Stopping one second recurring timer"); ManagedObject.delete(notifier); } } }.execute(); }}

When Example 8.8 on page 169 is run the output in Example 8.9 on page 171 is seen (annotationsadded).

Example 8.9. Highly available timer output## Timer started#[primary] Starting one second recurring timer

## Timer notifier called#[primary] Timer Id:primary:442381631492 Value: 1[primary] Timer Id:primary:442381631492 Value: 2[primary] Timer Id:primary:442381631492 Value: 3[primary] Timer Id:primary:442381631492 Value: 4[primary] Timer Id:primary:442381631492 Value: 5[primary] Timer Id:primary:442381631492 Value: 6[primary] Timer Id:primary:442381631492 Value: 7

## Timer terminated#[primary] Stopping one second recurring timer

Failure exposureThis section describes possible data loss under different backup policies.

Synchronous updatesSynchronous updates will only lose any non-committed Mirrored or Replicated object updates. Nocommitted work can be lost.

Inbound communications buffers that have not been processed by Fluency are also lost. Some net-work buffers are configurable. A smaller network buffer size implies lower exposure to data loss.

171

Failure exposure

Page 186: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

You can avoid even this small risk of data loss if the client of the Fluency application has a protocolacknowledgement and includes retry logic if no acknowledgement is received. If the client applicationresends the request nothing is lost. However, care should be taken to handle duplicates.

Deferred updatesDeferred updates will lose data queued for update. The amount of data that is queued is controlledby the time interval of the backup. Smaller intervals minimize the possible data loss. This lost datawas committed by the application on the primary node.

172

Chapter 8. High availability

Page 187: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

9Configuration

This chapter describes how to define and use Fluency configuration.

Defining configuration objectsA Fluency configuration object is defined as a Java class that extends a known base type. A Fluencyconfiguration notifier is also defined using inheritance.

Table 9.1. Configuration object definitions

DescriptionIdentification Mechanism

A configuration object.extends com.kabira.platform.kcs.Configuration

A configuration notifier.extends com.kabira.platform.switchconfig.Configura-tionListener

Configuration objects and notifiers are managed objects - they can only be manipulated in a Fluencytransaction. See Chapter 6 for more details on Managed Objects.

Here is an example of a configuration object.

Example 9.1. Configuration object// $Revision: 1.6.2.1 $package com.kabira.snippets.configuring;

import com.kabira.platform.kcs.Configuration;import com.kabira.platform.annotation.Key;import com.kabira.platform.annotation.KeyField;import java.util.Date;

enum Gender{ MALE, FEMALE

173

Page 188: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

}

/** * User configuration * * A key was added to allow the configuration data to be accessed * by last name. Notice that the versionId field also is in the * key. This is required since there may be multiple versions * of this configuration data loaded, both with the same last name. */@Key(name = "ByLastName",fields ={ "lastName", "versionId"},unique = true,ordered = false)public class User extends Configuration{

User( @KeyField(fieldName = "lastName") final String lastName, @KeyField(fieldName = "versionId") final String version) { this.versionId = version; this.lastName = lastName; } String firstName; final String lastName; Long age; Gender gender; Date joined;

// // Phone number is an optional field // String phoneNumber = "Not provided";}

See Example 9.9 on page 185 for an example of a configuration notifier.

Configuration typeBy default the configuration type of a configuration object is the Java package name. All configurationobjects defined in the same package will have the same configuration type For example, the config-uration type of the configuration object defined in Example 9.1 on page 173 iscom.kabira.snippets.configuring.

The default configuration type can be changed by overriding the getType() method. This methodreturns a string that is used for the configuration type.

For historical reasons the configuration type is called GroupKind in the configurationAPI. The documentation will always use type to describe this concept.

Example 9.2. Overriding default configuration type// $Revision: 1.3.4.1 $package com.kabira.snippets.configuring;

import com.kabira.platform.kcs.Configuration;

174

Chapter 9. Configuration

Page 189: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * A configuration object that overrides the default configuration type. * * This configuration object has a configuration type of MyConfigurationType */public class TypeOverride extends Configuration{ @Override public String getType() { return "MyConfigurationType"; } public String value;}

Optional fieldsBy default all fields specified in a configuration class are required in the configuration file. Addinga field initializer to a field in a configuration object definition makes that field optional in the config-uration file. If the field is not set in the configuration value, the configuration object will have theinitializer value specified in the class definition. The User.phoneNumber field is optional in theUser configuration object in Example 9.1 on page 173.

Supported field and array typesThe supported types for fields and array elements in configuration objects are:

• boolean and Boolean

• byte and Byte

• long and Long

• java.lang.String

• java.util.Date

• Enumerations

• Managed Objects (including other configuration objects)

• Arrays containing one of the supported types.

Managed Objects and Array nesting is supported. See Example 9.3 on page 176 for an example ofdefining nested configuration. See Example 9.4 on page 176 for an example of how nested configur-ation data is specified in a configuration file.

An exception is thrown during configuration load if the configuration data contains unsupportedtypes.

Fields in a configuration object can be either public, package private, or private.

Keys are supported, but not required, on configuration objects. See the section called “Keys andQueries” on page 116 for details on defining keys.

Configuration classes must be resolved by the JVM before configuration data can be loaded. SeeExample 9.7 on page 178 for details on one way to ensure that a configuration class has been resolved

175

Defining configuration objects

Page 190: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

by the JVM. If the configuration class has not been resolved, the configuration will fail to load withan unresolved class error.

Example 9.3. Nested configuration definition// $Revision: 1.3 $package com.kabira.snippets.configuring;

import com.kabira.platform.annotation.Managed;import com.kabira.platform.kcs.Configuration;

@Managedclass Player{ String name; String position;}

/** */public class Team extends Configuration{ /** * Team name */ String name;

/** * Team players */ Player [] players;}

Example 9.4. Nested configuration file// $Revision: 1.3 $configuration "team" version "1.0" type "com.kabira.snippets.configuring"{ configure com.kabira.snippets.configuring { Team { name = "giants"; players = { { name = "Tim Lincecum"; position = "Pitcher"; }, { name = "Matt Cain"; position = "Pitcher"; }, { name = "Buster Posey"; position = "Catcher"; } }; }; };};

Data Format  A Date value in a configuration file must be a string using a format of Y-M-D Twhere:

176

Chapter 9. Configuration

Page 191: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Y is the year, including a century, expressed as a decimal number, e.g. 2011.

• M is the month expressed as a decimal number from 01 to 12, e.g. 12 for December.

• D is the day of the month expressed as a decimal number from 01 to 31, e.g. 04.

• T is the time expressed as H:M:S where H is a decimal number between representing a 24 hourclock from 00 to 23, M is the minute expressed as a decimal number from 00 to 59, and S is thesecond expressed as a decimal number from 00-60, e.g. 11:05:23.

Configuration object life cycleThe creation and deletion of all configuration objects is done by the Fluency configuration framework.Any nested Managed Objects contained in a configuration object are also created and deleted bythe configuration framework. They must not be deleted by the application.

RestrictionsConfiguration objects have the following restrictions:

• all fields must be a supported Java type.

• all arrays must contain only supported Java types.

• nested Managed Objects cannot contain fields named groupId or versionId. This is becausethe configuration loader automatically populates these fields with the current configuration name(groupId) and version (versionId) when the data is loaded. These fields are removed fromthe configuration data when it is exported using the configuration exporter. If these fields areused in nested Managed Objects, round-tripping of the configuration data will not work.

Accessing configuration objectsConfiguration objects are accessed like any other Managed Object. They can be located using anextent query or a select using unique or non-unique keys.

If a unique key is defined on a configuration object it must include the version identifier. This isrequired because different versions of a configuration object may be loaded at the same time. If theunique key did not include the version identifier a duplicate key exception would be reported whenthe second version of the configuration data was loaded. Example 9.1 on page 173 has an exampleof a unique key that contains the version identifier.

Example 9.7 on page 178 loads two versions of the same configuration data and then displays theconfiguration data using an extent query.

Example 9.5. User configuration version 1.0// $Revision: 1.3.2.1 $configuration "user" version "1.0" type "com.kabira.snippets.configuring"{ configure com.kabira.snippets.configuring { User { firstName = "John"; lastName = "Doe";

177

Accessing configuration objects

Page 192: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

age = 8; gender = Gender.MALE; joined = "2011-01-25 12:00:00"; }; User { firstName = "Big"; lastName = "Steve"; age = 19; gender = Gender.MALE; joined = "2011-01-25 01:09:12"; }; };};

Example 9.6. User configuration version 2.0// $Revision: 1.5.2.1 $configuration "user" version "2.0" type "com.kabira.snippets.configuring"{ configure com.kabira.snippets.configuring { User { firstName = "John"; lastName = "Doe"; age = 9; gender = Gender.MALE; joined = "2011-01-25 08:04:00"; }; User { firstName = "Big"; lastName = "Steve"; age = 87; gender = Gender.MALE; phoneNumber = "415-555-1212"; joined = "2011-01-25 01:09:12"; }; };};

Example 9.7. Locating configuration objects// $Revision: 1.7.2.1 $package com.kabira.snippets.configuring;

import com.kabira.test.management.Client;import com.kabira.test.management.CommandFailed;

import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.platform.switchconfig.Version;

import java.net.URL;

/** * Snippet to locate configuration objects by version * * NOTE: This snippet requires the classpath to include the * directory where the configuration files are located. This * allows the get resource call to locate the configuration files * * <p> * <h2> Target Nodes</h2> * <ul>

178

Chapter 9. Configuration

Page 193: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

* <li> <b>domainnode</b> = primary * </ul> */public class LocateConfiguration{ /** * Execute snippet * @param args Not used * @throws CommandFailed Configuration command failed * @throws ClassNotFoundException Could not load a class */ public static void main(String[] args) throws CommandFailed, ClassNotFoundException { Client client = new Client("guest", "guest");

URL url1 = client.getClass().getClassLoader().getResource("user1.kcs"); URL url2 = client.getClass().getClassLoader().getResource("user2.kcs"); URL url3 = client.getClass().getClassLoader().getResource("team.kcs");

if ((url1 == null) || (url2 == null) || (url3 == null)) { throw new Error( "Configuration files not located - are they installed into " + "the current class path?"); }

Client.Configuration version1 = client.new Configuration(url1); Client.Configuration version2 = client.new Configuration(url2); Client.Configuration version3 = client.new Configuration(url3);

// // Resolve configuration classes // Class.forName("com.kabira.snippets.configuring.User"); Class.forName("com.kabira.snippets.configuring.Team");

// // Load configuration files // version1.load(); version2.load(); version3.load();

// // Activate version 1 // version1.activate(); displayData();

// // Activate version 2 // version2.activate(); displayData();

// // Deactive version 2 // version2.deactivate();

// // Remove configurations // version1.remove(); version2.remove(); version3.remove(); }

179

Accessing configuration objects

Page 194: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // Display configuration data and versions // private static void displayData() { // // Display the configuration objects // new Transaction("Locate Configuration") { @Override protected void run() { // // Display user configuration objects // System.out.println("Configuration Data"); for (User user : ManagedObject.extent(User.class)) { System.out.println( "\tFirst Name: " + user.firstName + " Last Name: " + user.lastName + " Age: " + user.age + " Joined: " + user.joined + " Configuration Version: " + user.versionId + " Configuration Name: " + user.groupId); } System.out.println(""); for (Team team : ManagedObject.extent(Team.class)) { System.out.println( "\tTeam Name: " + team.name + " Configuration Version: " + team.versionId + " Configuration Name: " + team.groupId); for (Player player : team.players) { System.out.println( "\t\tName: " + player.name + " Position: " + player.position); } } System.out.println("");

// // Display version data - skip all versions other // then the ones associated with this configuration type // System.out.println("Versions"); for (Version version : ManagedObject.extent(Version.class)) { if (version.groupKindId.equals( "com.kabira.snippets.configuring") != true) { continue; } System.out.println( "\tType: " + version.groupKindId + " Name: " + version.groupId + " Version: " + version.versionId + " State: " + version.state.name()); } System.out.println(""); } }.execute(); }}

180

Chapter 9. Configuration

Page 195: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

When this snippet is run the following output is displayed (annotation added).

## All configuration data is loaded in memory#[primary] Configuration Data[primary] First Name: John Last Name: Doe Age: 9 Joined: Tue Jan 25 08:04:00 PST 2011 Configuration Version: 2.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 87 Joined: Tue Jan 25 01:09:12 PST 2011 Configuration Version: 2.0 Configuration Name: user[primary] First Name: John Last Name: Doe Age: 8 Joined: Tue Jan 25 12:00:00 PST 2011 Configuration Version: 1.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 19 Joined: Tue Jan 25 01:09:12 PST 2011 Configuration Version: 1.0 Configuration Name: user[primary] [primary] Team Name: giants Configuration Version: 1.0 Configuration Name: team[primary] Name: Tim Lincecum Position: Pitcher[primary] Name: Matt Cain Position: Pitcher[primary] Name: Buster Posey Position: Catcher[primary]

## Version 1.0 of the user configuration is active. Version 2.0 of # the user configuration is inactive. Version 1.0 of the team configuration# is inactive#[primary] Versions[primary] Type: com.kabira.snippets.configuring Name: user Version: 1.0 State: Active[primary] Type: com.kabira.snippets.configuring Name: user Version: 2.0 State: Inactive[primary] Type: com.kabira.snippets.configuring Name: team Version: 1.0 State: Inactive[primary]

## All configuration data still in memory after activating version 2.0 of# user configuration#[primary] Configuration Data[primary] First Name: John Last Name: Doe Age: 9 Joined: Tue Jan 25 08:04:00 PST 2011 Configuration Version: 2.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 87 Joined: Tue Jan 25 01:09:12 PST 2011 Configuration Version: 2.0 Configuration Name: user[primary] First Name: John Last Name: Doe Age: 8 Joined: Tue Jan 25 12:00:00 PST 2011 Configuration Version: 1.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 19 Joined: Tue Jan 25 01:09:12 PST 2011 Configuration Version: 1.0 Configuration Name: user[primary] [primary] Team Name: giants Configuration Version: 1.0 Configuration Name: team[primary] Name: Tim Lincecum Position: Pitcher[primary] Name: Matt Cain Position: Pitcher[primary] Name: Buster Posey Position: Catcher[primary]

## Version 2.0 of the user configuration is active. Version 1.0 of # the user configuration is inactive. Version 1.0 of the team configuration# is inactive#[primary] Versions[primary] Type: com.kabira.snippets.configuring Name: user Version: 1.0 State: Inactive[primary] Type: com.kabira.snippets.configuring Name: user Version: 2.0 State: Active[primary] Type: com.kabira.snippets.configuring Name: team Version: 1.0 State: Inactive

181

Accessing configuration objects

Page 196: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

VersionsTo find an active version for a specific configuration type and name the ByGroupState key is used.This non-unique key allows Version objects to be selected using the configuration type, name, andstate. The ByGroupState key is non-unique since there can be multiple Inactive versions fora specific configuration type and name. There is always only zero or one Active version.

For historical reasons the configuration name is called Group in the configuration API.The documentation will always use name to describe this concept.

All configuration objects associated with a version (active or not) are found using the Version.get-Configs() method. This is shown in Example 9.8 on page 182. Configuration objects are returnedfrom the Version.getConfigs() method in the same order in which they were loaded fromthe configuration file.

Example 9.8. Version object// $Revision: 1.7.2.1 $package com.kabira.snippets.configuring;

import com.kabira.platform.KeyFieldValueList;import com.kabira.platform.KeyManager;import com.kabira.platform.KeyQuery;import com.kabira.platform.LockMode;import com.kabira.test.management.Client;import com.kabira.test.management.CommandFailed;

import com.kabira.platform.Transaction;import com.kabira.platform.switchconfig.Config;import com.kabira.platform.switchconfig.Version;

import java.net.URL;

/** * Snippet to locate the active version * * NOTE: This snippet requires the classpath to include the * directory where the configuration files are located. This * allows the get resource call to locate the configuration files * * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ActiveVersion{ /** * Execute snippet * @param args Not used * @throws CommandFailed Configuration command filed * @throws ClassNotFoundException Configuration class not found */ public static void main(String[] args) throws CommandFailed, ClassNotFoundException { Client client = new Client("guest", "guest");

URL url1 = client.getClass().getClassLoader().getResource("user1.kcs"); URL url2 = client.getClass().getClassLoader().getResource("user2.kcs");

if ((url1 == null) || (url2 == null))

182

Chapter 9. Configuration

Page 197: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ throw new Error( "Configuration files not located - are they installed into " + "the current class path?"); }

// // Resolve configuration classes // Class.forName("com.kabira.snippets.configuring.User");

Client.Configuration version1 = client.new Configuration(url1); Client.Configuration version2 = client.new Configuration(url2);

// // Load configuration files // version1.load(); version2.load();

// // Activate version 1 // System.out.println("Activate version 1.0"); version1.activate(); displayActiveVersion();

// // Activate version 2 // System.out.println("Activate version 2.0"); version2.activate(); displayActiveVersion();

// // Deactive version 2 // version2.deactivate();

// // Remove configurations // version1.remove(); version2.remove(); }

// // Locate and display the active version // private static void displayActiveVersion() { new Transaction("Display Active Version") { @Override protected void run() throws Rollback { KeyQuery<Version> kq; KeyFieldValueList kfvl; // // The active version is selected using the ByGroupState key. // kq = new KeyManager<Version>(). createKeyQuery(Version.class, "ByGroupState"); kfvl = new KeyFieldValueList(); kfvl.add("groupKindId", User.class.getPackage().getName()); kfvl.add("groupId", "user"); kfvl.add("state", Version.State.Active);

183

Versions

Page 198: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

kq.defineQuery(kfvl);

for (Version version : kq.getResults(LockMode.READLOCK)) { System.out.println( "Name: " + version.groupId + " Type: " + version.groupKindId + " Version: " + version.versionId + " State: " + version.state.name());

Config[] configArray = version.getConfigs(); System.out.println("Contains:"); for (Config config : configArray) { User user = (User)config;

if (user == null) { continue; }

System.out.println( "\tFirst Name: " + user.firstName + " Last Name: " + user.lastName + " Age: " + user.age + " Gender: " + user.gender + " Joined: " + user.joined + " Phone Number: " + user.phoneNumber + " Configuration Version: " + user.versionId + " Configuration Name: " + user.groupId); } } } }.execute(); }}

When this snippet is run it displays the following output (annotation added):

## Version 1.0 is active#[primary] Activate version 1.0[primary] Name: user Type: com.kabira.snippets.configuring Version: 1.0 State: Active[primary] Contains:[primary] First Name: John Last Name: Doe Age: 8 Gender: MALE Joined: Tue Jan 25 12:00:00 PST 2011 Phone Number: Not provided Configuration Version: 1.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 19 Gender: MALE Joined: Tue Jan 25 01:09:12 PST 2011 Phone Number: Not provided Configuration Version: 1.0 Configuration Name: user

## Version 2.0 is active#[primary] Activate version 2.0[primary] Name: user Type: com.kabira.snippets.configuring Version: 2.0 State: Active[primary] Contains:[primary] First Name: John Last Name: Doe Age: 9 Gender: MALE Joined: Tue Jan 25 08:04:00 PST 2011 Phone Number: Not provided Configuration Version: 2.0 Configuration Name: user[primary] First Name: Big Last Name: Steve Age: 87 Gender: MALE Joined: Tue Jan 25 01:09:12 PST 2011 Phone Number: 415-555-1212 Configuration Version: 2.0 Configu

184

Chapter 9. Configuration

Page 199: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

NotifiersConfiguration notifiers provide a mechanism to perform application specific configuration auditingand to associate application behavior with configuration state changes.

Configuration notifiers are defined by extending com.kabira.platform.switchconfig.Con-figurationListener. Configuration notifiers must be created and initialized before they arecalled by the configuration framework. This initialization and termination can be done as part ofapplication initialization and termination. The disadvantage of this approach is that the applicationmust specifically call initialize and terminate methods for each configuration type. Another mechanismto install and remove configuration notifiers is to use Fluency component notifiers. See the sectioncalled “Notifiers” on page 195 for details.

There are two different kinds of methods in a configuration notifier:

• Audit

• State change

Audit methods are always called before its associated state change method (except for load wherethey are called after the load method). If a method throws the com.kabira.platform.switch-config.ConfigurationException it is an audit method. An audit method reports an auditfailure by throwing a com.kabira.platform.switchconfig.ConfigurationExceptionexception. An audit failure prevents the requested configuration state change from occurring. Auditmethods should not change the application state in any way.

A state change method cannot fail. It is only called if its associated audit method did not report anerror. Any application state changes triggered by the configuration state change should be imple-mented in state methods.

The loaded state change method provides a mechanism to manually add additional configurationobjects to the ones loaded from an external file. To add additional configuration objects, the imple-mentation of the loaded method should create configuration instances and return them to theframework in the additions parameter.

Here is an example of a configuration notifier.

Example 9.9. Configuration notifier// $Revision: 1.5 $package com.kabira.snippets.configuring;

import com.kabira.platform.switchconfig.Config;import com.kabira.platform.switchconfig.ConfigurationException;import com.kabira.platform.switchconfig.ConfigurationListener;import com.kabira.platform.switchconfig.Version;

/** * Configuration notifier */public class UserNotifier extends ConfigurationListener{

public UserNotifier() { super( User.class.getPackage().getName()); }

185

Notifiers

Page 200: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

@Override public void loaded( Version version, java.util.List<Config> additions) { System.out.println("Loading type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void auditLoad(Version version) throws ConfigurationException { System.out.println("Auditing load for type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void auditActivate(Version version) throws ConfigurationException { System.out.println("Auditing activation for type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void activated(Version version) { System.out.println("Activating type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void auditReplace( Version deactivating, Version activating) throws ConfigurationException { System.out.println("Auditing replace (deactivation) of type: " + deactivating.groupKindId + " name: " + deactivating.groupId + " version: " + deactivating.versionId);

System.out.println("Auditing replace (activation) of type: " + activating.groupKindId + " name: " + activating.groupId + " version: " + activating.versionId); }

@Override public void replaced(Version deactivating, Version activating)

186

Chapter 9. Configuration

Page 201: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ System.out.println("Replacing (deactivation) type: " + deactivating.groupKindId + " name: " + deactivating.groupId + " version: " + deactivating.versionId);

System.out.println("Replacing (activation) type: " + activating.groupKindId + " name: " + activating.groupId + " version: " + activating.versionId); }

@Override public void auditDeactivate(Version version) throws ConfigurationException { System.out.println("Auditing deactivation of type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void deactivated(Version version) { System.out.println("Deactivating type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void auditRemove(Version version) throws ConfigurationException { System.out.println("Auditing removal of type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }

@Override public void removed(Version version) { System.out.println("Removing type: " + version.groupKindId + " name: " + version.groupId + " version: " + version.versionId); }}

Configuration notifiers are installed by creating an instance. They are removed by deleting the in-stance.

Example 9.10 on page 188 contains a complete example of initializing and terminating a configurationnotifier. See Example 9.9 on page 185 for the notifier that is being installed.

187

Notifiers

Page 202: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 9.10. Notifier initialization and termination// $Revision: 1.6 $package com.kabira.snippets.configuring;

import com.kabira.platform.ManagedObject;import com.kabira.platform.Transaction;import com.kabira.test.management.Client;import com.kabira.test.management.CommandFailed;import java.net.URL;

/** * Snippet to install and terminate configuration notifiers * * NOTE: This snippet requires the classpath to include the * directory where the configuration files are located. This * allows the get resource call to locate the configuration files * * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class NotifierLifeCycle{ /** * Initialize the configuration notifier */ public void initialize() { new Transaction("Initialize Configuration Notifier") { @Override protected void run() throws Rollback { m_userNotifier = new UserNotifier(); } }.execute(); }

/** * Terminate the configuration notifier */ public void terminate() { new Transaction("Terminate Configuration Notifier") { @Override protected void run() throws Rollback { // // Delete the configuration notifier // ManagedObject.delete(m_userNotifier); m_userNotifier = null; } }.execute(); }

/** * Execute snippet * * @param args Not used * @throws CommandFailed Configuration command failed * @throws ClassNotFoundException Configuration class not found */

188

Chapter 9. Configuration

Page 203: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

public static void main(String[] args) throws CommandFailed, ClassNotFoundException { Client client = new Client("guest", "guest");

URL url1 = client.getClass().getClassLoader().getResource("user1.kcs"); URL url2 = client.getClass().getClassLoader().getResource("user2.kcs");

if ((url1 == null) || (url2 == null)) { throw new Error( "Configuration files not located - are they installed into " + "current class path?"); }

Client.Configuration version1 = client.new Configuration(url1); Client.Configuration version2 = client.new Configuration(url2);

// // Install configuration notifiers // NotifierLifeCycle notifierLifeCycle = new NotifierLifeCycle(); notifierLifeCycle.initialize();

// // Resolve configuration classes // Class.forName("com.kabira.snippets.configuring.User");

// // Load configuration files // version1.load(); version2.load();

// // Activate version 1 // version1.activate();

// // Activate version 2 - causes replace notifier to be called // version2.activate();

// // Deactive version 2 // version2.deactivate();

// // Remove configurations // version1.remove(); version2.remove();

// // Remove configuration notifiers // notifierLifeCycle.terminate();

} private UserNotifier m_userNotifier;}

When Example 9.10 on page 188 is run it outputs the following (annotation added):

189

Notifiers

Page 204: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

## Load and audit version 1.0#[primary] Loading type: com.kabira.snippets.configuring name: user version: 1.0[primary] Auditing load for type: com.kabira.snippets.configuring name: user version: 1.0

## Load and audit version 2.0#[primary] Loading type: com.kabira.snippets.configuring name: user version: 2.0[primary] Auditing load for type: com.kabira.snippets.configuring name: user version: 2.0

## Audit activation, and activate version 1.0#[primary] Auditing activation for type: com.kabira.snippets.configuring name: user version: 1.0[primary] Activating type: com.kabira.snippets.configuring name: user version: 1.0

## Audit replace, and then replace version 1.0 with version 2.0#[primary] Auditing replace (deactivation) of type: com.kabira.snippets.configuring name: user version: 1.0[primary] Auditing replace (activation) of type: com.kabira.snippets.configuring name: user version: 2.0[primary] Replacing (deactivation) type: com.kabira.snippets.configuring name: user version: 1.0[primary] Replacing (activation) type: com.kabira.snippets.configuring name: user version: 2.0

## Audit deactivation, and then deactivate version 2.0#[primary] Auditing deactivation of type: com.kabira.snippets.configuring name: user version: 2.0[primary] Deactivating type: com.kabira.snippets.configuring name: user version: 2.0

## Audit removal, and then remove, version 1.0#[primary] Auditing removal of type: com.kabira.snippets.configuring name: user version: 1.0[primary] Removing type: com.kabira.snippets.configuring name: user version: 1.0

## Audit removal, and then remove, version 2.0#[primary] Auditing removal of type: com.kabira.snippets.configuring name: user version: 2.0[primary] Removing type: com.kabira.snippets.configuring name: user version: 2.0

Runtime objectsThe purpose of configuration objects is to provide data for runtime objects. A runtime object is anapplication specific object that contains both state and behavior that provides an application specificfunction. This section describes common patterns for runtime objects and some guidelines formanaging them.

190

Chapter 9. Configuration

Page 205: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Design patternsThere are various patterns you can use to define the correspondence between configuration andruntime objects; the following sections discuss some of these patterns.

Matching configuration and runtime objects  In many cases, each configuration objectis used to create and configure a runtime counterpart. The runtime object can be a Managed Objector a POJO. For example, when a Printer configuration object is activated, the activate notifiermethod would create a runtime printer object. The configuration data is copied into the runtimeobject fields.

Similarly, when the configuration object is deactivated, the runtime object is deleted or released.This is the least complex pattern to use, and results in the fewest design and implementation issues.

This pattern is best used when the application quickly locates a runtime object, uses it, and detaches.This pattern is also used when it seems that the existence of the runtime object should be initiatedby loading and activating a configuration, and destroyed by deactivating a configuration.

Differing life cycles  Another pattern is used when a small number of runtime objects have alifecycle that must be longer than the configuration object. In this case, upon activation, the config-uration object should simply locate the runtime object, and copy attribute values from the configur-ation object to the runtime object. This pattern is also simple to use.

Shared configuration objects  Another pattern is used when a large number of runtime objectsshare the same configuration objects. A large number could be thousands, or even millions ofruntime objects. This patter is used when the configuration objects form a repository, as a productcatalog might for an example application. The product catalog (configuration data) defines thecharacteristics of the product, while the runtime objects would represent instances of products. Inthis case, the runtime objects would attach to the configuration object every time it needs to usethe configuration data.

Runtime objects should never cache handles to configuration objects. These handles willbecome stale when the configuration version state changes.

191

Runtime objects

Page 206: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

192

Page 207: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

10Components

This chapter describes how to define and use Fluency components.

Defining a componentA component is a JAR file that contains a property file named kabira.properties. The propertiessupported in the kabira.properties file are summarized in Table 10.1 on page 193.

Table 10.1. Component properties

DescriptionProperty

A unique indentifier for this component. This property is used both foridentifying the component in log messages and to prevent the samecomponent from being loaded multiple times. This property is required.

Component-Name

A comma separated list of fully qualified class names which extendcom.kabira.platform.component.Notifier. This property isoptional.

Component-Notifi-ers

A comma separated list of configuration files which include path inform-ation relative to the top of the JAR. It is recommended that configuration

Configuration-Files

files are stored with enough path to prevent collisions with files of thesame name in other components. This property is optional.

Property values must be specified in a single line unless the "\" line continuation character is usedto span lines. See Example 10.1 on page 194 for an example property file.

White-space is allowed in the value for the Component-Name property.

All other white-space in property files is ignored.

193

Page 208: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 10.1. Component property file# $Revision: 1.4 $

## The name of this component#Component-Name Snippet Component Sample

## Notifiers associated with this component#Component-Notifiers com.kabira.snippets.components.NotifierOne, \ com.kabira.snippets.components.NotifierTwo

## Configuration files associated with this component#Configuration-Files default.kcs

Locating the kabira.properties fileThe kabira.properties file is searched for in these locations:

• top of the JAR file

• any element in the classpath

If the kabira.properties file is located in the top of the JAR file it is always found and loadedif the JAR file is in the current class path. This is the simplest and most transparent mechanism tolocate the kabira.properties file.

It is also possible to locate the kabira.properties file in a nested directory in a JAR file if thisdirectory is specified in the class path.

If there are multiple kabira.properties file located in a JAR file, the first one located is used.All others are ignored.

This is an example of a JAR file that contains the kabira.properties file at the top of the JARfile.

Example 10.2. Location of kabira.properties in JAR file

jar tf snippets.jar

META-INF/META-INF/MANIFEST.MFcom/com/kabira/com/kabira/snippets/com/kabira/snippets/components/com/kabira/snippets/development/com/kabira/snippets/distributedcomputing/com/kabira/snippets/highavailability/com/kabira/snippets/managedobjects/com/kabira/snippets/management/com/kabira/snippets/reference/com/kabira/snippets/transactions/com/kabira/snippets/vmlifecycle/

...

194

Chapter 10. Components

Page 209: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

kabira.properties

NotifiersComponent notifiers provide a mechanism to transparently perform component initialization andtermination. The user of the component does not need to explicitly initialize or terminate a component.

A notifier is implemented by extending com.kabira.platform.Notifier and overriding themethods are that are needed to perform component initialization and termination. See Ex-ample 10.3 on page 195 for an example notifier.

Example 10.3. Component notifier// $Revision: 1.4 $package com.kabira.snippets.components;

import com.kabira.platform.component.Notifier;import com.kabira.platform.component.ComponentException;

/** * Component notifier one */public class NotifierOne extends Notifier{ @Override protected void preConfigurationInitialize() throws ComponentException { try { // // Resolve configuration class // Class.forName("com.kabira.snippets.components.Defaults"); } catch (ClassNotFoundException ex) { new ComponentException("Class resolution failed", ex); }

m_notifierName = getClass().getSimpleName();

System.out.println(m_notifierName + ": - preConfigurationInitialize"); }

@Override protected void postConfigurationInitialize() { System.out.println(m_notifierName + ": - postConfigurationInitialize");

}

@Override protected void preConfigurationTerminate() { System.out.println(m_notifierName + ": - preConfigurationTerminate");

}

@Override protected void postConfigurationTerminate() { System.out.println(m_notifierName + ": - postConfigurationTerminate");

195

Defining a component

Page 210: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

}

private String m_notifierName;}

Notifiers are created and executed in the order they are specified in the Component-Notifiersproperty during component initialization. They are executed and released for garbage collection inthe reverse order during component termination. Since the same notifier instance is used for initial-ization and termination, state information can be stored in the notifier during the lifetime of thecomponent for implementation specific reasons.

Component activation fails if:

• a notifier class specified in the Component-Notifiers property cannot be found.

• a notifier class does not extend from com.kabira.platform.component.Notifier.

• a com.kabira.platform.component.ComponentException is thrown by a notifier ini-tialization method.

ConfigurationComponents may contain configuration files. The configuration files contained in a component areautomatically loaded and activated when a component is initialized. They are loaded and activatedin the order they are specified in the Configuration-Files property. The configuration filesare deactivated and removed when the component is terminated. They are deactivated and removedin the reverse order from which they were activated during initialization.

Component activation fails if:

• a configuration file specified in the Configuration-Files property cannot be found.

• a configuration file load fails.

• a configuration file activation fails.

Any failures deactivating and removing configuration files during component termination are ignored.

ExampleThis is a complete example of a component. The example consists of these files:

• NotifierOne.java - component notifier one (see Example 10.3 on page 195).

• NotifierTwo.java - component notifier two (see Example 10.4 on page 197).

• Defaults.java - example configuration definition (see Example 10.5 on page 197).

• default.kcs - configuration file loaded by component (see Example 10.6 on page 197).

• ComponentMain.java - driver to execute example (see Example 10.7 on page 198).

• kabira.properties - component property file (see Example 10.1 on page 194).

196

Chapter 10. Components

Page 211: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 10.4. NotifierTwo.java// $Revision: 1.4 $package com.kabira.snippets.components;

import com.kabira.platform.component.Notifier;

/** * Component notifier two */public class NotifierTwo extends Notifier{ @Override protected void preConfigurationInitialize() { m_notifierName = getClass().getSimpleName();

System.out.println(m_notifierName + ": - preConfigurationInitialize"); }

@Override protected void postConfigurationInitialize() { System.out.println(m_notifierName + ": - postConfigurationInitialize");

}

@Override protected void preConfigurationTerminate() { System.out.println(m_notifierName + ": - preConfigurationTerminate");

}

@Override protected void postConfigurationTerminate() { System.out.println(m_notifierName + ": - postConfigurationTerminate"); }

private String m_notifierName;}

Example 10.5. Defaults.java// $Revision: 1.3 $package com.kabira.snippets.components;

import com.kabira.platform.kcs.Configuration;

/** * Default component configuration */public class Defaults extends Configuration{ String defaultValue;}

Example 10.6. default.kcs// $Revision: 1.2 $configuration "default" version "1.0" type "com.kabira.snippets.components"{ configure com.kabira.snippets.components { Defaults

197

Example

Page 212: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ defaultValue = "hello world"; }; };};

Example 10.7. ComponentMain.java// $Revision: 1.4 $package com.kabira.snippets.components;

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;

/** * Execute component example * * NOTE: This example requires the classpath to explicitly include the * directory that contains this snippet source so that the kabira.properties * file is found. * * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ComponentMain{ /** * @param args None supported */ public static void main(String[] args) { System.out.println("Main executed");

new Transaction("Components") { @Override protected void run() throws Rollback { for (Defaults defaults : ManagedObject.extent(Defaults.class )) { System.out.println( "Configured default value: " + defaults.defaultValue); } }

}.execute();

System.out.println("Main exiting"); }}

When main is executed the following output (annotation added) is generated.

This example requires that the class path explicitly contain the location of the examplesource - <Fluency installation directory>/snippets/src/com/kabira/snippets/com-ponents

198

Chapter 10. Components

Page 213: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 10.8. Example component output

### Component initialization#[primary] NotifierOne: - preConfigurationInitialize[primary] NotifierTwo: - preConfigurationInitialize[primary] NotifierOne: - postConfigurationInitialize[primary] NotifierTwo: - postConfigurationInitialize

## Main execution#[primary] Main executed[primary] Configured default value: hello world[primary] Main exiting

## Component termination#[primary] NotifierTwo: - preConfigurationTerminate[primary] NotifierOne: - preConfigurationTerminate[primary] NotifierTwo: - postConfigurationTerminate[primary] NotifierOne: - postConfigurationTerminate

199

Example

Page 214: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

200

Page 215: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

11System management

This chapter describes how to define Fluency system management targets. It also describes thedefault Fluency logger.

Defining a system management targetA system management target is defined by extending com.kabira.platform.management.Tar-get.

Example 11.1. Defining a management target// $Revision: 1.4 $

package com.kabira.snippets.management;

import com.kabira.platform.management.Target;import com.kabira.platform.management.ManagementTarget;

/** * MyTarget management target definition */@ManagementTarget(name = "mytarget", description = "a management target")public class MyTarget extends Target{}

Annotations are used to define the user interface to the management target. The annotations usedare:

Table 11.1. System management annotations

DescriptionAnnotation

Define the name and description of a management target.@ManagementTarget

Indicate that a method should be exposed as a management command.@Command

201

Page 216: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Define a management command parameter.@Parameter

Define default values for management command parameters.@Default

@ManagementTarget annotationThe @ManagementTarget annotation is defined as:

Example 11.2. @ManagementTarget annotationpackage com.kabira.platform.management;

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

/** * Indicate that this class implements a Management Target. This * annotation must be applied to any class registered with Target.register(). */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface ManagementTarget{ /** * The public name of the target. Required. */ String name();

/** * The description of the target. Used to generate command help message. */ String description() default "";}

@Command annotationThe @Command annotation is defined as:

Example 11.3. @Command annotationpackage com.kabira.platform.management;

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

/** * Indicate that this method should be exposed as an command. * Commands must return void, or TargetException will be thrown * when the target is registered. */@Documented@Inherited

202

Chapter 11. System management

Page 217: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Command{ /** * The description of the command. Used to generate command help message. */ String description() default "";}

A method exposed as a management command must be:

• public

• return void

A TargetException is thrown when the management target is registered if a method with the@Command annotation does not following these rules.

@Default annotationThe @Default annotation is defined as:

Example 11.4. @Default annotationpackage com.kabira.platform.management;

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

/** * Defines default values for parameters. * see java.lang.String for descriptions of valid String formats for * the supported parameter types. */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Default{ /** * Must be set true if the default value is provided. */ boolean provided() default true;

/** * The default value to be used. */ String value();}

@Parameter annotationThe @Parameter annotation is defined as:

203

Defining a system management target

Page 218: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 11.5. @Parameter annotationpackage com.kabira.platform.management;

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

/** * ManagementTarget Command parameter. * Must be present on all parameters of a method annotated as a @Command. Valid * parameter types are String, Enum, Boolean, Character, Integer, Byte, Short, * Long, Float, and Double. Other types will cause TargetException to be * thrown when the target is registered. Arrays are not supported. * see java.lang.String for descriptions of valid String formats for * the supported parameter types. */@Documented@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public @interface Parameter{ /** * The parameter name as exposed to management clients */ String name();

/** * A description of the parameter. Used in the generated help for the * command. */ String description() default "";

/** * Indicates that this parameter must be set by the caller. * If the parameter is not set. the command will fail. * If false, and no default is provided, the value of the parameter will be * null */ boolean required() default false;

/** * The default value of the parameter. */ Default defaultValue() default @Default(provided = false, value = "");}

All parameters of a method marked with the @Command annotation must be marked with the@Parameter annotation. The supported parameter types are:

• String

• Enum

• Boolean

• Character

• Integer

204

Chapter 11. System management

Page 219: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• Byte

• Short

• Long

• Float

• Double

A TargetException is thrown when the management target is registered if an unsupportedparameter type is detected.

SecuritySecurity should be configured for all application administration targets. This protects the applicationfrom unauthorized access to administrative functions. In general, access to any command thatmodifies the state of the running system should only be granted to the switchadmin role. Com-mands that only display system state should grant access to the switchmonitor role. See theFluency Administration Guide for details on the switchadmin and switchmonitor roles.

An example security configuration for an administration target is in Example 11.10 on page 210.

ConventionsThe following conventions are recommended for management targets:

• target names are nouns.

• command names are verbs.

• target, command, and parameter names are all lower case.

• single word target, command, and parameter names are preferred.

• there are no spaces, or underscores, used in multi-word target, command, or parameter names.

• most targets define a display command which returns tabular data describing the target's state.

Target lifecycleA management target must be registered before it is available for use. It should be unregisteredwhen the target is no longer needed. Generally all management targets should be registered whenan application starts and be unregistered when the application exits.

A new target object instance is created by the management framework for each command invocation.This allows asynchronous commands to store command state in fields in the target. The target objectinstance is destroyed by the management framework when the command completes.

ExampleThis is a complete example of a management target implementation. The example consists of thesefiles:

205

Defining a system management target

Page 220: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• AnEnum.java - definition of an enumeration used as a parameter.

• ExampleTarget.java - target implementation.

• ExampleMain.java - driver to execute example target.

• ExampleTargetLifecycle.java - initialize and terminate the example target.

• exampletargetsecurity.kcs - security definition for example target.

Example 11.6. AnEnum.java// $Revision: 1.2 $

package com.kabira.snippets.management;

/** * A simple enum for the example target */public enum AnEnum{ /** * for the money */ One, /** * for the show */ Two, /** * to get ready */ Three, /** * to go! */ Four};

Example 11.7. ExampleTarget.java// $Revision: 1.6 $

package com.kabira.snippets.management;

import com.kabira.platform.management.Command;import com.kabira.platform.management.Default;import com.kabira.platform.management.Parameter;import com.kabira.platform.management.Target;import com.kabira.platform.management.ManagementTarget;import com.kabira.platform.management.TargetError;

/** * An example of an management target */@ManagementTarget( name = "exampletarget", description = "example management target")public class ExampleTarget extends Target{ /** * example display command. return a simple table of data. * @throws TargetError */

206

Chapter 11. System management

Page 221: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

@Command public void display() throws TargetError {

String[] names = { "Who", "Where", "What" }; setColumnNames(names);

String[] row = { "Colonel Mustard", "Library", "Candlestick" }; addRow(row);

commandComplete(); }

/** * example of command which fails. Transactions are committed when * commandFailed is called. */ @Command public void setstate() { commandFailed("setstate not supported"); }

/** * * example of command which throws an exception. If an exception is thrown, * the command fails, and the transaction is aborted. * @throws Exception */ @Command public void rollbackexample() throws Exception { throw new Exception("transaction will roll back"); }

/** * Example of Parameter annotations * * @param version required String parameter * @param count optional Integer parameter with default value * @param enum123 optional Enum parameter with default value * @param aBool optional Boolean parameter with default value * @param aFloat optional Float parameter with default value */ @Command public void examplecommand( @Parameter(name = "version", description = "version number", required = true) String version, @Parameter(name = "count", description = "number to display", defaultValue = @Default(value = "1")) Integer count, @Parameter(name = "enum123", description = "Pick One Two or Three", defaultValue = @Default(value = "One")) AnEnum enum123, @Parameter(name = "abool", defaultValue = @Default(value = "true")) Boolean aBool,

@Parameter(name = "afloat", defaultValue = @Default(value = "123.456")) Float aFloat) {

commandComplete(); }

207

Defining a system management target

Page 222: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

/** * Asynchronous command example. asyncCommand() starts the command. * @throws TargetError */ @Command public void asynccommand() throws TargetError { String[] names = { "elapsed time" }; setColumnNames(names); long now = System.currentTimeMillis(); }

/** * complete an asynchronous command. Note that this method must be called * with a valid transaction. */ void asyncCommandComplete() throws TargetError { long elapsedTime = System.currentTimeMillis() - asyncStartTime; String[] row = { Long.toString(elapsedTime) }; addRow(row); commandComplete(); } long asyncStartTime;}

Example 11.8. ExampleMain.java// $Revision: 1.5 $

package com.kabira.snippets.management;

import com.kabira.test.management.Client;import com.kabira.test.management.CommandFailed;

import java.util.HashMap;

/** * Execute example target * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class ExampleMain{

/** * @param args None supported * @throws CommandFailed Command execution failed */ public static void main(String[] args) throws CommandFailed { // // Initialize target // ExampleTargetLifecycle.register();

//

208

Chapter 11. System management

Page 223: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// Create test client // Client client = new Client("guest", "guest");

// // Execute help on the target // String[] results = client.runCommand("help", ExampleTargetLifecycle.Name, null);

// // Display results // for (String s : results) { System.out.println(s); }

// // Execute display // results = client.runCommand("display", ExampleTargetLifecycle.Name, null);

// // Display results // for (String s : results) { System.out.println(s); }

// // Execute examplecommand // HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put("version", "1.0"); parameters.put("count", "100"); parameters.put("enum123", "Three"); parameters.put("abool", "true"); parameters.put("afloat", "3.75"); results = client.runCommand("examplecommand", ExampleTargetLifecycle.Name, parameters);

// // Terminate target // ExampleTargetLifecycle.unregister(); }}

Example 11.9. ExampleTargetLifecycle.java// $Revision: 1.5 $

package com.kabira.snippets.management;

import com.kabira.platform.management.Target;import com.kabira.platform.Transaction;

/** * Example target life-cycle implementation */public class ExampleTargetLifecycle{ /** * Target name

209

Defining a system management target

Page 224: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

*/ public final static String Name = "exampletarget";

/** * Register MyTarget management target */ public static void register() { new Transaction("Register Target") {

@Override protected void run() throws Rollback { Target.register(ExampleTarget.class); } }.execute();

}

/** * Un-register MyTarget management target */ public static void unregister() { new Transaction("Un-register Target") {

@Override protected void run() throws Rollback { Target.unregister(Name); } }.execute(); }}

Example 11.10. exampletargetsecurity.kcs// $Revision: 1.5 $

configuration "exampletargetsecurity" version "1" type "security"{ configure security { configure AccessControl { // // this rule locks all elements in // ExampleTargetCommand to prevent unauthenticated // access, and then grants full access to all // elements in the command to the "switchadmin" role. // Rule { name = "com.kabira.platform.management.ExampleTarget"; lockAllElements = true; accessRules = { { roleName = "switchadmin"; permission = AccessAllOperationsAndAttributes; } }; };

210

Chapter 11. System management

Page 225: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // the remaining rules grant access to specific // operations to the "switchmonitor" role: // Rule { name = "com.kabira.platform.management.ExampleTarget.examplecommand"; accessRules = { { roleName = "switchmonitor"; permission = Execute; } }; }; }; };};

When main is executed the following is output (annotation added):

Example 11.11. Example Target Output

## Output from help command#[primary] valid commands and parameters for target "exampletarget":[primary] [primary] display exampletarget[primary] [primary] examplecommand exampletarget[primary] version=<String>[primary] version number[primary] [primary] [ count=<Integer, default = 1> ][primary] number to display[primary] [primary] [ enum123=<AnEnum, default = One> ][primary] Pick One Two or Three[primary] [primary] [ abool=<Boolean, default = true> ][primary] [primary] [ afloat=<Float, default = 123.456> ][primary] [primary] [primary] setstate exampletarget[primary] [primary] rollbackexample exampletarget[primary] [primary] asynccommand exampletarget[primary] [primary] [primary] Description:[primary] [primary] example management target

## Output from display command#[primary] Who Where What[primary] Colonel Mustard Library Candlestick

211

Defining a system management target

Page 226: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

LoggingThe Fluency log handler removes all log handlers installed by the JVM at initialization. It executescode like the following to perform this:

Logger log = Logger.getLogger(""); Handler[] hlist = log.getHandlers();

for (Handler h : hlist) { log.removeHandler(h); } log.addHandler(new com.kabira.platform.logging.Handler());

Removing this handler from the root logger will disable logging to the node log file.

Example 11.12 on page 212 shows an example of writing log messages that use the Fluency defaultlog handler.

The .level property in the java.util.logging properties file may have to beupdated to display all severity levels. For example:

# Default global logging level.# This specifies which kinds of events are logged across# all loggers. For any given facility this global level# can be overriden by a facility specific level# Note that the ConsoleHandler also has a separate level# setting to limit messages printed to the console.#.level= INFO## Enable all log levels.level= ALL

Example 11.12. Logging example// $Revision: 1.1 $

package com.kabira.snippets.management;

import java.util.logging.Logger;

/** * Simple use of Fluency logger * * This snippet writes messages to the Fluency logger. * * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Logging{ public static void main(String [] args) { // // Get the global logger // Logger logger = Logger.getLogger("");

logger.severe("this is a severe message");

212

Chapter 11. System management

Page 227: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

logger.warning("this is a warning message"); logger.info("this is an info message"); logger.fine("this is a debug message"); } }

When this example is run the node log file on the primary node contains the following messages:

Example 11.13. Node log file messages

01-30 11:48:58|event::Severity::Error|com.kabira.platform.logging.EventService:2 (919571:2902264:2001:2 offset 59679576)|1203:36|Error| Jan 30, 2010 11:48:56 AM com.kabira.snippets.management.Logging main SEVERE: this is a severe message

01-30 11:48:58|event::Severity::Warning|com.kabira.platform.logging.EventService:2 (919571:2902264:2001:2 offset 59679576)|1203:37|Warning| Jan 30, 2010 11:48:58 AM com.kabira.snippets.management.Logging main WARNING: this is a warning message

01-30 11:48:58|event::Severity::Info|com.kabira.platform.logging.EventService:2 (919571:2902264:2001:2 offset 59679576)|1203:38|Info| Jan 30, 2010 11:48:58 AM com.kabira.snippets.management.Logging main INFO: this is an info message

Notice that the fine message is not written to the log file because debug messages have not beenenabled.

213

Logging

Page 228: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

214

Page 229: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

12Monitoring applications

This chapter describes how to monitor Fluency applications for development. All of the material inthis chapter assumes you are using the Development Appliance described in the section called“Development appliance” on page 230.

Management consoleThe management console - Kabira Manager - is used to control and monitor Fluency nodes. Thefollowing steps must be taken to start monitoring the Fluency development server environment.

1. Connect to the URL on the VMWare image start-up screen with a Web Browser.

2. Log into the management console using a username of guest and a password of guest.

The sections below show these steps in more detail.

Management console loginThe initial screen displayed when navigating to the Kabira Manager URL is:

215

Page 230: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 12.1. Manager login screen

Following a successful login and selecting an application node, this screen is displayed:

216

Chapter 12. Monitoring applications

Page 231: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 12.2. Node details display

Object monitorThe Object Monitor allows viewing of Managed Objects in shared memory. The Object Monitorcan be accessed for all application nodes from the Development Appliance information screen ac-cessed from the Development Appliance Welcome Page.

217

Object monitor

Page 232: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Figure 12.3. Object Monitor access from Development Applianceinformation screen

EventsFluency nodes generate events for exceptional conditions. These events are available in:

• Node log files. See the section called “Logs directory” on page 231.

• Domain Manager event cache

• Domain Manager event monitor

No matter where events are viewed, they have the same content:

• Time Stamp - time event occurred

• Event Topic - topic on which event was published

• Event Identifier - unique event identifier

• Event Originator - a unique identifier for the event originator

• Message - a textual message

218

Chapter 12. Monitoring applications

Page 233: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

In addition, events displayed from the Domain Manager event cache or monitor also contain thenode name that generated the event. Here is a example event displayed in the Domain Managerevent monitor:

Node Name = primaryDate Time = 2008-09-10 12:57:38 Event Topic = kabira.kts.security Event Identifier = switchadmin::EventIdentifiers::OperatorActionSucceeded Event Originator = switchadmin::PluginServiceImpl:1 (344579:8358104:7100:1 offset 67017096)

Message = Administrator command [display] on target [security] executed by principal [guest] succeeded.

Domain manager event cacheThe Domain Manager event cache provides a historical cache of all events raised by nodes beingmanaged by a domain manager. The event cache supports the following filters:

• Node Name - only show events for a specific node.

• Event Topic - only show events for a specific event topic.

• Event Identifier - only show events with a specific event identifier.

• Event Originator - only show events from a specific originator

• Contains - only show events that contain a specific phrase.

• Start Time to End Time Range - only show events between specific start and end times. The endtime can be omitted to show all events from a specific start time.

The screen below shows how to access the Event Cache.

Figure 12.4. Event cache

219

Events

Page 234: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Domain Manager Event MonitorThe Domain Manager Event Monitor displays events real time as they occur. The screen belowshows how to access the Event Monitor.

Figure 12.5. Accessing event monitor

The Event Monitor button will bring up a screen that looks like:

Figure 12.6. Event monitor display

220

Chapter 12. Monitoring applications

Page 235: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

13Reference

Fluency ships with a deployment tool that is used during development to deploy applications toFluency nodes. The deployment tool can be used from the command line or via a Java IDE.

Deployment toolThe Fluency deployment tool is named fluency.jar.

The general syntax for using the deployment tool is:

java [local JVM options] -jar fluency.jar [options] <target> [application parameters]java [local JVM options] -jar fluency.jar [options] helpjava [local JVM options] -jar fluency.jar [options] display services

fluency.jar must be specified as the first -jar option. This ensures that the Fluency deploymenttool gets control during the execution of the application and manages execution and debugging ofthe application on a Fluency node.

Attempting to execute an application that uses Fluency classes without specifying thefluency.jar file as the first -jar option will cause a Java stack dump (example below) becausethe Fluency classes cannot execute outside of a Fluency JVM:

Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.langat java.lang.ClassLoader.preDefineClass(ClassLoader.java:479)at java.lang.ClassLoader.defineClass(ClassLoader.java:614)at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)at java.net.URLClassLoader.access$100(URLClassLoader.java:56)at java.net.URLClassLoader$1.run(URLClassLoader.java:195)at java.security.AccessController.doPrivileged(Native Method)at java.net.URLClassLoader.findClass(URLClassLoader.java:188)at java.lang.ClassLoader.loadClass(ClassLoader.java:306)at sun.misc.Launcher.loadClass(Launcher.java:268)at java.lang.ClassLoader.loadClass(ClassLoader.java:251)at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)at pojopersistent.Main.main(Main.java:23)

221

Page 236: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

[local JVM options] is used to pass options to the local JVM. These options are specific tothe version of the local JVM.

[options] consists of any combination of JVM options or Fluency options. The Fluency JVMsupports the same options as the Sun Java SE 6 JVM plus Fluency specific JVM options (See thesection called “JVM properties” on page 227). See ht-tp://java.sun.com/javase/6/docs/technotes/tools/windows/java.html. JVMoptions are prefixed with a "-", while Fluency options are of the form name = value.

<target> is the application jar file or class that will be executed on the Fluency node.

[application parameters] are application specific parameters that are passed to the applic-ation program's main.

The help command displays the usage message.

The display services command is used to query MDNS service discovery for Fluency serviceson the network.

The display services command only works if MDNS service discovery is configuredon the local machine.

Table 13.1 on page 222 summarizes the supported deployment tool options:

Table 13.1. Deployment tool options

DescriptionOption

The administration port of the Fluency node that should be used to run theapplication.

adminport

This option species the type of binaries used by the JVM. The valid valuesare PRODUCTION or DEVELOPMENT. If not specified, the JVM will use thesame binary type as the node it runs in.

buildtype

An enumeration indicating the level of diagnostic output. The valid valuesare enable - a high level description of the deployment tool activity,

debug

verbose - detailed description of deployment tool activity, or none - nodiagnostic output. (default: none).

A boolean flag indicating whether the deployment tool will wait for the ap-plication to terminate (false), or simply exit once the application is started(true). The default value is false.

detach

A boolean flag indicating whether the 'display services' command outputshould contain detailed results (default: false).

detailed

A boolean flag indicating whether the Fluency version information shouldbe displayed (default: true).

displayversion

The name of the domain that the application is to run on. When this optionis used, the deployment tool must connect to a Kabira Domain Manager

domainname

node which is managing the given domain. The application will execute onall nodes in the domain.

The name of the domain group that the application is to run on. When thisoption is used, the deployment tool must connect to a Kabira Domain

domaingroup

Manager node which is managing the given domain group. The applicationwill execute on all nodes in the domain group.

222

Chapter 13. Reference

Page 237: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The name of the domain node that the application is to run on. When thisoption is used, the deployment tool must connect to a Kabira Domain

domainnode

Manager node which is managing the given domain node. The applicationwill execute on the specified node.

Control multi-node completion behavior. A value of true causes the de-ployment tool to return to the caller when any node returns a non-zero exit

exitonfailure

code. A value of false causes the deployment tool to not return until allnodes exit. (default: false).

The host name hosting the Fluency node that should be used to run theapplication (default: localhost).

hostname

The number of seconds that the Fluency node should wait before terminat-ing a deployed application when connectivity between the Fluency nodeand the deploy tool is lost (default: 10 seconds).

keepaliveseconds

A boolean flag that controls whether generated artifacts (e.g. deploymentspecification) to start a JVM are removed when the JVM exits. A value of

nodecleanup

true removes all generated artifacts, a value of false does not. (default:true).

The password to use when authenticating username during the connectionto the Fluency node.

password

If true, require the JVM hosting the application to enable remote debug-ging (default: false for PRODUCTION nodes, true for DEVELOPMENTnodes).

remotedebug

The debugger agent port, to be used by the JVM to listen for remote debug-ger clients (default: randomly chosen by the JVM).

remotedebugport

This option, when given a value of true, requests that all Java objects andany changed type definitions on the node be deleted before the application

reset

begins execution. If there is a JVM already running an error will be reportedand the new JVM will fail to start. (default: true).

Control server diagnostics. An enumeration value that has one of the fol-lowing values: enable or none. A value of enable causes additional

serverdebug

server debug tracing. A value of none disables server debug tracing. Defaultvalue is none.

The service name of the Fluency node that is to be used to run the applica-tion. This option may be used instead of adminport and hostname. This

servicename

option only works if MDNS service discovery is configured on the localmachine.

If true, require the JVM to suspend execution before main() is calledduring remote debugging. This option only applies if remotedebug=trueis specified (default: false).

suspend

The number of seconds to wait while resolving servicename with MDNS(default: 10).

timeout

The user name to use when connecting to a Fluency node. The specifiedvalue must identify a principal with administrative privileges on the node.

username

Defaults to the user.name system property, which is set to be the UIDof the user who executed the deployment tool client JVM.

The X509 certificate keystore file to use for authentication. If given, thepassword parameter is required, and should be the keystore password.

x509credential

223

Deployment tool

Page 238: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

The alias of the user's X509 certificate in the keystore specified by thex509credential option (default: mykey).

x509creden-tialalias

ResetThe reset option provides development support for changing the shape of Managed Objects inshared memory. It has no affect on non-managed Java objects.

The reset option should only be used during development. It should never be used ona production system.

The reset option only affects the node on which it was executed. To reset types in adistributed or highly available environment, the same reset option value must be executedon all nodes.

Examples of changing the shape of a Managed Objects are:

• adding a field to a class

• removing a field from a class

• changing the type of a field in a class

• changing the inheritance hierarchy

Fluency detects when the shape of a Managed Object changes and fails the load of the changedclass definition if reset = false.

For example, if Example 13.1 on page 224 is run twice - once with m_string not commented out,and then again with m_string commented out:

Example 13.1. Type change// $Revision: 1.8 $

package com.kabira.snippets.reference;

import com.kabira.platform.Transaction;import com.kabira.platform.annotation.Managed;

/** * Snippet used to demonstrate changing the shape of a class * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class Shape{ /** * A managed object */ @Managed public static class ShapeChange { private int m_int; // // Uncomment this field after running once to see // type conflict

224

Chapter 13. Reference

Page 239: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // private String m_string; }

/** * Main entry point * @param args Not used */ public static void main(String args[]) { new Transaction("Create Object") { @Override protected void run() throws Rollback { new ShapeChange(); } }.execute(); }}

On the second run, the following exception is thrown:

Example 13.2. Type change - second run output[primary] Java main class programming.fluency.reference.Shape.main exited with an exception.[primary] Java exception occurred: Audit of class [programming.fluency.reference.ShapeChange] failed: Type did not match. New type name programming.fluency.reference.ShapeChange - existing type name programming.fluency.reference.ShapeChange. Changed values :numberSlots:objectSize:; the class will not be loaded.[primary] at com.kabira.platform.classloader.ClassLoader.createKTPTypeDescriptor (Native Method)[primary] at com.kabira.platform.classloader.ClassLoader.defineManagedClass (ClassLoader.java:642)[primary] at com.kabira.platform.classloader.ClassLoader.findClass(ClassLoader.java:302)[primary] at com.kabira.platform.classloader.ClassLoader.loadClass(ClassLoader.java:228)[primary] at java.lang.ClassLoader.loadClass(ClassLoader.java:251)[primary] at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)[primary] at programming.fluency.reference.Shape.run(Shape.java:37)[primary] at com.kabira.platform.Transaction.execute(Transaction.java:132)[primary] at programming.fluency.reference.Shape.main(Shape.java:31)INFO: Application [programming.fluency.reference.Shape6] running on node [primary] exited with status [-1]INFO: Run of distributed application [programming.fluency.reference.Shape6] complete.

Setting reset = true (the default value) will avoid this exception.

When an application is executed with reset = true the following happens:

1. All Managed Objects in shared memory are deleted

2. If the type definition of a Managed Object changed it is removed.

3. The type definition of the Managed Object was removed it is recreated using the new classdefinition.

Attempting to use reset = true if there is already a JVM running will cause the JVM that isbeing started to fail with an error message. To start a second JVM the reset option must be setto false.

225

Deployment tool

Page 240: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Highly available and distributed systems  When Replicated, Mirrored, or DistributedManaged Objects are used in an application, the type definition for these classes are pushed to allnodes in a cluster. To ensure that the type definitions stay consistent on all nodes, the same valuefor the reset option must be sent to all nodes. This is accomplished using the Distributed Devel-opment features as described in Chapter 3.

Using inconsistent values for the reset option on nodes in a cluster will cause application failuresbecause of the inconsistent type definitions on the nodes. The cluster must be restarted to resolvethis problem.

SSL Trust ManagerThe Fluency deployment tool always uses SSL connections to Fluency nodes. This requires an SSLTrustManagerFactory algorithm that supports storage and management of X.509v3 credentials.By default the SunX509 TrustManagerFactory is used. If that TrustManagerFactory al-gorithm is not supported in the JRE being used to execute the deployment tool, an alternative al-gorithm can be specified using the ssl.TrustManagerFactory.algorithm JVM systemproperty.

The algorithm specified using the above property must reference a TrustManagerFactory whichsupports storage and management of X.509v3 credentials and is provided by the JRE being used.

Configuring default optionsWhen the Fluency deployment tool is executed it looks for the following file:

<user home directory>/.fluency/options

If this file exists, any deployment tool command line options in the options file are used. Commandline options specified in the options file have the same affect as the same command line optionspecified on the command line.

Options on the command line override the same option in the options file. For example if thecommand line contains -jar fluency.jar debug=true and the options file contains debug= false, a debug value of true is used for the application execution.

The options file must follow the format below.

## Any line starting with '#' is ignored## Each option is specified on a separate line, as follows:#<fluency option name> = <fluency option value>[newline]

For example, the following options file would set up the default username and password for usewith the Fluency development nodes:

## Username and password for Fluency development nodes#username = guestpassword = guest

226

Chapter 13. Reference

Page 241: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Default JVM propertiesThe options file also supports defining default JVM properties for the Fluency JVM. Default FluencyJVM properties are specified using the jvmoptions option name. Here is an example of using thejvmoptions option.

## Username and password for Fluency development nodes#username = guestpassword = guest

## Default JVM options#jvmoptions = -Duser.name=fred -Duser.country=US

JVM propertiesThe Fluency JVM supports these Fluency specific properties in addition to all of the existing SunJVM properties.

Table 13.2. Fluency JVM Properties

DescriptionOption

A string property. The location of the application classes on theFluency node. These application classes were copied to the Fluency

com.kabira.applica-tion.class.path

node by the deployment tool. This property is initialized by Flu-ency.

A boolean property. Control whether components are loaded atJVM startup. A value of true loads all configured components. A

com.kabira.platform.com-ponent.manager

value of false disables the loading of components at startup. Thedefault value is true.

Control whether JMX is initialized at JVM startup. A value of trueinitializes JMX. A value of false disables the initialization of JMXat startup. The default value is true.

com.kabira.platform.man-agement.jmxEnable

A numeric property. The administration listener port for the Flu-ency node. This property is initialized by Fluency.

com.kabira.platform.man-agement.port

A boolean property. When set to true causes the Fluency classloader to create a class file in the node directory for each classmodified at load time. The default value is false.

com.kabira.platform.de-bugClasses

An optional string property. A list of package names (or packageprefixes), separated by the system path separator character (nor-

com.kabira.platform.ig-noredPackages

mally ":"). The Fluency class loader will skip byte code rewritingfor all classes that match an ignored package prefix. None of theseclasses can contain Managed Object definitions or references toManaged Objects.

An optional string property. A list of package names, separated bythe system path separator character (normally ":"). These packages

com.kabira.platform.sys-temPackages

are defined as system packages. Classes contained in these pack-ages will always be loaded by the parent of the Fluency classloader.

227

Configuring default options

Page 242: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Deployment tool exampleExample 13.3 on page 228 shows how to execute a simple Java program using the Fluency DeploymentTool from the command line.

Example 13.3. Deployment tool example// $Revision: 1.4 $

package com.kabira.snippets.reference;

/** * Simple hello world snippet * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class HelloWorld{ /** * Main entry point * @param args Not used */ public static void main(String args[]) { System.out.println("Hello World"); }}

## NOTE: Remove the package statement from the HelloWorld.java snippet above# to work with the example steps below.#

## Compile the program using the native javac on the host machine#javac HelloWorld.java

## Excute the program against a Fluency node - assumes fluency.jar is in local directory*java -jar fluency.jar hostname=192.168.1.128 adminport=2001 \ username=guest password=guest HelloWorld

## The output from the command#INFO: fluency.jar version: [core_linux081117]INFO: node version: [core_linux081117]Hello World

Debugging exampleExample 13.4 on page 229 shows how to attach the Java debugger to an application running on Flu-ency.

228

Chapter 13. Reference

Page 243: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Example 13.4. Debugging example// $Revision: 1.4 $

package com.kabira.snippets.reference;

/** * Simple hello world snippet * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */public class HelloWorld{ /** * Main entry point * @param args Not used */ public static void main(String args[]) { System.out.println("Hello World"); }}

## NOTE: Remove the package statement from the HelloWorld.java snippet above# to work with the example steps below.#

## Compile the program using the native javac on the host machine#javac HelloWorld.java

## Excute the program against a Fluency node - assumes fluency.jar is in the local directory# Notice that suspend=true is set on the command line to suspend main until the# debugger attaches.##java -jar fluency.jar hostname=192.168.1.128 adminport=2001 \ username=guest password=guest suspend=true remotedebug=true HelloWorld

## The output from the Fluency node - the above command blocks waiting for the# debugger to attach.#INFO: fluency.jar version: [core_linux081108]INFO: JVM remote debugger agent running on [192.168.1.128:45871] ...INFO: node version: [core_linux081108]INFO: Running with suspend=true - the application will suspend execution before main() is called ...Listening for transport dt_socket at address: 45871

## Execute jdb in another window using -connect to connect to the Fluency node## NOTE: The port number is obtained from the above output.#jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.1.128,port=45871

## Output from jdb command - enter cont at the prompt

229

Debugging example

Page 244: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

#Set uncaught java.lang.ThrowableSet deferred uncaught java.lang.ThrowableInitializing jdb ...> VM Started: No frames on the current call stack

main[1] cont

## Output in jdb window after cont#> The application exited

## Output in java window after cont.#Hello World

Development applianceThe Fluency SDK ships with a VMWare image that contains a complete Fluency server developmentenvironment known as the Fluency Development Appliance. The development appliance has thesenodes installed and configured:

• primary - Fluency application node

• backup - Fluency application node

• replica - Fluency application node

• domainmanager - Distributed domain management

When the VMWare image is started all of these nodes are automatically started and configured. Torestart the server development appliance, the VMWare image should be powered off and back on.This will restore all nodes to their default configuration.

The server development appliance is reset to its default state when the VMWare imageis restarted. Any modifications made to the server are discarded.

DirectoriesAll user-visible directories on the development appliance are remotely mountable using SMB. Thedirectories are:

• configuration - default configuration files

• deploy - user deployment directory for JAR and class files

• logs - event, console, and change log files

• nodes - node directories

Configuration directory  The configuration directory contains the following configurationfiles:

230

Chapter 13. Reference

Page 245: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

• default node configuration files

The structure of the configuration directory is:

configuration/<node name>

Deploy directory  The deploy directory provides a location for installing JAR or class files onthe server. When a JVM is started on an application node, any JAR or class files in this directoryare automatically added to the JVM's class path. The JAR files are sorted in ascending ASCII orderby name before being added to the JVM's class path.

This provides a simple mechanism for installing software on the server that is visible to the applic-ation nodes configured in the server development appliance.

Application start-up times can be significantly improved by using the deploy directoryto avoid the overhead of transferring class files over the network from a client. It is stronglyrecommend that any frameworks be installed into the deploy directory.

Restarting the VMWare image removes the files in this directory.

Logs directory  The logs directory contains the following log files:

• node specific event logs

• console log

• node specific console logs

• change logs

The node specific event logs use the following naming convention:

## nodename - node name generating log file# mmdd - month/day stamp# count - number of files created on same date#<nodename>_<mmdd>_<count>.log

The console log is named console.log. It contains the output captured during application startup.

The node specific console logs are named <nodename>.log. They contain the installation andstartup output for the individual nodes.

Change logs are located in the changelogs directory in the logs directory. They use the followingnaming convention:

## In Progress Files## nodename - node name generating change log file# mmdd - month/day stamp# count - number of files created on same date

changelogs/<nodename>/<mmdd>_<count>.xml

## Completed Files#

231

Development appliance

Page 246: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

# nodename - node name generating change log file# originalname - original name of file# count - number of files created on same date

changelogs/<nodename>/complete/<originalname>.xml_<count>

Nodes directory  The nodes directory contains the runtime files associated with active nodes.Each active node is in a separate sub-directory. This directory contains the shared memory filesassociated with a node and low-level log files that may be useful for debugging problems.

CustomizationThe development appliance can be customized by:

1. Enabling shared folders in VMWare

2. Create a kabira.env file in the Kabira-Server/share directory located in the FluencySDK.

The supported properties in the kabira.env file are summarized in Table 13.3 on page 232.

Table 13.3. Development appliance customization properties

DescriptionProperty

Controls whether nodes are started in production or development mode. Valid valuesare PRODUCTION or DEVELOPMENT. Default value is DEVELOPMENT.

BuildType

Default configurationThis is the default configuration information loaded into the Development Appliance.

This is the default high-availability configuration.

Example 13.5. Default high availability configuration//// Name// ha.kcs//// Copyright// Confidential Property of Kabira Technologies, Inc.// Copyright 2008, 2010 by Kabira Technologies, Inc.// All rights reserved//// History// $Source: /opt/cvs-ps/fluency/external/vmware-config/ha.kcs,v $// $Revision: 1.3.2.2 $ $Date: 2010/08/24 21:15:55 $//configuration "ha" version "1.0" type "ha"{ configure ha { // // Configure a primary, backup, and replica node // NodeConfiguration { name = "primary"; }; NodeConfiguration { name = "backup"; }; NodeConfiguration { name = "replica"; };

232

Chapter 13. Reference

Page 247: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// // Define default Fluency partition // PartitionConfiguration { name = "fluency"; group = "fluency"; primaryNodeName = "primary"; backupNodeName = "backup"; minimumNumber = 0; maximumNumber = 100; changeLogScope = LogBoth;

fileNameTemplate = "../../logs/changelogs/%nodeName/%m%d_%count.xml"; fileOpenMode = Append; directoryCreateMode = "0755"; fileCreateMode = "0666"; rolloverBySize = Disabled; rolloverSizeBytes = 0; rolloverByInterval = Disabled; rolloverIntervalSeconds = 0; rolloverByNumRecords = Enabled; rolloverNumRecords = 1000; renameOnClose = Enabled; renameTemplate = "../../logs/changelogs/%nodeName/complete/%m%d_%count.xml";

// Do not change loggingMode and transactionalLogger // (FLUENCY-2505). loggingMode = Asynchronous; transactionalLogger = Disabled; fileSyncMode = Unsynchronized; };

// // Define a partition for each node in the HA cluster // PartitionConfiguration { name = "primary"; group = "primary"; primaryNodeName = "primary"; backupNodeName = "backup"; minimumNumber = 0; maximumNumber = 100; };

PartitionConfiguration { name = "backup"; group = "backup"; primaryNodeName = "backup"; backupNodeName = "replica"; minimumNumber = 0; maximumNumber = 100; };

PartitionConfiguration { name = "replica"; group = "replica"; primaryNodeName = "replica"; backupNodeName = "primary"; minimumNumber = 0; maximumNumber = 100; }; };};

233

Development appliance

Page 248: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

This is the default security configuration.

Example 13.6. Default security configuration// Name// $RCSfile: security.kcs,v $//// Copyright// Confidential Property of Kabira Technologies, Inc.// Copyright 2010 by Kabira Technologies, Inc.// All rights reserved.//// History// $Revision: 1.1 $ $Date: 2010/02/26 22:17:47 $// $Source: /opt/cvs-ps/fluency/application/config/applicationconfig/security.kcs,v $//// Description// Default Fluency principal//configuration "users" version "1.0" type "security" { configure security { configure Principals { Principal { name = "guest"; textCredential = "guest";

roles = { "switchadmin", "nodeAdmin" }; }; }; }; };

This is the default domain configuration.

Example 13.7. Default domain configuration// Name// kdm.kcs//// Copyright// Confidential Property of Kabira Technologies, Inc.// Copyright 2008, 2010 by Kabira Technologies, Inc.// All rights reserved.//// History// $Revision: 1.5 $ $Date: 2010/03/31 00:20:22 $// $Source: /opt/cvs-ps/fluency/external/vmware-config/kdm.kcs,v $//// Description// Domain manager configuration for the Fluency vmware image.//configuration "kdm" version "2.0" type "kdm"{ configure kdm { DomainConfig

234

Chapter 13. Reference

Page 249: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

{ // // Domain name // domainName = "Kabira Development";

// // The number of seconds between retrying // queued configuration commands following a // failure. // retryIntervalSeconds = 5;

// // Disable auto-join // enableAutoJoin = false;

// // Add the configured nodes to the domain. Node // configuration is generated by fluency-server.env // nodeConfiguration = { NODE_CONFIGURATION };

// // Optional configuration for managed nodes // defaultNodeConfiguration = { };

// // Configure the Application Cluster group // groupConfiguration = { { name = "Application Cluster"; properties = ""; defaultNodeConfiguration = { }; } }; }; };

configure switchadmin { configure Node { Description { defaultDescription = "Fluency Domain Manager"; properties = { }; }; }; };};

This is the default node configuration.

Example 13.8. Default node configuration// Name// $RCSfile: node.kcs,v $//

235

Development appliance

Page 250: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

// History// $Source: /opt/cvs-ps/fluency/external/vmware-config/node.kcs,v $// $Revision: 1.2 $ $Date: 2010/01/22 21:16:07 $//// Description// Node configuration for fluency development nodes//configuration "nodeconfig" version "1.0" type "nodeconfig"{ configure switchadmin { configure Node { // // Default description for application node // Description { defaultDescription = "Fluency Development"; properties = { }; }; }; };};

Java Debug Wire ProtocolThe Java Debug Wire Protocol (JDWP) is used to integrate debugging tools. JDWP was updatedto support transactions. The transaction support makes assumptions on how a debugger clientmanipulates threads. These assumptions may not be true for all clients. In this case, the wrongtransaction, or worse a committed transaction, may be used by the JDWP in the Fluency JVM. Thiswill cause unpredictable results when debugging an application.

A property was added to enable and disable JDWP transaction support.

-Djava.jdwp.transaction=[true|false]

The default value of the java.jdwp.transaction property is true. Debugger clients who ex-perience problems with JDWP when debugging transactional threads should change the value ofthis property to false.

vmOptions = "-Djava.jdwp.transaction=false ...";

Once disabled, transactional access to Managed Object fields from a debugger client will only reportthe contents of the Java proxy instance, not the backing shared memory.

Class resolutionThe Fluency Class Loader uses multiple mechanisms to resolve a class reference. These mechanismsare searched in the following order:

1. Fluency defined system CLASSPATH

2. JAR or Class files in deploy directory

3. Client side CLASSPATH definition

Once a class is resolved the search is terminated.

236

Chapter 13. Reference

Page 251: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Fluency defines a system CLASSPATH that cannot be changed.

The contents of the deploy directory are then searched to resolve class resolutions as described inthe section called “Deploy directory” on page 231.

Finally, the CLASSPATH specified to the deployment tool on the client is searched. All classes resolvedusing the client class path are sent over a network connection to the server. The client CLASSPATHis only available for class resolution if the detach option was not set to true when the deploymenttool was executed.

Client and server class paths are distinct. The client class path is never sent to the server.All resources in a client's class path that are in a shared file system visible to the serverare still sent to the server from the client if the resource is not also in the server's classpath.

Change log formatTable Table 13.4 on page 237 summarizes the format of the change log.

Table 13.4. Change log format

DescriptionXML Tag

Starts a change log. When a change log is closed, theending haChangeLog tag is added.

<haChangeLog>...</haChangeLog>

A single entry in a change log.<haChangeLogEntry>...</haChangeLo-gEntry>

One of created, updated, or deleted. This is the action onthe object that caused the change log to be written.

<recordType>...</recordType>

Sequential sequence number for all records written to asingle change log file. The sequence number is not resetwhen a change log file rolls over.

<sequenceNumber>...</sequenceNum-ber>

Commit time of transaction that wrote record to file.<timeStamp>...</timeStamp>

Object data<objectData>...</objectData>

The type name of the object.<typeName>...</typeName>

Distributed object reference. Can be used to uniquelyidentify an object instance.

<reference>...</reference>

A user specified field in an object.<attribute>...</attribute>

Field name.<name>...</name>

Either true or false. A value of true indicates that no valuehas been set in this field. A value of false indicates that thefield was set to a valid value.

<isnull>...</isnull>

The value contained in the field.<value>...</value>

A simple example and the change log file output is shown below.

Example 13.9. Change log// $Revision: 1.7 $

package com.kabira.snippets.reference;

237

Change log format

Page 252: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

import com.kabira.platform.Transaction;import com.kabira.platform.ManagedObject;import com.kabira.platform.ha.ReplicatedObject;

/** * Snippet to generate change log output * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = primary * </ul> */

public class ChangeLog extends Transaction{ /** * Replicated application object */ public static class MyObject extends ReplicatedObject { String stringValue; int intValue;

MyObject() { super ("fluency", 0); } }

/** * Control program execution */ public enum Action { /** * Create replicated objects */ CREATE, /** * Update replicated objects */ UPDATE, /** * Delete replicated objects */ DELETE }

private Action m_action; private MyObject m_r;

/** * Main entry point * @param args Not used */ public static void main(String args[]) { ChangeLog changeLog = new ChangeLog();

changeLog.m_action = Action.CREATE; changeLog.execute();

changeLog.m_action = Action.UPDATE; changeLog.execute();

238

Chapter 13. Reference

Page 253: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

changeLog.m_action = Action.DELETE; changeLog.execute(); }

/** * Transaction run method * @throws com.kabira.platform.Transaction.Rollback */ @Override protected void run() throws Rollback { if (m_action == Action.CREATE) { m_r = new MyObject(); m_r.intValue = 5; m_r.stringValue = "object created"; } else if (m_action == Action.UPDATE) { m_r.intValue = 10; m_r.stringValue = "object updated";

} else { assert ( m_action == Action.DELETE );

m_r.stringValue = "object deleted"; ManagedObject.delete(m_r); m_r = null; } }}

When Example 13.9 on page 237 is run the following is written to the change log.

There is no closing haChangeLog tag because the change log file was not closed.

Example 13.10. Change log output<?xml version="1.0" ?><haChangeLog> <haChangeLogEntry> <recordType>created</recordType> <sequenceNumber>0</sequenceNumber> <timeStamp>2008-09-19 12:47:26</timeStamp>

<objectData> <typeName>programming.fluency.reference.R</typeName> <reference>1030910:172528:7100:1</reference> <attribute> <name>m_flags</name> <isnull>true</isnull> </attribute> <attribute> <name>haKey</name> <isnull>false</isnull> <value>1030910:172528:7100:1</value> </attribute> <attribute> <name>partitionName</name> <isnull>false</isnull> <value>fluency</value> </attribute>

239

Change log format

Page 254: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

<attribute> <name>partitionGroup</name> <isnull>false</isnull> <value>fluency</value> </attribute> <attribute> <name>partitionNumber</name> <isnull>false</isnull> <value>0</value> </attribute> <attribute> <name>identifier</name> <isnull>false</isnull> <value></value> </attribute> <attribute> <name>stringValue</name> <isnull>false</isnull> <value>object created</value> </attribute> <attribute> <name>intValue</name> <isnull>false</isnull> <value>5</value> </attribute> </objectData> </haChangeLogEntry>

<haChangeLogEntry> <recordType>updated</recordType> <sequenceNumber>1</sequenceNumber> <timeStamp>2008-09-19 12:47:26</timeStamp>

<objectData> <typeName>programming.fluency.reference.R</typeName> <reference>1030910:172528:7100:1</reference> <attribute> <name>m_flags</name> <isnull>true</isnull> </attribute> <attribute> <name>haKey</name> <isnull>false</isnull> <value>1030910:172528:7100:1</value> </attribute> <attribute> <name>partitionName</name> <isnull>false</isnull> <value>fluency</value> </attribute> <attribute> <name>partitionGroup</name> <isnull>false</isnull> <value>fluency</value> </attribute> <attribute> <name>partitionNumber</name> <isnull>false</isnull> <value>0</value> </attribute> <attribute> <name>identifier</name> <isnull>false</isnull> <value></value> </attribute> <attribute> <name>stringValue</name>

240

Chapter 13. Reference

Page 255: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

<isnull>false</isnull> <value>object updated</value> </attribute> <attribute> <name>intValue</name> <isnull>false</isnull> <value>10</value> </attribute> </objectData> </haChangeLogEntry>

<haChangeLogEntry> <recordType>deleted</recordType> <sequenceNumber>2</sequenceNumber> <timeStamp>2008-09-19 12:47:26</timeStamp>

<objectData> <typeName>programming.fluency.reference.R</typeName> <reference>1030910:172528:7100:1</reference> <attribute> <name>m_flags</name> <isnull>true</isnull> </attribute> <attribute> <name>haKey</name> <isnull>false</isnull> <value>1030910:172528:7100:1</value> </attribute> <attribute> <name>partitionName</name> <isnull>false</isnull> <value>fluency</value> </attribute> <attribute> <name>partitionGroup</name> <isnull>false</isnull> <value>fluency</value> </attribute> <attribute> <name>partitionNumber</name> <isnull>false</isnull> <value>0</value> </attribute> <attribute> <name>identifier</name> <isnull>false</isnull> <value></value> </attribute> <attribute> <name>stringValue</name> <isnull>false</isnull> <value>object deleted</value> </attribute> <attribute> <name>intValue</name> <isnull>false</isnull> <value>10</value> </attribute> </objectData> </haChangeLogEntry>

241

Change log format

Page 256: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

242

Page 257: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

IndexSymbols@Command, 202@Default, 203@Isolation, 75@KeyField, 133@Managed, 103, 105@ManagementTarget, 202@Parameter, 203@Transactional, 73@TransactionalJavaObject, 74@TransctionalJavaObject, 79

Aabandoned transactions, 26abortTimeout, 55accessing data

and cache behavior, 21asynchronous updates and state conflict, 155configuration object life cycle, 177deferred updates, 35locking behavior, 85managed object life cycle, 107minimizing state conflicts, 156routing of update, 159synchronous and asynchronous updates, 22synchronous updates, 35transaction locks and, 13

active caching (see caching)active version, 182adminport, 222annotations, 103, 201

@Command, 202@Default, 203@Distributed, 139, 141-142@Isolation, 75@KeyField, 133@Managed, 103@ManagementTarget, 202@Parameter, 203@Transactional, 72-73@TransactionalJavaObject, 74auditing of, 76cache group, 20directed create, 20managed objects, 103system management, 201

application datadata loss exposure, 171partitioning, 163

routing of, 159applications

execution scope of, 52monitoring, 215

arrayslocal copy of, 134

asynchronous object creationcreates a separate transaction, 22duplicate key error and, 22

asynchronous updates, 22state conflict handling, 155

auditingof annotations, 76

authentication, 223

Bbackup node, 34backup policies

failure exposure and, 171buildtype, 222

Ccache groups, 20

cache policy should be "always", 21configuration and use, 145global extents for, 155incompatibility with directed create types, 20remote object reference and, 149specifying, 141

cache policyextents policy of always, 23specifying, 141

caching, 21policies, 21

change log, 6format, 237

class filesloading by deployment tool, 52

class loader, 236and annotation auditing, 76

class path, 236classes, 52

(see also class files)com.kabira.platform.Transaction, 67preloading, 231resolution, 236transactional, 72-83transactional properties, 73-74

clusters, 7code snippets, xivcom.kabira.platform.NoTransactionError exception,74com.kabira.platform.StateConflictError exception, 155

243

Page 258: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

com.kabira.platform.swbuiltin.TransactionNotifierclass, 93com.kabira.platform.Transaction class, 67commit, 13compensation, 93component, 6components, 43-48, 193-199

activation, 46configuration, 196deactivation, 47defining, 193kabira.properties, 193notifiers, 195

configuration, 39-43, 173-191active, 41active version, 182audit, 41base classes, 173ByGroupState key, 182class, 39date representation, 176default for development appliance, 232defining, 173defining type, 174directory on development appliance, 230inactive, 41life cycle, 40life cycle of, 177loaded, 41notifier, 40, 185notifiers, 42, 185object, 173objects, 40optional fields, 175removed, 41replacing, 41restrictions, 177states, 41supported types, 175type, 39version, 40-41

console (see Kabira Manager)constructors, 133creating and deleting objects, 22, 142

(see also asynchronous object creation)(see also directed create)and cache behavior, 21and partitions, 33and transaction isolation of extent, 110and transaction isolation of index, 121configuration object life cycle, 177directed create, 19-20extent not locked, 13invalid reference after delete, 108

locking behavior, 85managed object life cycle, 107state conflict during, 22

Ddata (see application data)deadlocks

and automatic transaction replay, 69and Java monitors, 90avoiding, 101detection, 14, 88eliminating distributed deadlocks, 156

debug, 222debugger, 54

example, 228remote debug port, 54

debugging, 54(see also debugger)enabling diagnostic output, 222enabling server diagnostics, 223JDWP support, 236log files, 232

default log handler, 49deferred updates, 35

data loss exposure and, 172deploy directory on development appliance, 231deployment tool, 51, 221-228

(see also fluency.jar)adminport, 222buildtype, 222debug, 222detach, 222, 237detached, 222displayversion, 222domaingroup, 222domainname, 222domainnode, 223exitonfailure, 223hostname, 223keepaliveseconds, 223nodecleanup, 223password, 223remotedebug, 223remotedebugport, 223reset, 223serverdebug, 223servicename, 223suspend, 223timeout, 223username, 223x509credential, 223x509credentialalias, 224

detach, 222

244

Index

Page 259: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

detailed, 222Development Appliance, 230

configuration, 230customization, 232default configuration, 232deploy directory, 231kabira.env, 232log file directory, 231nodes directory, 232user visible directories, 230

directed create, 20configuration and use, 143incompatibility with cache group types, 21remote object reference and, 149specifying, 142

discovery (see location discovery) (see service discov-ery)displayversion, 222distributed computing, 139-156

guidelines, 155distributed references, 18distributed transactions

transient network errors, 23distribution, 17-27

and transactions, 9(see also accessing data)

architecture of, 51-52developing applications with, 51-54managed objects, 17overview, 2, 6transaction deadlock timeout, 15

domainspecifying for fluency.jar, 222

domain groupspecifying for fluency.jar, 222

domain groups, 7executing applications on, 53

Domain Managernodes, domains, and the deployment tool, 52

domain managerevent cache, 219event monitor, 220

domain nodespecifying for fluency.jar, 223

domaingroup, 222domainname, 222domainnode, 223domains, 7

and the deployment tool, 52executing applications on, 53

Eerrors

due to inconsistent reset values, 226stack dump using non-Fluency JVM, 221

event monitor, 220events, 218

monitoring, 220type conflict transaction rollback, 20

exceptionscom.kabira.platform.NoTransactionError, 74com.kabira.platform.StateConflictError, 155java.lang.IllegalAccessError, 99java.lang.IllegalAccessException, 75java.lang.NullPointerException, 108java.lang.VirtualMachineError, 148Transaction.Rollback, 69, 93unhandled exception handling, 97unhandled exceptions terminate transactions, 69unhandled, JVM lifecycle and, 64

exit codenon-zero exit from unhandled exception, 64

exitonfailure, 223extents, 8, 109-115

and locking, 13cache groups and, 20cache policy of always, 23can return deleted object references, 112global extents for cache group, 155iteration and, 110, 112locking and isolation, 110

Ffailover

data routing and, 38ha timer behavior, 169

fieldsstatic fields not transactional, 80transaction isolation of, 75

Fluencydevelopment appliance, 230JVM, 1

Fluency nodes (see nodes)fluency.jar, 51, 221-228

(see also deployment tool)options, 222options file, 226syntax, 221

frameworkspreloading, 231

Ggarbage collection, 8

managed objects vs Java proxy objects, 108groupId

prohibited in configuration objects, 177

245

Page 260: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

HHA (see high availability)high availability, 29-39, 157-172

overview, 2states, 29timers, 168

hostname, 223

Iimplicit commit, 32

asynchronous, 33synchronous, 32

indexeslocking and isolation, 121

inheritanceand transactional behavior, 76-77illegal to relax inherited transaction requirement,76

isolation level (see transactions, isolation)

JJava classes (see classes)Java Debug Wire Protocol (see JDWP)Java monitors, 90

avoiding use of, 101Java Native Interface (see JNI)java.lang.IllegalAccessError exception, 99java.lang.IllegalAccessException exception, 75java.lang.NullPointerException exception, 108java.lang.reflect, 137java.lang.VirtualMachineError exception, 148java.util.Date, 106, 175

representation in a configuration file, 176JDWP, 236JNI, 100JVM

life cycle of, 55-65multiple JVMs in a transaction, 9operator shutdown, 58relationship to node, 7Runtime.getRuntime().exit(), 58shutdown hooks, 56, 60shutdown hooks and thread management, 60stack dump using non-Fluency, 221starting and stopping, 55System.exit(), 58transactions can span multiple JVMs, 84

JVM Propertiescom.kabira.application.class.path, 227com.kabira.platform.component.manager, 227com.kabira.platform.debugClasses, 227com.kabira.platform.ignoredPackages, 227com.kabira.platform.management.jmxEnable, 227

com.kabira.platform.management.port, 227com.kabira.platform.systemPackages, 227

KKabira Manager, 215kabira.env, 232kabira.env Properties

BuildType, 232kabira.properties, 43

locating, 194supported properties, 193

keep-alive, 30keepAliveMilliseconds, 30keepaliveseconds, 223keys, 116

@Key, 117@KeyList, 117Duplicate Keys, 119key annotations, 117ObjectNotUniqueError, 119

keys and queriesoverview, 2

Llife cycle

of configuration objects, 177of managed objects, 107

load balancingand partitions, 33

location codes, 18mapping to network addresses, 19

location discovery, 19lock promotion

avoiding promotion deadlocks, 101explicit locking used to prevent, 88

locking, 13of extents, 110of indexes, 121

locks, 85, 88(see also deadlocks)(see also lock promotion)behavior with Java monitors, 91explicit locking, 85, 88I/O, 101minimizing lock duration, 101minimizing resource contention, 101

log fileslocation of, 232

logging, 49, 212transactional behavior, 49

logs directory on development appliance, 231

246

Index

Page 261: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Mmanaged object annotation (see @Managed)managed objects, 1, 6, 8-9, 103-138

(see also distribution)(see also extents)(see also mirrored objects)(see also replicated objects)(see also triggers)base classes, 103changing shape of, 224defining, 103equals, 109explicit deletion required, 8hashCode, 109key restrictions, 118keys, 8life cycle of, 8, 107mirrored, 104overview, 1, 5persistent, 103queries, 9replicated, 104restrictions, 106supported types, 106triggers, 115

management console (see Kabira Manager)MDNS (see service discovery)mirrored objects, 6, 31

(see also distribution)defining, 157restoring nodes and, 37

monitoring applications, 215-220monitors, 217, 220

(see also event event monitor)(see also object monitor)

Nnetwork addresses

mapping to location codes, 19node names

with directed create, 19node startup

and type conflict, 19nodecleanup, 223nodes, 7

access error if unavailable, 148adding, 54detecting failure of, 30directory on development appliance, 232events generated by, 218executing applications on individual nodes, 53high availability states, 29identification of, 18

migrating partition, 38naming, 18primary and backup, 34restoring, 37, 54routing data to, 38transaction spanning of, 9transactions can span multiple, 84

noDestinationTimeoutSeconds, 58nonResponseTimeoutSeconds, 30notifiers, 185

transaction, 12, 93, 153

Oobject life cycle

and cache behavior, 21object monitor, 217object references, 17

accessing on remote nodes, 20distributed, 18extent may include invalid, 112invalid after delete, 108

objects, 103, 173(see also configuration)(see also managed objects)directed create, 19-20distributed behavior by default, 139location transparency of, 18network location of, 19representation on multiple nodes, 17

optional configuration data, 175options file, 226

jvmoptions, 227

Ppartition groups, 34partitions, 33, 163

configuration of, 34failover when primary node is down, 31migrating, 38routing data to, 38splitting, 36

passive caching (see caching)password, 223performance

and distributed deadlock detection, 16persistence

overview, 2primary node, 34

migrating, 38pull caching (see caching)push caching (see caching)

247

Page 262: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

Qqueries

@KeyField annotation, 133atomic creates of unique keyed objects, 130constructors, 133general pattern, 120KeyFieldValueList, 120KeyFieldValueRangeList, 120KeyManager, 120KeyQuery, 120locking and isolation, 121mapping constructor parameters, 134non-unique key, 123ordered, 125range, 128unique key, 121

Rreflection, 137registration

of management targets, 205remote debug port, 54remote method invocation, 149remote objects

locating, 149state conflict and, 155

remotedebug, 223remotedebugport, 223removenode, 29

outcome voting, 29replicated objects, 6, 31

(see also distribution)defining, 157overview, 3restoring nodes and, 37

reset, 223reset option, 224, 226rollback, 13

and explicit compensation, 93due to deadlock, 14for automatic state conflict resolution, 23logging, 17

routing, 38, 159-163run method

to execute code in a transaction, 69runtime objects, 190

Ssecondary node

migrating, 38serverdebug, 223service discovery, 222-223servicename, 223

shared memory persistence (see persistence)snippets, xivssl.TrustManagerFactory.algorithm, 226state conflicts, 22, 155

minimizing, 156static fields

not transactional, 80prohibited in managed objects, 106

suspend, 223switchadmin, 205switchmonitor, 205synchronous updates, 22, 35system management, 48-49, 201-213

logging, 49target, 48

System Propertiesssl.TrustManagerFactory.algorithm, 226

Ttarget

defining, 201threads

application shutdown and, 60creation, 84managing, 60transaction span of, 84transactions can span threads, 84

timeout, 223timers, 168Transaction class (see com.kabira.platform.Transactionclass)transaction notifiers, 153Transaction.Rollback exception, 69, 93transactional classes

guidelines for use, 101use outside transaction illegal, 99

TransactionNotifier class (see com.kabira.plat-form.swbuiltin.TransactionNotifier class)transactions, 9-17, 67-101

abandoned, 26boundaries, 67distributed, 9failover processing and, 38global transaction spanning nodes, 9history buffer configuration, 28history record size, 29initiator restarts, 27isolation, 13, 16isolation of extents, 110isolation of fields, 75isolation of indexes, 121local vs distributed, 9locking behavior, 13

248

Index

Page 263: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

logging, 17new transaction for asynchronous create, 22outcome voting, 27-28overview, 2, 5thread of control, 83

triggers, 8, 115-116delete trigger, 115update trigger, 115

TrustManagerFactory, 226X.509v3 algorithm, 226

type mismatch (see types, conflict)types

conflict, 19

Uunregister

of management targets, 205updating data (see accessing data)username, 223

VversionId

prohibited in configuration objects, 177VMware, 230

XX509, 223x509credential, 223x509credentialalias, 224

249

Page 264: TIBCO ActiveSpaces Transactionsdownloads.fluency.kabira.com/fluency/P.FLUENCY.JAVASDK-1... · 2011-02-06 · tibco softw are. the embedded or bundled softw are is not licensed to

250