From b086f57f56bf0eb9dab9cf321a0f69aaaae84347 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Wed, 30 May 2012 08:37:45 +0200 Subject: Initial Maven Conversion --- .../java/com/c2kernel/collection/Aggregation.java | 116 +++ .../collection/AggregationDescription.java | 59 ++ .../c2kernel/collection/AggregationInstance.java | 45 ++ .../com/c2kernel/collection/AggregationMember.java | 161 ++++ .../java/com/c2kernel/collection/Collection.java | 32 + .../c2kernel/collection/CollectionDescription.java | 14 + .../com/c2kernel/collection/CollectionMember.java | 38 + .../c2kernel/collection/CollectionMemberList.java | 22 + .../java/com/c2kernel/collection/Dependency.java | 117 +++ .../c2kernel/collection/DependencyDescription.java | 53 ++ .../com/c2kernel/collection/DependencyMember.java | 152 ++++ .../c2kernel/collection/MembershipException.java | 21 + .../collection/Parent2ChildCollection.java | 127 +++ .../com/c2kernel/collection/RelationshipUtils.java | 33 + .../gui/model/AggregationVertexFactory.java | 46 ++ .../gui/model/AggregationVertexOutlineCreator.java | 44 + .../gui/view/AggregationMemberRenderer.java | 125 +++ .../collection/gui/view/CollectionFrame.java | 41 + .../collection/gui/view/PropertyPanel.java | 37 + .../collection/gui/view/SelectedMemberPanel.java | 164 ++++ .../java/com/c2kernel/entity/C2KLocalObject.java | 32 + src/main/java/com/c2kernel/entity/CorbaServer.java | 190 +++++ .../java/com/c2kernel/entity/TraceableEntity.java | 341 ++++++++ .../java/com/c2kernel/entity/TraceableLocator.java | 85 ++ .../com/c2kernel/entity/agent/ActiveEntity.java | 295 +++++++ .../com/c2kernel/entity/agent/ActiveLocator.java | 87 ++ src/main/java/com/c2kernel/entity/agent/Job.java | 346 ++++++++ .../com/c2kernel/entity/agent/JobArrayList.java | 30 + .../java/com/c2kernel/entity/agent/JobList.java | 108 +++ .../java/com/c2kernel/entity/proxy/AgentProxy.java | 302 +++++++ .../entity/proxy/DomainPathSubscriber.java | 18 + .../com/c2kernel/entity/proxy/EntityProxy.java | 248 ++++++ .../c2kernel/entity/proxy/EntityProxyManager.java | 339 ++++++++ .../c2kernel/entity/proxy/EntityProxyObserver.java | 27 + .../java/com/c2kernel/entity/proxy/ItemProxy.java | 213 +++++ .../c2kernel/entity/proxy/MemberSubscription.java | 118 +++ .../entity/proxy/ProxyClientConnection.java | 185 +++++ .../com/c2kernel/entity/proxy/ProxyMessage.java | 102 +++ .../entity/proxy/ProxyServerConnection.java | 134 +++ .../com/c2kernel/entity/transfer/TransferItem.java | 133 +++ .../com/c2kernel/entity/transfer/TransferSet.java | 103 +++ src/main/java/com/c2kernel/events/Event.java | 276 +++++++ src/main/java/com/c2kernel/events/History.java | 87 ++ .../graph/controller/AutoScrollController.java | 41 + .../graph/controller/DeletionController.java | 92 +++ .../controller/EdgeConstructionController.java | 253 ++++++ .../controller/MultiSelectionDragController.java | 571 +++++++++++++ .../graph/controller/StartVertexController.java | 79 ++ .../controller/VertexConstructionController.java | 47 ++ .../com/c2kernel/graph/event/ClearedEvent.java | 6 + .../com/c2kernel/graph/event/EdgeRemovedEvent.java | 6 + .../c2kernel/graph/event/EdgesChangedEvent.java | 6 + .../graph/event/ElasticBandResizedEvent.java | 6 + .../c2kernel/graph/event/ElasticBandSetEvent.java | 6 + .../graph/event/EntireModelChangedEvent.java | 6 + .../c2kernel/graph/event/ForcedNotifyEvent.java | 6 + .../com/c2kernel/graph/event/GraphModelEvent.java | 7 + .../graph/event/GraphModelResizedEvent.java | 6 + .../graph/event/NewEdgeEndPointChangedEvent.java | 6 + .../graph/event/SelectionChangedEvent.java | 9 + .../c2kernel/graph/event/SelectionMovedEvent.java | 7 + .../graph/event/StartVertexIdChangedEvent.java | 6 + .../com/c2kernel/graph/event/VertexAddedEvent.java | 6 + .../c2kernel/graph/event/VertexCreatedEvent.java | 6 + .../com/c2kernel/graph/event/VertexMovedEvent.java | 6 + .../c2kernel/graph/event/VertexRemovedEvent.java | 6 + .../c2kernel/graph/event/VerticesChangedEvent.java | 6 + .../graph/layout/DefaultGraphLayoutGenerator.java | 116 +++ .../com/c2kernel/graph/layout/IntegerWrapper.java | 13 + .../com/c2kernel/graph/model/DirectedEdge.java | 99 +++ .../java/com/c2kernel/graph/model/EdgeFactory.java | 14 + .../java/com/c2kernel/graph/model/ElasticBand.java | 17 + .../java/com/c2kernel/graph/model/GraphModel.java | 900 +++++++++++++++++++++ .../c2kernel/graph/model/GraphModelCastorData.java | 29 + .../c2kernel/graph/model/GraphModelManager.java | 143 ++++ .../java/com/c2kernel/graph/model/GraphPoint.java | 18 + .../java/com/c2kernel/graph/model/Graphable.java | 55 ++ .../com/c2kernel/graph/model/GraphableEdge.java | 71 ++ .../com/c2kernel/graph/model/GraphableVertex.java | 261 ++++++ .../java/com/c2kernel/graph/model/Selection.java | 35 + .../graph/model/TypeNameAndConstructionInfo.java | 24 + src/main/java/com/c2kernel/graph/model/Vertex.java | 308 +++++++ .../com/c2kernel/graph/model/VertexFactory.java | 16 + .../c2kernel/graph/model/VertexOutlineCreator.java | 10 + .../c2kernel/graph/traversal/GraphTraversal.java | 85 ++ .../graph/view/DefaultDirectedEdgeRenderer.java | 75 ++ .../c2kernel/graph/view/DefaultVertexRenderer.java | 60 ++ .../c2kernel/graph/view/DirectedEdgeRenderer.java | 11 + .../c2kernel/graph/view/EditorModeListener.java | 8 + .../java/com/c2kernel/graph/view/EditorPanel.java | 104 +++ .../com/c2kernel/graph/view/EditorToolBar.java | 346 ++++++++ .../java/com/c2kernel/graph/view/GraphPanel.java | 272 +++++++ .../com/c2kernel/graph/view/PropertyTable.java | 40 + .../c2kernel/graph/view/PropertyTableModel.java | 135 ++++ .../c2kernel/graph/view/SelectedVertexPanel.java | 27 + .../c2kernel/graph/view/VertexPropertyPanel.java | 259 ++++++ .../com/c2kernel/graph/view/VertexRenderer.java | 11 + src/main/java/com/c2kernel/gui/Console.java | 290 +++++++ .../java/com/c2kernel/gui/DomainKeyConsumer.java | 16 + .../java/com/c2kernel/gui/DomainKeyListener.java | 27 + .../java/com/c2kernel/gui/DynamicTreeBuilder.java | 183 +++++ src/main/java/com/c2kernel/gui/EntityDetails.java | 228 ++++++ src/main/java/com/c2kernel/gui/EntityFinder.java | 217 +++++ .../java/com/c2kernel/gui/EntityTabManager.java | 86 ++ src/main/java/com/c2kernel/gui/LoginBox.java | 327 ++++++++ src/main/java/com/c2kernel/gui/Main.java | 40 + src/main/java/com/c2kernel/gui/MainFrame.java | 309 +++++++ src/main/java/com/c2kernel/gui/MenuBuilder.java | 281 +++++++ src/main/java/com/c2kernel/gui/TreeBrowser.java | 213 +++++ src/main/java/com/c2kernel/gui/data/Node.java | 232 ++++++ src/main/java/com/c2kernel/gui/data/NodeAgent.java | 33 + .../java/com/c2kernel/gui/data/NodeCollection.java | 68 ++ .../java/com/c2kernel/gui/data/NodeContext.java | 65 ++ .../java/com/c2kernel/gui/data/NodeEntity.java | 82 ++ src/main/java/com/c2kernel/gui/data/NodeItem.java | 112 +++ .../java/com/c2kernel/gui/data/NodeSubscriber.java | 13 + .../com/c2kernel/gui/tabs/AgentPropertiesPane.java | 51 ++ .../java/com/c2kernel/gui/tabs/CloseTabIcon.java | 70 ++ .../java/com/c2kernel/gui/tabs/CollectionPane.java | 109 +++ .../com/c2kernel/gui/tabs/DomainPathAdmin.java | 174 ++++ .../java/com/c2kernel/gui/tabs/EntityTabPane.java | 197 +++++ .../java/com/c2kernel/gui/tabs/ExecutionPane.java | 208 +++++ .../java/com/c2kernel/gui/tabs/HistoryPane.java | 270 +++++++ .../gui/tabs/JTabbedPaneWithCloseIcons.java | 96 +++ .../java/com/c2kernel/gui/tabs/JobListPane.java | 312 +++++++ .../java/com/c2kernel/gui/tabs/PropertiesPane.java | 200 +++++ .../java/com/c2kernel/gui/tabs/ViewpointPane.java | 515 ++++++++++++ .../java/com/c2kernel/gui/tabs/WorkflowPane.java | 286 +++++++ .../gui/tabs/collection/AggregationView.java | 90 +++ .../tabs/collection/CollectionHistoryWindow.java | 192 +++++ .../gui/tabs/collection/CollectionView.java | 49 ++ .../gui/tabs/collection/DependencyView.java | 34 + .../c2kernel/gui/tabs/execution/ActivityItem.java | 55 ++ .../gui/tabs/execution/ActivityViewer.java | 296 +++++++ .../gui/tabs/execution/DefaultExecutor.java | 35 + .../com/c2kernel/gui/tabs/execution/Executor.java | 22 + .../c2kernel/gui/tabs/execution/RequestButton.java | 34 + .../gui/tabs/outcome/BasicOutcomeEditor.java | 112 +++ .../gui/tabs/outcome/InvalidOutcomeException.java | 11 + .../gui/tabs/outcome/InvalidSchemaException.java | 11 + .../gui/tabs/outcome/OutcomeException.java | 11 + .../c2kernel/gui/tabs/outcome/OutcomeHandler.java | 16 + .../outcome/OutcomeNotInitialisedException.java | 11 + .../gui/tabs/outcome/form/AttributeList.java | 160 ++++ .../gui/tabs/outcome/form/CardinalException.java | 14 + .../c2kernel/gui/tabs/outcome/form/DataRecord.java | 252 ++++++ .../c2kernel/gui/tabs/outcome/form/Dimension.java | 395 +++++++++ .../gui/tabs/outcome/form/DimensionInstance.java | 33 + .../gui/tabs/outcome/form/DimensionTableModel.java | 332 ++++++++ .../com/c2kernel/gui/tabs/outcome/form/Field.java | 142 ++++ .../c2kernel/gui/tabs/outcome/form/HelpPane.java | 55 ++ .../tabs/outcome/form/MultiLinePasteAdapter.java | 141 ++++ .../gui/tabs/outcome/form/OutcomeEditor.java | 218 +++++ .../gui/tabs/outcome/form/OutcomePanel.java | 370 +++++++++ .../gui/tabs/outcome/form/OutcomeStructure.java | 283 +++++++ .../gui/tabs/outcome/form/StructuralException.java | 12 + .../tabs/outcome/form/field/ArrayEditField.java | 173 ++++ .../tabs/outcome/form/field/ArrayTableModel.java | 113 +++ .../tabs/outcome/form/field/BooleanEditField.java | 75 ++ .../gui/tabs/outcome/form/field/ComboField.java | 144 ++++ .../tabs/outcome/form/field/DecimalEditField.java | 122 +++ .../tabs/outcome/form/field/ImageEditField.java | 112 +++ .../tabs/outcome/form/field/IntegerEditField.java | 120 +++ .../gui/tabs/outcome/form/field/ListOfValues.java | 31 + .../outcome/form/field/LongStringEditField.java | 40 + .../tabs/outcome/form/field/StringEditField.java | 257 ++++++ .../java/com/c2kernel/lifecycle/ActivityDef.java | 143 ++++ .../com/c2kernel/lifecycle/ActivitySlotDef.java | 156 ++++ .../java/com/c2kernel/lifecycle/AndSplitDef.java | 114 +++ .../c2kernel/lifecycle/CompositeActivityDef.java | 227 ++++++ src/main/java/com/c2kernel/lifecycle/JoinDef.java | 68 ++ src/main/java/com/c2kernel/lifecycle/LoopDef.java | 78 ++ src/main/java/com/c2kernel/lifecycle/NextDef.java | 95 +++ .../java/com/c2kernel/lifecycle/OrSplitDef.java | 24 + .../com/c2kernel/lifecycle/WfCastorHashMap.java | 33 + .../java/com/c2kernel/lifecycle/WfVertexDef.java | 83 ++ .../java/com/c2kernel/lifecycle/XOrSplitDef.java | 29 + .../lifecycle/chooser/ActivityChooser.java | 194 +++++ .../lifecycle/chooser/LDAPEntryChooser.java | 70 ++ .../lifecycle/chooser/LDAPFileChooser.java | 121 +++ .../lifecycle/chooser/WorkflowDialogue.java | 20 + .../lifecycle/gui/model/WfDefGraphPanel.java | 59 ++ .../lifecycle/gui/model/WfEdgeDefFactory.java | 30 + .../lifecycle/gui/model/WfVertexDefFactory.java | 97 +++ .../gui/model/WfVertexDefOutlineCreator.java | 51 ++ .../gui/view/ActivitySlotDefRenderer.java | 71 ++ .../gui/view/CompActDefOutcomeHandler.java | 233 ++++++ .../gui/view/ElemActDefOutcomeHandler.java | 161 ++++ .../lifecycle/gui/view/SplitJoinDefRenderer.java | 138 ++++ .../gui/view/WfDirectedEdgeDefRenderer.java | 134 +++ .../lifecycle/gui/view/WfVertexDefRenderer.java | 30 + .../com/c2kernel/lifecycle/instance/Activity.java | 689 ++++++++++++++++ .../lifecycle/instance/AdvancementCalculator.java | 225 ++++++ .../com/c2kernel/lifecycle/instance/AndSplit.java | 27 + .../lifecycle/instance/CompositeActivity.java | 458 +++++++++++ .../com/c2kernel/lifecycle/instance/EventList.java | 19 + .../c2kernel/lifecycle/instance/EventStorage.java | 24 + .../com/c2kernel/lifecycle/instance/JobPusher.java | 70 ++ .../java/com/c2kernel/lifecycle/instance/Join.java | 216 +++++ .../java/com/c2kernel/lifecycle/instance/Loop.java | 107 +++ .../java/com/c2kernel/lifecycle/instance/Next.java | 83 ++ .../com/c2kernel/lifecycle/instance/OrSplit.java | 62 ++ .../com/c2kernel/lifecycle/instance/ParserWF.java | 356 ++++++++ .../com/c2kernel/lifecycle/instance/Split.java | 225 ++++++ .../com/c2kernel/lifecycle/instance/WfVertex.java | 180 +++++ .../com/c2kernel/lifecycle/instance/Workflow.java | 208 +++++ .../com/c2kernel/lifecycle/instance/XOrSplit.java | 54 ++ .../instance/gui/model/WfEdgeFactory.java | 35 + .../lifecycle/instance/gui/model/WfGraphPanel.java | 59 ++ .../instance/gui/model/WfVertexFactory.java | 92 +++ .../instance/gui/model/WfVertexOutlineCreator.java | 52 ++ .../instance/gui/view/ActivityRenderer.java | 117 +++ .../instance/gui/view/FindActDefPanel.java | 72 ++ .../instance/gui/view/SplitJoinRenderer.java | 142 ++++ .../instance/gui/view/TransitionPanel.java | 187 +++++ .../instance/gui/view/WfDirectedEdgeRenderer.java | 130 +++ .../instance/gui/view/WfVertexRenderer.java | 23 + .../instance/predefined/AddC2KObject.java | 75 ++ .../instance/predefined/AddDomainPath.java | 67 ++ .../predefined/AddStepsFromDescription.java | 56 ++ .../instance/predefined/AssignItemToSlot.java | 116 +++ .../predefined/CreateItemFromDescription.java | 183 +++++ .../lifecycle/instance/predefined/Erase.java | 85 ++ .../lifecycle/instance/predefined/Import.java | 71 ++ .../instance/predefined/PredefinedStep.java | 156 ++++ .../predefined/PredefinedStepContainer.java | 61 ++ .../instance/predefined/RemoveC2KObject.java | 67 ++ .../instance/predefined/RemoveDomainPath.java | 59 ++ .../instance/predefined/ReplaceDomainWorkflow.java | 53 ++ .../predefined/ServerPredefinedStepContainer.java | 41 + .../instance/predefined/WriteProperty.java | 77 ++ .../predefined/entitycreation/Aggregation.java | 25 + .../entitycreation/AggregationMember.java | 21 + .../predefined/entitycreation/CreateNewAgent.java | 49 ++ .../predefined/entitycreation/CreateNewItem.java | 46 ++ .../predefined/entitycreation/Dependency.java | 44 + .../entitycreation/DependencyMember.java | 18 + .../predefined/entitycreation/Geometry.java | 29 + .../predefined/entitycreation/NewAgent.java | 63 ++ .../predefined/entitycreation/NewItem.java | 141 ++++ .../predefined/entitycreation/Property.java | 26 + .../instance/stateMachine/StateMachine.java | 142 ++++ .../lifecycle/instance/stateMachine/States.java | 40 + .../instance/stateMachine/Transitions.java | 41 + .../routingHelpers/ViewpointDataHelper.java | 79 ++ src/main/java/com/c2kernel/lookup/AgentPath.java | 154 ++++ src/main/java/com/c2kernel/lookup/DomainPath.java | 158 ++++ src/main/java/com/c2kernel/lookup/EntityPath.java | 175 ++++ .../c2kernel/lookup/InvalidAgentPathException.java | 13 + .../lookup/InvalidEntityPathException.java | 13 + src/main/java/com/c2kernel/lookup/LDAPLookup.java | 464 +++++++++++ .../java/com/c2kernel/lookup/LDAPLookupUtils.java | 317 ++++++++ src/main/java/com/c2kernel/lookup/LDAPPathSet.java | 72 ++ .../java/com/c2kernel/lookup/LDAPProperties.java | 38 + .../com/c2kernel/lookup/LDAPPropertyManager.java | 118 +++ .../java/com/c2kernel/lookup/LDAPRoleManager.java | 199 +++++ .../c2kernel/lookup/LegacyLDAPPropertyManager.java | 75 ++ .../java/com/c2kernel/lookup/NextKeyManager.java | 71 ++ src/main/java/com/c2kernel/lookup/Path.java | 303 +++++++ src/main/java/com/c2kernel/lookup/RolePath.java | 121 +++ .../com/c2kernel/persistency/ClusterStorage.java | 104 +++ .../persistency/ClusterStorageException.java | 17 + .../persistency/ClusterStorageManager.java | 379 +++++++++ .../com/c2kernel/persistency/LDAPClientReader.java | 43 + .../c2kernel/persistency/LDAPClusterStorage.java | 172 ++++ .../java/com/c2kernel/persistency/ProxyLoader.java | 133 +++ .../java/com/c2kernel/persistency/RemoteMap.java | 374 +++++++++ .../c2kernel/persistency/TransactionManager.java | 324 ++++++++ .../c2kernel/persistency/XMLClusterStorage.java | 154 ++++ .../com/c2kernel/persistency/outcome/Outcome.java | 177 ++++ .../persistency/outcome/OutcomeValidator.java | 188 +++++ .../com/c2kernel/persistency/outcome/Schema.java | 18 + .../persistency/outcome/SchemaValidator.java | 55 ++ .../c2kernel/persistency/outcome/Viewpoint.java | 180 +++++ .../java/com/c2kernel/process/AbstractMain.java | 161 ++++ src/main/java/com/c2kernel/process/Bootstrap.java | 288 +++++++ src/main/java/com/c2kernel/process/Gateway.java | 429 ++++++++++ .../java/com/c2kernel/process/ItemHTTPBridge.java | 52 ++ src/main/java/com/c2kernel/process/Module.java | 303 +++++++ .../java/com/c2kernel/process/ModuleManager.java | 82 ++ .../java/com/c2kernel/process/StandardClient.java | 18 + .../java/com/c2kernel/process/StandardServer.java | 127 +++ .../java/com/c2kernel/process/UserCodeProcess.java | 234 ++++++ src/main/java/com/c2kernel/property/Property.java | 85 ++ .../com/c2kernel/property/PropertyArrayList.java | 29 + .../com/c2kernel/property/PropertyDescription.java | 77 ++ .../c2kernel/property/PropertyDescriptionList.java | 63 ++ .../com/c2kernel/property/PropertyUtility.java | 83 ++ .../java/com/c2kernel/scripting/ErrorInfo.java | 46 ++ .../java/com/c2kernel/scripting/Parameter.java | 52 ++ .../com/c2kernel/scripting/ParameterException.java | 20 + src/main/java/com/c2kernel/scripting/Script.java | 456 +++++++++++ .../java/com/c2kernel/scripting/ScriptConsole.java | 229 ++++++ .../c2kernel/scripting/ScriptLoadingException.java | 24 + .../c2kernel/scripting/ScriptParsingException.java | 21 + .../scripting/ScriptingEngineException.java | 20 + src/main/java/com/c2kernel/utils/ActDefCache.java | 98 +++ .../java/com/c2kernel/utils/CastorArrayList.java | 30 + .../java/com/c2kernel/utils/CastorHashMap.java | 54 ++ .../java/com/c2kernel/utils/CastorXMLUtility.java | 126 +++ src/main/java/com/c2kernel/utils/DateUtility.java | 118 +++ .../java/com/c2kernel/utils/FileStringUtility.java | 432 ++++++++++ .../com/c2kernel/utils/GTimeStampComparator.java | 25 + src/main/java/com/c2kernel/utils/KeyValuePair.java | 77 ++ src/main/java/com/c2kernel/utils/Language.java | 66 ++ .../java/com/c2kernel/utils/LocalObjectLoader.java | 77 ++ src/main/java/com/c2kernel/utils/Logger.java | 194 +++++ src/main/java/com/c2kernel/utils/Resource.java | 166 ++++ src/main/java/com/c2kernel/utils/SoftCache.java | 113 +++ .../java/com/c2kernel/utils/TransientCache.java | 130 +++ .../java/com/c2kernel/utils/XmlElementParser.java | 105 +++ .../c2kernel/utils/server/HTTPRequestHandler.java | 160 ++++ .../c2kernel/utils/server/SimpleTCPIPServer.java | 109 +++ .../com/c2kernel/utils/server/SocketHandler.java | 15 + .../com/c2kernel/utils/server/UDPListener.java | 54 ++ 315 files changed, 37846 insertions(+) create mode 100644 src/main/java/com/c2kernel/collection/Aggregation.java create mode 100644 src/main/java/com/c2kernel/collection/AggregationDescription.java create mode 100644 src/main/java/com/c2kernel/collection/AggregationInstance.java create mode 100644 src/main/java/com/c2kernel/collection/AggregationMember.java create mode 100644 src/main/java/com/c2kernel/collection/Collection.java create mode 100644 src/main/java/com/c2kernel/collection/CollectionDescription.java create mode 100644 src/main/java/com/c2kernel/collection/CollectionMember.java create mode 100644 src/main/java/com/c2kernel/collection/CollectionMemberList.java create mode 100644 src/main/java/com/c2kernel/collection/Dependency.java create mode 100644 src/main/java/com/c2kernel/collection/DependencyDescription.java create mode 100644 src/main/java/com/c2kernel/collection/DependencyMember.java create mode 100644 src/main/java/com/c2kernel/collection/MembershipException.java create mode 100644 src/main/java/com/c2kernel/collection/Parent2ChildCollection.java create mode 100644 src/main/java/com/c2kernel/collection/RelationshipUtils.java create mode 100644 src/main/java/com/c2kernel/collection/gui/model/AggregationVertexFactory.java create mode 100644 src/main/java/com/c2kernel/collection/gui/model/AggregationVertexOutlineCreator.java create mode 100644 src/main/java/com/c2kernel/collection/gui/view/AggregationMemberRenderer.java create mode 100644 src/main/java/com/c2kernel/collection/gui/view/CollectionFrame.java create mode 100644 src/main/java/com/c2kernel/collection/gui/view/PropertyPanel.java create mode 100644 src/main/java/com/c2kernel/collection/gui/view/SelectedMemberPanel.java create mode 100644 src/main/java/com/c2kernel/entity/C2KLocalObject.java create mode 100644 src/main/java/com/c2kernel/entity/CorbaServer.java create mode 100644 src/main/java/com/c2kernel/entity/TraceableEntity.java create mode 100644 src/main/java/com/c2kernel/entity/TraceableLocator.java create mode 100644 src/main/java/com/c2kernel/entity/agent/ActiveEntity.java create mode 100644 src/main/java/com/c2kernel/entity/agent/ActiveLocator.java create mode 100644 src/main/java/com/c2kernel/entity/agent/Job.java create mode 100644 src/main/java/com/c2kernel/entity/agent/JobArrayList.java create mode 100644 src/main/java/com/c2kernel/entity/agent/JobList.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/AgentProxy.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/DomainPathSubscriber.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/EntityProxy.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/EntityProxyManager.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/EntityProxyObserver.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/ItemProxy.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/MemberSubscription.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/ProxyClientConnection.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/ProxyMessage.java create mode 100644 src/main/java/com/c2kernel/entity/proxy/ProxyServerConnection.java create mode 100644 src/main/java/com/c2kernel/entity/transfer/TransferItem.java create mode 100644 src/main/java/com/c2kernel/entity/transfer/TransferSet.java create mode 100644 src/main/java/com/c2kernel/events/Event.java create mode 100644 src/main/java/com/c2kernel/events/History.java create mode 100644 src/main/java/com/c2kernel/graph/controller/AutoScrollController.java create mode 100644 src/main/java/com/c2kernel/graph/controller/DeletionController.java create mode 100644 src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java create mode 100644 src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java create mode 100644 src/main/java/com/c2kernel/graph/controller/StartVertexController.java create mode 100644 src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java create mode 100644 src/main/java/com/c2kernel/graph/event/ClearedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/GraphModelEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java create mode 100644 src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java create mode 100644 src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java create mode 100644 src/main/java/com/c2kernel/graph/model/DirectedEdge.java create mode 100644 src/main/java/com/c2kernel/graph/model/EdgeFactory.java create mode 100644 src/main/java/com/c2kernel/graph/model/ElasticBand.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphModel.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphModelManager.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphPoint.java create mode 100644 src/main/java/com/c2kernel/graph/model/Graphable.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphableEdge.java create mode 100644 src/main/java/com/c2kernel/graph/model/GraphableVertex.java create mode 100644 src/main/java/com/c2kernel/graph/model/Selection.java create mode 100644 src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java create mode 100644 src/main/java/com/c2kernel/graph/model/Vertex.java create mode 100644 src/main/java/com/c2kernel/graph/model/VertexFactory.java create mode 100644 src/main/java/com/c2kernel/graph/model/VertexOutlineCreator.java create mode 100644 src/main/java/com/c2kernel/graph/traversal/GraphTraversal.java create mode 100644 src/main/java/com/c2kernel/graph/view/DefaultDirectedEdgeRenderer.java create mode 100644 src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java create mode 100644 src/main/java/com/c2kernel/graph/view/DirectedEdgeRenderer.java create mode 100644 src/main/java/com/c2kernel/graph/view/EditorModeListener.java create mode 100644 src/main/java/com/c2kernel/graph/view/EditorPanel.java create mode 100644 src/main/java/com/c2kernel/graph/view/EditorToolBar.java create mode 100644 src/main/java/com/c2kernel/graph/view/GraphPanel.java create mode 100644 src/main/java/com/c2kernel/graph/view/PropertyTable.java create mode 100644 src/main/java/com/c2kernel/graph/view/PropertyTableModel.java create mode 100644 src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java create mode 100644 src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java create mode 100644 src/main/java/com/c2kernel/graph/view/VertexRenderer.java create mode 100644 src/main/java/com/c2kernel/gui/Console.java create mode 100644 src/main/java/com/c2kernel/gui/DomainKeyConsumer.java create mode 100644 src/main/java/com/c2kernel/gui/DomainKeyListener.java create mode 100644 src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java create mode 100644 src/main/java/com/c2kernel/gui/EntityDetails.java create mode 100644 src/main/java/com/c2kernel/gui/EntityFinder.java create mode 100644 src/main/java/com/c2kernel/gui/EntityTabManager.java create mode 100644 src/main/java/com/c2kernel/gui/LoginBox.java create mode 100644 src/main/java/com/c2kernel/gui/Main.java create mode 100644 src/main/java/com/c2kernel/gui/MainFrame.java create mode 100644 src/main/java/com/c2kernel/gui/MenuBuilder.java create mode 100644 src/main/java/com/c2kernel/gui/TreeBrowser.java create mode 100644 src/main/java/com/c2kernel/gui/data/Node.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeAgent.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeCollection.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeContext.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeEntity.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeItem.java create mode 100644 src/main/java/com/c2kernel/gui/data/NodeSubscriber.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/CollectionPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/HistoryPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/JobListPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/Executor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/Field.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/HelpPane.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java create mode 100644 src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java create mode 100644 src/main/java/com/c2kernel/lifecycle/ActivityDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/ActivitySlotDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/AndSplitDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/CompositeActivityDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/JoinDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/LoopDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/NextDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/OrSplitDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/WfCastorHashMap.java create mode 100644 src/main/java/com/c2kernel/lifecycle/WfVertexDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/XOrSplitDef.java create mode 100644 src/main/java/com/c2kernel/lifecycle/chooser/ActivityChooser.java create mode 100644 src/main/java/com/c2kernel/lifecycle/chooser/LDAPEntryChooser.java create mode 100644 src/main/java/com/c2kernel/lifecycle/chooser/LDAPFileChooser.java create mode 100644 src/main/java/com/c2kernel/lifecycle/chooser/WorkflowDialogue.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/model/WfDefGraphPanel.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/model/WfEdgeDefFactory.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefFactory.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefOutlineCreator.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/ActivitySlotDefRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/CompActDefOutcomeHandler.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/ElemActDefOutcomeHandler.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/SplitJoinDefRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/WfDirectedEdgeDefRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/gui/view/WfVertexDefRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Activity.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/AdvancementCalculator.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/AndSplit.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/CompositeActivity.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/EventList.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/EventStorage.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/JobPusher.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Join.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Loop.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Next.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/OrSplit.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/ParserWF.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Split.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/WfVertex.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/Workflow.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/XOrSplit.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfEdgeFactory.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfGraphPanel.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexFactory.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexOutlineCreator.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/ActivityRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/FindActDefPanel.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/SplitJoinRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/TransitionPanel.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfDirectedEdgeRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfVertexRenderer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/AddC2KObject.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/AddDomainPath.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/AddStepsFromDescription.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/AssignItemToSlot.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/CreateItemFromDescription.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/Erase.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/Import.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStep.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStepContainer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveC2KObject.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveDomainPath.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/ReplaceDomainWorkflow.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/ServerPredefinedStepContainer.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/WriteProperty.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Aggregation.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/AggregationMember.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewAgent.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewItem.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Dependency.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/DependencyMember.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Geometry.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Property.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/stateMachine/States.java create mode 100644 src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transitions.java create mode 100644 src/main/java/com/c2kernel/lifecycle/routingHelpers/ViewpointDataHelper.java create mode 100644 src/main/java/com/c2kernel/lookup/AgentPath.java create mode 100644 src/main/java/com/c2kernel/lookup/DomainPath.java create mode 100644 src/main/java/com/c2kernel/lookup/EntityPath.java create mode 100644 src/main/java/com/c2kernel/lookup/InvalidAgentPathException.java create mode 100644 src/main/java/com/c2kernel/lookup/InvalidEntityPathException.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPLookup.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPLookupUtils.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPPathSet.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPProperties.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPPropertyManager.java create mode 100644 src/main/java/com/c2kernel/lookup/LDAPRoleManager.java create mode 100644 src/main/java/com/c2kernel/lookup/LegacyLDAPPropertyManager.java create mode 100644 src/main/java/com/c2kernel/lookup/NextKeyManager.java create mode 100644 src/main/java/com/c2kernel/lookup/Path.java create mode 100644 src/main/java/com/c2kernel/lookup/RolePath.java create mode 100644 src/main/java/com/c2kernel/persistency/ClusterStorage.java create mode 100644 src/main/java/com/c2kernel/persistency/ClusterStorageException.java create mode 100644 src/main/java/com/c2kernel/persistency/ClusterStorageManager.java create mode 100644 src/main/java/com/c2kernel/persistency/LDAPClientReader.java create mode 100644 src/main/java/com/c2kernel/persistency/LDAPClusterStorage.java create mode 100644 src/main/java/com/c2kernel/persistency/ProxyLoader.java create mode 100644 src/main/java/com/c2kernel/persistency/RemoteMap.java create mode 100644 src/main/java/com/c2kernel/persistency/TransactionManager.java create mode 100644 src/main/java/com/c2kernel/persistency/XMLClusterStorage.java create mode 100644 src/main/java/com/c2kernel/persistency/outcome/Outcome.java create mode 100644 src/main/java/com/c2kernel/persistency/outcome/OutcomeValidator.java create mode 100644 src/main/java/com/c2kernel/persistency/outcome/Schema.java create mode 100644 src/main/java/com/c2kernel/persistency/outcome/SchemaValidator.java create mode 100644 src/main/java/com/c2kernel/persistency/outcome/Viewpoint.java create mode 100644 src/main/java/com/c2kernel/process/AbstractMain.java create mode 100644 src/main/java/com/c2kernel/process/Bootstrap.java create mode 100644 src/main/java/com/c2kernel/process/Gateway.java create mode 100644 src/main/java/com/c2kernel/process/ItemHTTPBridge.java create mode 100644 src/main/java/com/c2kernel/process/Module.java create mode 100644 src/main/java/com/c2kernel/process/ModuleManager.java create mode 100644 src/main/java/com/c2kernel/process/StandardClient.java create mode 100644 src/main/java/com/c2kernel/process/StandardServer.java create mode 100644 src/main/java/com/c2kernel/process/UserCodeProcess.java create mode 100644 src/main/java/com/c2kernel/property/Property.java create mode 100644 src/main/java/com/c2kernel/property/PropertyArrayList.java create mode 100644 src/main/java/com/c2kernel/property/PropertyDescription.java create mode 100644 src/main/java/com/c2kernel/property/PropertyDescriptionList.java create mode 100644 src/main/java/com/c2kernel/property/PropertyUtility.java create mode 100644 src/main/java/com/c2kernel/scripting/ErrorInfo.java create mode 100644 src/main/java/com/c2kernel/scripting/Parameter.java create mode 100644 src/main/java/com/c2kernel/scripting/ParameterException.java create mode 100644 src/main/java/com/c2kernel/scripting/Script.java create mode 100644 src/main/java/com/c2kernel/scripting/ScriptConsole.java create mode 100644 src/main/java/com/c2kernel/scripting/ScriptLoadingException.java create mode 100644 src/main/java/com/c2kernel/scripting/ScriptParsingException.java create mode 100644 src/main/java/com/c2kernel/scripting/ScriptingEngineException.java create mode 100644 src/main/java/com/c2kernel/utils/ActDefCache.java create mode 100644 src/main/java/com/c2kernel/utils/CastorArrayList.java create mode 100644 src/main/java/com/c2kernel/utils/CastorHashMap.java create mode 100644 src/main/java/com/c2kernel/utils/CastorXMLUtility.java create mode 100644 src/main/java/com/c2kernel/utils/DateUtility.java create mode 100644 src/main/java/com/c2kernel/utils/FileStringUtility.java create mode 100644 src/main/java/com/c2kernel/utils/GTimeStampComparator.java create mode 100644 src/main/java/com/c2kernel/utils/KeyValuePair.java create mode 100644 src/main/java/com/c2kernel/utils/Language.java create mode 100644 src/main/java/com/c2kernel/utils/LocalObjectLoader.java create mode 100644 src/main/java/com/c2kernel/utils/Logger.java create mode 100644 src/main/java/com/c2kernel/utils/Resource.java create mode 100644 src/main/java/com/c2kernel/utils/SoftCache.java create mode 100644 src/main/java/com/c2kernel/utils/TransientCache.java create mode 100644 src/main/java/com/c2kernel/utils/XmlElementParser.java create mode 100644 src/main/java/com/c2kernel/utils/server/HTTPRequestHandler.java create mode 100644 src/main/java/com/c2kernel/utils/server/SimpleTCPIPServer.java create mode 100644 src/main/java/com/c2kernel/utils/server/SocketHandler.java create mode 100644 src/main/java/com/c2kernel/utils/server/UDPListener.java (limited to 'src/main/java/com/c2kernel') diff --git a/src/main/java/com/c2kernel/collection/Aggregation.java b/src/main/java/com/c2kernel/collection/Aggregation.java new file mode 100644 index 0000000..e869621 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/Aggregation.java @@ -0,0 +1,116 @@ +package com.c2kernel.collection; + + +import com.c2kernel.collection.gui.model.AggregationVertexOutlineCreator; +import com.c2kernel.graph.model.GraphModel; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/** + * @version $Revision: 1.59 $ $Date: 2004/08/10 07:56:08 $ + * @author $Author: abranson $ + */ + +abstract public class Aggregation extends Parent2ChildCollection +{ + + protected GraphModel mLayout = new GraphModel(new AggregationVertexOutlineCreator()); + + private final TypeNameAndConstructionInfo[] mVertexTypeNameAndConstructionInfo = { + new TypeNameAndConstructionInfo(Language.translate("Slot"), "AggregationMember") + }; + + public Aggregation() + { + setName("Aggregation"); + } + + + public GraphModel getLayout() + { + return mLayout; + } + + public void setLayout(GraphModel layout) + { + mLayout = layout; + } + + public TypeNameAndConstructionInfo[] getVertexTypeNameAndConstructionInfo() + { + return mVertexTypeNameAndConstructionInfo; + } + + public boolean exists(int entityKey) + { + for (int i=0; i +{ + + public AggregationDescription() + { + setName("AggregationDescription"); + } + + public AggregationDescription(String name) + { + setName(name); + } + + + @Override + public Aggregation newInstance() + { + AggregationInstance newInstance = new AggregationInstance(getName()); + newInstance.setURLInfo(getURLInfo()); + //for each desc member + for (int i=0; i -1) { + if (mClassProps == null || getProperties() == null) + throw new MembershipException("ClassProps not yet set. Cannot check membership validity."); + + //for each mandatory prop check if its in the member property and has the matching value + StringTokenizer sub = new StringTokenizer(mClassProps, ","); + while (sub.hasMoreTokens()) + { + String aClassProp = sub.nextToken(); + try { + String memberValue = (String)getProperties().get(aClassProp); + Property entityProperty = (Property)Gateway.getStorage().get(entityKey, ClusterStorage.PROPERTY+"/"+aClassProp, null); + if (entityProperty == null) + throw new MembershipException("Property "+aClassProp+ " does not exist for entityKey=" + entityKey ); + if (entityProperty.getValue() == null || !entityProperty.getValue().equalsIgnoreCase(memberValue)) + throw new MembershipException("Value of mandatory prop "+aClassProp+" does not match: " + entityProperty.getValue()+"!="+memberValue); + } + catch (MembershipException ex) { + throw ex; + } + catch (Exception ex) + { + Logger.error(ex); + throw new MembershipException("Error checking properties"); + } + } + } + + mEntityKey = entityKey; + mEntity = null; + entityName = null; + } + + @Override + public void clearEntity() { + mEntityKey = -1; + mEntity = null; + } + + @Override + public EntityProxy resolveEntity() throws ObjectNotFoundException { + if (mEntity == null) { + try { + EntityPath path = new EntityPath(mEntityKey); + mEntity = Gateway.getProxyManager().getProxy(path); + } catch (InvalidEntityPathException ex) { + throw new ObjectNotFoundException("No member defined", ""); + } + } + return mEntity; + + } + + public Image getImage() { + if (image == null) { + image = Resource.findImage("typeicons/"+getProperties().get("Type")+"_16.png").getImage(); + } + return image; + } + + public String getEntityName() { + if (entityName == null) { + if (mEntityKey > -1) { + try { + entityName = resolveEntity().getName(); + } catch (ObjectNotFoundException ex) { + Logger.error(ex); + entityName = "Error ("+mEntityKey+")"; + } + } + else + entityName = "Empty"; + } + + return entityName; + } + +} diff --git a/src/main/java/com/c2kernel/collection/Collection.java b/src/main/java/com/c2kernel/collection/Collection.java new file mode 100644 index 0000000..b507593 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/Collection.java @@ -0,0 +1,32 @@ +package com.c2kernel.collection; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.utils.CastorHashMap; + +/** + * @version $Revision: 1.13 $ $Date: 2004/05/14 15:39:39 $ + * @author $Author: abranson $ + */ +public interface Collection extends C2KLocalObject +{ + public static final short EMPTY = -1; + + public int getCounter(); + + public void setCounter(int count); + + public int size(); + + public void setMembers(CollectionMemberList newMembers); + + public CollectionMemberList getMembers(); + + public E addMember(int entityKey, CastorHashMap props, String classProps) throws MembershipException; + + public E addMember(int entityKey) throws MembershipException; + + public void removeMember(int memberId) throws MembershipException; + + public E getMember(int memberId) throws ObjectNotFoundException; + +} diff --git a/src/main/java/com/c2kernel/collection/CollectionDescription.java b/src/main/java/com/c2kernel/collection/CollectionDescription.java new file mode 100644 index 0000000..69b569e --- /dev/null +++ b/src/main/java/com/c2kernel/collection/CollectionDescription.java @@ -0,0 +1,14 @@ +package com.c2kernel.collection; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2003/03/11 11:09:07 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public interface CollectionDescription extends Collection { + public Collection newInstance(); +} diff --git a/src/main/java/com/c2kernel/collection/CollectionMember.java b/src/main/java/com/c2kernel/collection/CollectionMember.java new file mode 100644 index 0000000..0b21e30 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/CollectionMember.java @@ -0,0 +1,38 @@ +package com.c2kernel.collection; + +import java.io.Serializable; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.EntityProxy; +import com.c2kernel.utils.CastorHashMap; + +/************************************************************************** + * CollectionMember interface is the superclass of all members + * This should be temporary - if we manage to rip GraphableVertex from Vertex, + * then that should be the superclass. + * + * $Revision: 1.19 $ + * $Date: 2004/01/22 11:24:44 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public interface CollectionMember extends Serializable { + + public void setEntityKey(int entityKey) throws MembershipException; + public int getEntityKey(); + + public void assignEntity(int entityKey) throws MembershipException; + public void clearEntity(); + public EntityProxy resolveEntity() throws ObjectNotFoundException; + + public void setID(int Id); + public int getID(); + + public void setProperties(CastorHashMap props); + public CastorHashMap getProperties(); + + public void setClassProps(String classProps); + public String getClassProps(); +} diff --git a/src/main/java/com/c2kernel/collection/CollectionMemberList.java b/src/main/java/com/c2kernel/collection/CollectionMemberList.java new file mode 100644 index 0000000..0a4bb25 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/CollectionMemberList.java @@ -0,0 +1,22 @@ +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2003/05/15 13:10:09 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.collection; + +import com.c2kernel.utils.CastorArrayList; + +public class CollectionMemberList extends CastorArrayList +{ + + public CollectionMemberList() + { + super(); + } + +} diff --git a/src/main/java/com/c2kernel/collection/Dependency.java b/src/main/java/com/c2kernel/collection/Dependency.java new file mode 100644 index 0000000..cbbf28c --- /dev/null +++ b/src/main/java/com/c2kernel/collection/Dependency.java @@ -0,0 +1,117 @@ +package com.c2kernel.collection; + + +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.KeyValuePair; +import com.c2kernel.utils.Logger; + +/* +Dependency Object +Objectified link representing dependency between items. +e.g.: Used for ProductDesc::Item-dependency-dependencymember-WfDesc::Item +*/ + +/** + * @version $Revision: 1.15 $ $Date: 2005/04/07 08:03:21 $ + * @author $Author: abranson $ + */ +public class Dependency extends Parent2ChildCollection +{ + + protected CastorHashMap mProperties = new CastorHashMap(); + protected String mClassProps = ""; + + public Dependency() + { + setName("Dependency"); + } + + public Dependency(String name) + { + setName(name); + } + + public CastorHashMap getProperties() { + return mProperties; + } + + public void setProperties(CastorHashMap props) { + mProperties = props; + } + + public KeyValuePair[] getKeyValuePairs() + { + return mProperties.getKeyValuePairs(); + } + public void setKeyValuePairs(KeyValuePair[] pairs) + { + mProperties.setKeyValuePairs(pairs); + } + + public void setClassProps(String classProps) { + this.mClassProps = classProps; + } + + public String getClassProps() { + return mClassProps; + } + + @Override + public DependencyMember addMember(int entityKey) throws MembershipException { + // create member object + DependencyMember depMember = new DependencyMember(); + depMember.setID(getCounter()); + depMember.setProperties(mProperties); + depMember.setClassProps(mClassProps); + + // assign entity + depMember.assignEntity(entityKey); + mMembers.list.add(depMember); + Logger.msg(8, "Dependency::addMember(" + entityKey + ") added to children."); + return depMember; + } + + @Override + public DependencyMember addMember(int entityKey, CastorHashMap props, String classProps) + throws MembershipException + { + if (classProps != null && !classProps.equals(mClassProps)) + throw new MembershipException("Cannot change classProps in dependency member"); + DependencyMember depMember = new DependencyMember(); + depMember.setID(getCounter()); + + // merge props + CastorHashMap newProps = new CastorHashMap(); + for (Object name : props.keySet()) { + String key = (String)name; + newProps.put(key, props.get(key)); + + } + // class props override local + for (Object name : mProperties.keySet()) { + String key = (String)name; + newProps.put(key, mProperties.get(key)); + + } + depMember.setProperties(newProps); + depMember.setClassProps(mClassProps); + + // assign entity + depMember.assignEntity(entityKey); + mMembers.list.add(depMember); + Logger.msg(8, "Dependency::addMember(" + entityKey + ") added to children."); + return depMember; + } + + @Override + public void removeMember(int memberId) throws MembershipException { + for (DependencyMember element : mMembers.list) { + if (element.getID() == memberId) { + mMembers.list.remove(element); + return; + } + } + throw new MembershipException("Member "+memberId+" not found"); + } + +} diff --git a/src/main/java/com/c2kernel/collection/DependencyDescription.java b/src/main/java/com/c2kernel/collection/DependencyDescription.java new file mode 100644 index 0000000..547a286 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/DependencyDescription.java @@ -0,0 +1,53 @@ +package com.c2kernel.collection; + +import com.c2kernel.property.PropertyDescriptionList; +import com.c2kernel.property.PropertyUtility; +import com.c2kernel.utils.CastorHashMap; + +public class DependencyDescription extends Dependency implements CollectionDescription{ + + public DependencyDescription() + { + setName("DependencyDescription"); + } + + public DependencyDescription(String name) + { + setName(name); + } + + @Override + public Collection newInstance() { + String depName = getName().replaceFirst("\'$", ""); // HACK: Knock the special 'prime' off the end for the case of descriptions of descriptions + Dependency newDep = new Dependency(depName); + if (mMembers.list.size() == 1) { // constrain the members based on the property description + DependencyMember mem = mMembers.list.get(0); + PropertyDescriptionList pdList = PropertyUtility.getPropertyDescriptionOutcome(mem.getEntityKey()); + if (pdList!=null) { + newDep.setProperties(PropertyUtility.createProperty(pdList)); + newDep.setClassProps(pdList.getClassProps()); + } + } + return newDep; + } + + + @Override + public DependencyMember addMember(int entityKey) throws MembershipException { + checkMembership(); + return super.addMember(entityKey); + } + + @Override + public DependencyMember addMember(int entityKey, CastorHashMap props, String classProps) + throws MembershipException { + checkMembership(); + return super.addMember(entityKey, props, classProps); + } + + public void checkMembership() throws MembershipException { + if (mMembers.list.size() > 0) + throw new MembershipException("Dependency descriptions may not have more than one member."); + } + +} diff --git a/src/main/java/com/c2kernel/collection/DependencyMember.java b/src/main/java/com/c2kernel/collection/DependencyMember.java new file mode 100644 index 0000000..4ca2090 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/DependencyMember.java @@ -0,0 +1,152 @@ +package com.c2kernel.collection; + +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.EntityProxy; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.KeyValuePair; +import com.c2kernel.utils.Logger; + + +/** +* @version $Revision: 1.10 $ $Date: 2004/10/21 08:02:23 $ +* @author $Author: abranson $ +*/ + + +public class DependencyMember implements CollectionMember +{ + + private int mEntityKey = -1; + private EntityProxy mEntity = null; + private int mId = -1; + private CastorHashMap mProperties = null; + private String mClassProps; + + + /************************************************************************** + * + **************************************************************************/ + public DependencyMember() + { + mEntityKey = -1; + mProperties = new CastorHashMap(); + } + + + @Override + public void setEntityKey(int entityKey) + { + mEntityKey = entityKey; + mEntity = null; + } + + @Override + public int getEntityKey() + { + return mEntityKey; + } + + @Override + public void setProperties(CastorHashMap props) + { + mProperties = props; + } + + @Override + public CastorHashMap getProperties() + { + return mProperties; + } + + public KeyValuePair[] getKeyValuePairs() + { + return mProperties.getKeyValuePairs(); + } + public void setKeyValuePairs(KeyValuePair[] pairs) + { + mProperties.setKeyValuePairs(pairs); + } + + @Override + public int getID() { + return mId; + } + + @Override + public void setID(int id) { + mId = id; + } + + @Override + public void setClassProps(String props) + { + mClassProps = props; + } + + @Override + public String getClassProps() + { + return mClassProps; + } + + @Override + public void assignEntity(int entityKey) throws MembershipException + { + if (entityKey > -1) { + if (mClassProps == null || getProperties() == null) + throw new MembershipException("ClassProps not yet set. Cannot check membership validity."); + + //for each mandatory prop check if its in the member property and has the matching value + StringTokenizer sub = new StringTokenizer(mClassProps, ","); + while (sub.hasMoreTokens()) + { + String aClassProp = sub.nextToken(); + try { + String memberValue = (String)getProperties().get(aClassProp); + Property entityProperty = (Property)Gateway.getStorage().get(entityKey, ClusterStorage.PROPERTY+"/"+aClassProp, null); + if (entityProperty == null) + throw new MembershipException("Property "+aClassProp+ " does not exist for entityKey=" + entityKey ); + if (!entityProperty.getValue().equalsIgnoreCase(memberValue)) + throw new MembershipException("DependencyMember::checkProperty() Values of mandatory prop "+aClassProp+" do not match " + entityProperty.getValue()+"!="+memberValue); + } + catch (Exception ex) + { + Logger.error(ex); + throw new MembershipException("Error checking properties"); + } + } + } + + mEntityKey = entityKey; + mEntity = null; + } + + @Override + public void clearEntity() { + mEntityKey = -1; + mEntity = null; + } + + @Override + public EntityProxy resolveEntity() throws ObjectNotFoundException { + if (mEntity == null) { + try { + EntityPath path = new EntityPath(mEntityKey); + mEntity = Gateway.getProxyManager().getProxy(path); + } catch (InvalidEntityPathException ex) { + throw new ObjectNotFoundException("No member defined", ""); + } + } + return mEntity; + + } + + +} diff --git a/src/main/java/com/c2kernel/collection/MembershipException.java b/src/main/java/com/c2kernel/collection/MembershipException.java new file mode 100644 index 0000000..912d52c --- /dev/null +++ b/src/main/java/com/c2kernel/collection/MembershipException.java @@ -0,0 +1,21 @@ +package com.c2kernel.collection; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2003/05/09 14:23:01 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class MembershipException extends Exception { + + public MembershipException() { + super(); + } + + public MembershipException(String s) { + super(s); + } +} diff --git a/src/main/java/com/c2kernel/collection/Parent2ChildCollection.java b/src/main/java/com/c2kernel/collection/Parent2ChildCollection.java new file mode 100644 index 0000000..c59132e --- /dev/null +++ b/src/main/java/com/c2kernel/collection/Parent2ChildCollection.java @@ -0,0 +1,127 @@ +package com.c2kernel.collection; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.CastorHashMap; + +/** + * @version $Revision: 1.23 $ $Date: 2004/05/14 15:39:39 $ + * @author $Author: abranson $ + */ +abstract public class Parent2ChildCollection implements Collection +{ + + private int mCounter = -1; // Contains next available Member ID + protected CollectionMemberList mMembers = new CollectionMemberList(); + protected int mID = -1; + protected String mName = ""; // Not checked for uniqueness + protected String mURLInfo = ""; + + @Override + public int getCounter() + { + if (mCounter == -1) + for (Object name : mMembers.list) { + CollectionMember element = (CollectionMember)name; + if (mCounter < element.getID()) + mCounter = element.getID(); + } + return ++mCounter; + } + + @Override + public void setCounter(int count) + { + mCounter = count; + } + + + @Override + public int size() + { + return mMembers.list.size(); + } + + public void setID(int id) + { + mID = id; + } + + public int getID() + { + return mID; + } + + @Override + public void setName(String name) + { + mName = name; + } + + public void setURLInfo(String urlInfo) + { + mURLInfo = urlInfo; + } + + @Override + public String getName() + { + return mName; + } + + @Override + public String getClusterType() + { + return ClusterStorage.COLLECTION; + } + + public String getURLInfo() + { + return mURLInfo; + } + + @Override + public void setMembers(CollectionMemberList newMembers) + { + mMembers = newMembers; + } + + public boolean contains(int entityKey) { + for (Object name : mMembers.list) { + CollectionMember element = (CollectionMember)name; + if (element.getEntityKey() == entityKey) + return true; + } + return false; + } + + public boolean isFull() + { + for (int i=0; i getMembers() + { + return mMembers; + } + + @Override + public abstract E addMember(int entityKey, CastorHashMap props, String classProps) throws MembershipException; + +} diff --git a/src/main/java/com/c2kernel/collection/RelationshipUtils.java b/src/main/java/com/c2kernel/collection/RelationshipUtils.java new file mode 100644 index 0000000..6e35ac8 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/RelationshipUtils.java @@ -0,0 +1,33 @@ +package com.c2kernel.collection; + + +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; + + +/** + * @version $Revision: 1.22 $ $Date: 2004/10/21 08:02:23 $ + * @author $Author: abranson $ + */ + +public class RelationshipUtils +{ + + static public boolean getIsComposite(int entityKey) + { + if (entityKey == -1) return false; + try + { + if ( ((Aggregation) Gateway.getProxyManager().getProxy(new EntityPath(entityKey)).getObject(ClusterStorage.COLLECTION+"/Composition" )).size() > 0 ) + return true; + } + catch (Exception ex) + { + //do nothing - member has no composition, thus elementary + } + + return false; + } + +} diff --git a/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexFactory.java b/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexFactory.java new file mode 100644 index 0000000..cd4963f --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexFactory.java @@ -0,0 +1,46 @@ +package com.c2kernel.collection.gui.model; + +import java.awt.Point; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.MembershipException; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.graph.model.VertexFactory; +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.Logger; + + +public class AggregationVertexFactory implements VertexFactory +{ + private Aggregation mAggregation = null; + + + @Override + public void setCreationContext(Object aggregation) + { + if (aggregation != null && aggregation instanceof Aggregation) + mAggregation = (Aggregation)aggregation; + } + + + @Override + public void create + ( + GraphModelManager graphModelManager, + Point location, + TypeNameAndConstructionInfo typeNameAndConstructionInfo + ) + { + if (typeNameAndConstructionInfo.mInfo.equals("AggregationMember")) { + try { + mAggregation.addMember(-1, new CastorHashMap(), "", new GraphPoint(location.x, location.y), 40, 40); + } catch (MembershipException ex) { + Logger.error(ex); + Logger.exceptionDialog(ex); + } + } + } +} + diff --git a/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexOutlineCreator.java b/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexOutlineCreator.java new file mode 100644 index 0000000..b28af2e --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/model/AggregationVertexOutlineCreator.java @@ -0,0 +1,44 @@ +package com.c2kernel.collection.gui.model; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.model.VertexOutlineCreator; + + +public class AggregationVertexOutlineCreator implements VertexOutlineCreator +{ + @Override + public void setOutline(Vertex vertex) + { + GraphPoint centre = vertex.getCentrePoint(); + int height = vertex.getHeight(); + int width = vertex.getWidth(); + + + if (height==0 || width==0) + vertex.setOutlinePoints + ( + new GraphPoint[] + { + new GraphPoint(centre.x-20, centre.y-20), + new GraphPoint(centre.x+20, centre.y-20), + new GraphPoint(centre.x+20, centre.y+20), + new GraphPoint(centre.x-20, centre.y+20) + + } + ); + else + + vertex.setOutlinePoints + ( + new GraphPoint[] + { + new GraphPoint(centre.x-width/2, centre.y-height/2), + new GraphPoint(centre.x+width/2, centre.y-height/2), + new GraphPoint(centre.x+width/2, centre.y+height/2), + new GraphPoint(centre.x-width/2, centre.y+height/2) + + } + ); + } +} diff --git a/src/main/java/com/c2kernel/collection/gui/view/AggregationMemberRenderer.java b/src/main/java/com/c2kernel/collection/gui/view/AggregationMemberRenderer.java new file mode 100644 index 0000000..6d41d20 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/view/AggregationMemberRenderer.java @@ -0,0 +1,125 @@ +package com.c2kernel.collection.gui.view; + +import java.awt.FontMetrics; +import java.awt.Graphics2D; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.AggregationMember; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.utils.Logger; + +/** + * @version $Revision: 1.24 $ $Date: 2005/12/01 14:23:15 $ + * @author $Author: abranson $ + */ + +public class AggregationMemberRenderer implements VertexRenderer +{ + + private Aggregation mAggregation = null; + + public AggregationMemberRenderer() + { + } + + public void setAggregation(Aggregation agg) + { + mAggregation = agg; + } + + + @Override + public void draw(Graphics2D g2d, Vertex vertex) + { + GraphPoint centre = vertex.getCentrePoint(); + GraphPoint[] outline = vertex.getOutlinePoints(); + FontMetrics metrics = g2d.getFontMetrics(); + + AggregationMember memberPair = mAggregation.getMemberPair(vertex.getID()); + + try + { + String name = memberPair.getEntityName(); + + g2d.drawString( name, + centre.x-metrics.stringWidth(name)/2, + topYOfOutline(outline) ); + + g2d.drawImage + ( + memberPair.getImage(), + centre.x - 8, + centre.y - 8, + null + ); + + + + // Draw the outline of the vertex + if(outline.length > 1) + { + for(int i=0; i bottomY) + { + bottomY = outline[i].y; + } + } + + return bottomY; + } +} diff --git a/src/main/java/com/c2kernel/collection/gui/view/CollectionFrame.java b/src/main/java/com/c2kernel/collection/gui/view/CollectionFrame.java new file mode 100644 index 0000000..2d40436 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/view/CollectionFrame.java @@ -0,0 +1,41 @@ +package com.c2kernel.collection.gui.view; + +import java.awt.GridLayout; + +import javax.swing.JFrame; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.gui.tabs.CollectionPane; + + +/** + * @version $Revision: 1.10 $ $Date: 2003/04/06 15:06:36 $ + * @author $Author: abranson $ + */ + +public class CollectionFrame extends JFrame +{ + + private CollectionPane mCollectionPane = new CollectionPane(); + + public CollectionFrame() + { + createLayout(); + } + + public void setAggregation(Aggregation aggregation) + { + mCollectionPane.add(aggregation); + } + + + private void createLayout() + { + getContentPane().setLayout(new GridLayout(1, 1)); + + getContentPane().add(mCollectionPane); + + setSize(1000, 1000); + setVisible(true); + } +} diff --git a/src/main/java/com/c2kernel/collection/gui/view/PropertyPanel.java b/src/main/java/com/c2kernel/collection/gui/view/PropertyPanel.java new file mode 100644 index 0000000..f566d70 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/view/PropertyPanel.java @@ -0,0 +1,37 @@ +package com.c2kernel.collection.gui.view; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.AggregationMember; +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexPropertyPanel; + +public class PropertyPanel extends VertexPropertyPanel { + + Aggregation mCollection; + + public PropertyPanel() { + super(); + } + + public void setCollection(Aggregation collection) { + mCollection = collection; + } + + @Override + public void setVertex(Vertex vert) { + try { + CollectionMember newMember = mCollection.getMember(vert.getID()); + if (newMember instanceof AggregationMember) { + super.setVertex((AggregationMember)newMember); + return; + } + else + clear(); + } catch (ObjectNotFoundException ex) { + clear(); + selObjClass.setText("No Collection Member object found"); + } + } +} diff --git a/src/main/java/com/c2kernel/collection/gui/view/SelectedMemberPanel.java b/src/main/java/com/c2kernel/collection/gui/view/SelectedMemberPanel.java new file mode 100644 index 0000000..5b59b35 --- /dev/null +++ b/src/main/java/com/c2kernel/collection/gui/view/SelectedMemberPanel.java @@ -0,0 +1,164 @@ +package com.c2kernel.collection.gui.view; + +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.JToggleButton; + +import com.c2kernel.collection.AggregationMember; +import com.c2kernel.collection.MembershipException; +import com.c2kernel.entity.proxy.EntityProxy; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.SelectedVertexPanel; +import com.c2kernel.gui.DomainKeyConsumer; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Language; + +/************************************************************************** + * + * $Revision: 1.10 $ + * $Date: 2005/05/12 10:12:52 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + +public class SelectedMemberPanel extends SelectedVertexPanel implements DomainKeyConsumer { + + JLabel slotNumber = new JLabel(); + JTextField memberKey = new JTextField(14); + + JButton findButton = new JButton(Language.translate("Find")); + JToggleButton changeButton = new JToggleButton(Language.translate("Change")); + JButton removeButton = new JButton(Language.translate("Remove")); + + SelectedMemberPanel me; + AggregationMember selectedMember = null; + + public SelectedMemberPanel() { + me=this; + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JPanel attrs = new JPanel(new GridLayout(3,2)); + attrs.add(new JLabel(Language.translate("Slot Number:"))); + attrs.add(slotNumber); + attrs.add(new JLabel(Language.translate("Assigned Member:"))); + attrs.add(memberKey); + memberKey.setEditable(false); + + add(attrs); + add(Box.createVerticalStrut(10)); + + findButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + String code = memberKey.getText(); + if (code == null || code.length() == 0) + code = memberKey.getText().replace('/',' '); + MainFrame.itemFinder.pushNewKey(code); + } + }); + + changeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + if (changeButton.getModel().isSelected()) { + MainFrame.status.setText(Language.translate("Please scan or type your barcode to assign in the top field")); + MainFrame.itemFinder.setConsumer(me, "Assign"); + findButton.setEnabled(false); + } + else { + MainFrame.status.setText(""); + MainFrame.itemFinder.clearConsumer(me); + if (selectedMember.getEntityKey() > -1) findButton.setEnabled(true); + } + } + }); + + removeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + selectedMember.clearEntity(); + selectedMember.getProperties().remove("Name"); + select(selectedMember); + } + }); + + Box buttonBox = Box.createHorizontalBox(); + buttonBox.add(findButton); + if (MainFrame.isAdmin) { + buttonBox.add(changeButton); + buttonBox.add(removeButton); + } + + setButtons(false); + add(buttonBox); + } + + @Override + public void select(Vertex vert) { + selectedMember = (AggregationMember)vert; + slotNumber.setText(String.valueOf(vert.getID())); + int memberId = selectedMember.getEntityKey(); + String name = "Empty"; + try { + EntityProxy member = Gateway.getProxyManager().getProxy(new EntityPath(memberId)); + name = member.getName(); + } catch (Exception e) { } + memberKey.setText(name); + setButtons(true); + + revalidate(); + } + + @Override + public void clear() { + slotNumber.setText(""); + memberKey.setText(""); + setButtons(false); + revalidate(); + } + + public void setButtons(boolean state) { + findButton.setEnabled(state); + changeButton.getModel().setSelected(false); + changeButton.setEnabled(state); + removeButton.setEnabled(state); + MainFrame.itemFinder.clearConsumer(me); + } + /** + * + */ + @Override + public void push(DomainPath key) { + MainFrame.status.setText("Assigning entity "+key.getSysKey()+" to slot "+selectedMember.getID()); + try { + selectedMember.assignEntity(key.getSysKey()); + select(selectedMember); + } catch (MembershipException ex) { + JOptionPane.showMessageDialog(null, "Product does not fit in this slot", "Error", JOptionPane.ERROR_MESSAGE); + } + } + + /** + * + */ + @Override + public void push(String name) { + JOptionPane.showMessageDialog(null, "Product is not known in this centre", "Error", JOptionPane.ERROR_MESSAGE); + } + +} + diff --git a/src/main/java/com/c2kernel/entity/C2KLocalObject.java b/src/main/java/com/c2kernel/entity/C2KLocalObject.java new file mode 100644 index 0000000..ec30dc1 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/C2KLocalObject.java @@ -0,0 +1,32 @@ +package com.c2kernel.entity; + +import java.io.Serializable; + +/** + * Objects that are to be stored by Cristal Entities must implement this interface and be (un)marshallable by Castor + * i.e. have a map file properly registered in the kernel. Domain implementors should not create new C2KLocalObjects + *

Each object will be stored as the path /clustertype/name in most cases. Exceptions are: + *

    + *
  • Outcomes - /Outcome/SchemaType/SchemaVersion/EventId + *
  • Viewpoints - /ViewPoint/SchemaType/Name + *
+ * + * @see com.c2kernel.persistency.ClusterStorage + * @see com.c2kernel.persistency.ClusterStorageManager + * + * @author Andrew Branson + * + * $Revision: 1.5 $ + * $Date: 2004/01/22 11:10:41 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + */ + +public interface C2KLocalObject extends Serializable { + + public void setName(String name); + public String getName(); + + public String getClusterType(); +} diff --git a/src/main/java/com/c2kernel/entity/CorbaServer.java b/src/main/java/com/c2kernel/entity/CorbaServer.java new file mode 100644 index 0000000..84d2ef2 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/CorbaServer.java @@ -0,0 +1,190 @@ +package com.c2kernel.entity; + +import java.util.Map; + +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAManager; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.AdapterInactive; + +import com.c2kernel.common.CannotManageException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.ActiveEntity; +import com.c2kernel.entity.agent.ActiveLocator; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.SoftCache; + +/************************************************************************** + * + * $Revision: 1.8 $ + * $Date: 2005/10/13 08:13:44 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + +public class CorbaServer { + private Map mEntityCache; + private POA mRootPOA; + private POA mItemPOA; + private POA mAgentPOA; + private POAManager mPOAManager; + + public CorbaServer() throws InvalidDataException { + mEntityCache = new SoftCache(50); + + // init POA + try { + setupPOA(); + mPOAManager.activate(); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidDataException("Error initialising POA", ""); + } + + new Thread(new Runnable() { + @Override + public void run() { + Thread.currentThread().setName("ORB Invoker"); + Gateway.getORB().run(); + } + }).start(); + } + + public void close() { + try { + mPOAManager.deactivate(true, true); + } catch (AdapterInactive ex) { + Logger.error(ex); + } + } + + /************************************************************************** + * Initialises the C2KRootPOA with policies which are suitable for Factory objects + **************************************************************************/ + public void setupPOA() throws Exception { + + //Initialise the RootPOA + mRootPOA = org.omg.PortableServer.POAHelper.narrow( + Gateway.getORB().resolve_initial_references("RootPOA")); + + //Initilaise the default POAManager + + mPOAManager = mRootPOA.the_POAManager(); + + // Create POA for use by the entities + org.omg.CORBA.Policy[] policies = new org.omg.CORBA.Policy[6]; + + policies[0] = mRootPOA.create_id_assignment_policy( + org.omg.PortableServer.IdAssignmentPolicyValue.USER_ID); + policies[1] = mRootPOA.create_lifespan_policy( + org.omg.PortableServer.LifespanPolicyValue.PERSISTENT); + policies[2] = mRootPOA.create_servant_retention_policy( + org.omg.PortableServer.ServantRetentionPolicyValue.NON_RETAIN); + policies[3] = mRootPOA.create_id_uniqueness_policy( + org.omg.PortableServer.IdUniquenessPolicyValue.UNIQUE_ID); + policies[4] = mRootPOA.create_request_processing_policy( + org.omg.PortableServer.RequestProcessingPolicyValue. + USE_SERVANT_MANAGER); + policies[5] = mRootPOA.create_implicit_activation_policy( + org.omg.PortableServer.ImplicitActivationPolicyValue. + NO_IMPLICIT_ACTIVATION); + + mItemPOA = mRootPOA.create_POA( "Item", + mRootPOA.the_POAManager(), + policies ); + mAgentPOA = mRootPOA.create_POA( "Agent", + mRootPOA.the_POAManager(), + policies ); + + //Create the locators + TraceableLocator itemLocator = new TraceableLocator( mItemPOA ); + mItemPOA.set_servant_manager( itemLocator._this( Gateway.getORB() ) ); + + ActiveLocator agentLocator = new ActiveLocator( mAgentPOA ); + mAgentPOA.set_servant_manager( agentLocator._this( Gateway.getORB() ) ); + + } + + + /************************************************************************** + * Returns a CORBA servant for a pre-existing entity + **************************************************************************/ + private Servant getEntity(int sysKey, org.omg.PortableServer.POA poa) throws ObjectNotFoundException { + try { + EntityPath entityPath = new EntityPath(sysKey); + Servant entity = null; + synchronized (mEntityCache) { + entity = mEntityCache.get(entityPath); + if (entity == null) { + Logger.msg(7, "Creating new servant for "+sysKey); + + Class entityClass = Gateway.getLDAPLookup().getEntityClass(entityPath); + + if (entityClass == TraceableEntity.class) { + if (poa == null) poa = mItemPOA; + entity = new TraceableEntity(sysKey, poa); + } + else if (entityClass == ActiveEntity.class) { + if (poa == null) poa = mAgentPOA; + entity = new ActiveEntity(sysKey, poa); + } + mEntityCache.put(entityPath, entity); + } + } + return entity; + + } catch (InvalidEntityPathException ex) { + throw new ObjectNotFoundException("Invalid Entity Key", ""); + } + } + + /************************************************************************** + * Wrapper for fetching Items + **************************************************************************/ + public TraceableEntity getItem(int sysKey, org.omg.PortableServer.POA poa) throws ObjectNotFoundException { + return (TraceableEntity)getEntity(sysKey, poa); + } + + /************************************************************************** + * Wrapper for fetching Agents + **************************************************************************/ + public ActiveEntity getAgent(int sysKey, org.omg.PortableServer.POA poa) throws ObjectNotFoundException { + return (ActiveEntity)getEntity(sysKey, poa); + } + + /** + * @param entityPath + * @return + */ + public Servant createEntity(EntityPath entityPath) throws CannotManageException, ObjectAlreadyExistsException { + try { + if (entityPath == null) + entityPath = Gateway.getLDAPLookup().getNextKeyManager().generateNextEntityKey(); + } catch (Exception ex) { + Logger.error(ex); + throw new CannotManageException("Cannot generate next entity key"); + } + boolean isAgent = entityPath instanceof AgentPath; + POA myPOA = isAgent?mAgentPOA:mItemPOA; + org.omg.CORBA.Object obj = myPOA.create_reference_with_id(entityPath.getOID(), isAgent?AgentHelper.id():ItemHelper.id()); + entityPath.setIOR(obj); + Servant entity; + if (isAgent) + entity = new ActiveEntity(entityPath.getSysKey(), myPOA); + else + entity = new TraceableEntity(entityPath.getSysKey(), myPOA); + synchronized (mEntityCache) { + mEntityCache.put(entityPath, entity); + } + return entity; + + } +} diff --git a/src/main/java/com/c2kernel/entity/TraceableEntity.java b/src/main/java/com/c2kernel/entity/TraceableEntity.java new file mode 100644 index 0000000..c7aff82 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/TraceableEntity.java @@ -0,0 +1,341 @@ +/************************************************************************** + * TraceableEntity + * + * $Workfile$ + * $Revision: 1.108 $ + * $Date: 2005/10/06 14:46:22 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity; + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.common.PersistencyException; +import com.c2kernel.entity.agent.JobArrayList; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.persistency.TransactionManager; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +/************************************************************************** +* +* @author $Author: abranson $ $Date: 2005/10/06 14:46:22 $ +* @version $Revision: 1.108 $ +*
+*                                ,.   '\'\    ,---.
+*                            .  | \\  l\\l_ //    |
+*        _              _       |  \\/ `/  `.|    |
+*      /~\\   \        //~\     | Y |   |   ||  Y |
+*      |  \\   \      //  |     |  \|   |   |\ /  |
+*      [   ||        ||   ]     \   |  o|o  | >  /
+*     ] Y  ||        ||  Y [     \___\_--_ /_/__/
+*     |  \_|l,------.l|_/  |     /.-\(____) /--.\
+*     |   >'          `<   |     `--(______)----'
+*     \  (/~`--____--'~\)  /         u// u / \
+*      `-_>-__________-<_-'          / \  / /|
+*          /(_#(__)#_)\             ( .) / / ]
+*          \___/__\___/              `.`' /   [
+*           /__`--'__\                |`-'    |
+*        /\(__,>-~~ __)               |       |_
+*     /\//\\(  `--~~ )               _l       |-:.
+*     '\/  <^\      /^>             |  `   (  <  \\
+*          _\ >-__-< /_           ,-\  ,-~~->. \  `:._,/
+*        (___\    /___)         (____/    (____)   `-'
+*             Kovax            and, paradoxically, Kovax
+* 
+***************************************************************************/ + +public class TraceableEntity extends ItemPOA +{ + + private int mSystemKey; + private org.omg.PortableServer.POA mPoa; + private TransactionManager mStorage; + + + /************************************************************************** + * Constructor used by the Locator only + **************************************************************************/ + public TraceableEntity( int key, + org.omg.PortableServer.POA poa ) + { + Logger.msg(5,"TraceableEntity::constructor() - SystemKey:" + key ); + + mSystemKey = key; + mPoa = poa; + mStorage = Gateway.getStorage(); + } + + + /************************************************************************** + * + **************************************************************************/ + @Override + public org.omg.PortableServer.POA _default_POA() + { + if(mPoa != null) + return mPoa; + else + return super._default_POA(); + } + + + /************************************************************************** + * + **************************************************************************/ + @Override + public int getSystemKey() + { + Logger.msg(8, "TraceableEntity::getSystemKey() - " + mSystemKey); + return mSystemKey; + } + + /************************************************************************** + * + **************************************************************************/ + @Override + public void initialise( int agentId, + String propString, + String initWfString + ) + throws AccessRightsException, + InvalidDataException, + PersistencyException + { + Logger.msg(1, "TraceableEntity::initialise("+mSystemKey+") - agent:"+agentId); + synchronized (this) { + Workflow lc = null; + PropertyArrayList props = null; + + AgentPath agentPath; + try { + agentPath = new AgentPath(agentId); + } catch (InvalidEntityPathException e) { + throw new AccessRightsException("Invalid Agent Id:" + agentId); + } + + //unmarshalling checks the validity of the received strings + + // create properties + if (!propString.equals("")) { + try { + props = (PropertyArrayList)CastorXMLUtility.unmarshall(propString); + for (Object name : props.list) { + Property thisProp = (Property)name; + mStorage.put(mSystemKey, thisProp, props); + } + } catch (Throwable ex) { + Logger.msg(8, "TraceableEntity::initialise("+mSystemKey+ ") - Properties were invalid: "+propString); + Logger.error(ex); + mStorage.abort(props); + } + mStorage.commit(props); + } + + // create wf + try { + if (initWfString == null || initWfString.equals("")) + lc = new Workflow(new CompositeActivity()); + else + lc = new Workflow((CompositeActivity)CastorXMLUtility.unmarshall(initWfString)); + lc.initialise(mSystemKey, agentPath); + mStorage.put(mSystemKey, lc, null); + } catch (Throwable ex) { + Logger.msg(8, "TraceableEntity::initialise("+mSystemKey+") - Workflow was invalid: "+initWfString); + Logger.error(ex); + } + } + } + + /************************************************************************** + * + **************************************************************************/ + //requestdata is xmlstring + @Override + public void requestAction( int agentId, + String stepPath, + int transitionID, + String requestData + ) + throws AccessRightsException, + InvalidTransitionException, + ObjectNotFoundException, + InvalidDataException, + PersistencyException, + ObjectAlreadyExistsException + { + synchronized (this) { + try { + + Logger.msg(1, "TraceableEntity::request("+mSystemKey+") - " + + Transitions.getTransitionName(transitionID) + " "+stepPath + " by " +agentId ); + + AgentPath agent = new AgentPath(agentId); + Workflow lifeCycle = (Workflow)mStorage.get(mSystemKey, ClusterStorage.LIFECYCLE+"/workflow", null); + + lifeCycle.requestAction( agent, + stepPath, + transitionID, + requestData ); + + // store the workflow if we've changed the state of the domain wf + if (!(stepPath.startsWith("workflow/predefined"))) + mStorage.put(mSystemKey, lifeCycle, null); + + // Normal operation exceptions + } catch (AccessRightsException ex) { + Logger.msg("Propagating AccessRightsException back to the calling agent"); + throw ex; + } catch (InvalidTransitionException ex) { + Logger.msg("Propagating InvalidTransitionException back to the calling agent"); + throw ex; + } catch (ObjectNotFoundException ex) { + Logger.msg("Propagating ObjectNotFoundException back to the calling agent"); + throw ex; + // errors + } catch (ClusterStorageException ex) { + Logger.error(ex); + throw new PersistencyException("Error on storage: "+ex.getMessage(), ""); + } catch (InvalidEntityPathException ex) { + Logger.error(ex); + throw new AccessRightsException("Invalid Agent Id: "+agentId, ""); + } catch (InvalidDataException ex) { + Logger.error(ex); + Logger.msg("Propagating InvalidDataException back to the calling agent"); + throw ex; + } catch (ObjectAlreadyExistsException ex) { + Logger.error(ex); + Logger.msg("Propagating ObjectAlreadyExistsException back to the calling agent"); + throw ex; + // non-CORBA exception hasn't been caught! + } catch (Throwable ex) { + Logger.error("Unknown Error: requestAction on "+mSystemKey+" by "+agentId+" executing "+stepPath); + Logger.error(ex); + throw new InvalidDataException("Extraordinary Exception during execution:"+ex.getClass().getName()+" - "+ex.getMessage(), ""); + } + } + } + + /************************************************************************** + * + **************************************************************************/ + @Override + public String queryLifeCycle( int agentId, + boolean filter + ) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + synchronized (this) { + Logger.msg(1, "TraceableEntity::queryLifeCycle("+mSystemKey+") - agent: " + agentId); + + try + { + AgentPath agent = new AgentPath(agentId); + Workflow wf = (Workflow)mStorage.get(mSystemKey, ClusterStorage.LIFECYCLE+"/workflow", null); + JobArrayList jobBag = new JobArrayList(); + CompositeActivity domainWf = (CompositeActivity)wf.search("workflow/domain"); + jobBag.list = filter?domainWf.calculateJobs(agent, true):domainWf.calculateAllJobs(agent, true); + Logger.msg(1, "TraceableEntity::queryLifeCycle("+mSystemKey+") - Returning "+jobBag.list.size()+" jobs."); + return CastorXMLUtility.marshall( jobBag ); + } + catch( Throwable ex ) + { + Logger.error(ex); + return ""; + } + } + } + + /************************************************************************** + * The description for operation getData. + * + * @param path - the path to the object required + * the suffix 'all' retrieves a listing of all keys on that level + * + * @return The result string in xml format + * except 'all' which returns a comma sep list + * + * @exception ObjectNotFoundException + * ************************************************************************/ + @Override + public String queryData(String path) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + synchronized (this) { + String result = ""; + + Logger.msg(1, "TraceableEntity::queryData("+mSystemKey+") - " + path ); + + try + { // check for cluster contents query + + if (path.endsWith("/all")) + { + int allPos = path.lastIndexOf("all"); + String query = path.substring(0,allPos); + String[] ids = mStorage.getClusterContents( mSystemKey, query ); + + for( int i=0; i transaction aborted!"); + } + + Logger.msg(5, "ActiveEntity::init() - completed."); + } + + /** + * + * @param propsString + * @return Properties + * @throws InvalidDataException Properties cannot be unmarshalled + * @throws ClusterStorageException + */ + private PropertyArrayList initProps( String propsString ) + throws InvalidDataException, + ClusterStorageException + { + PropertyArrayList props = null; + + // create properties + if( propsString != null && !propsString.equals("") ) + { + try + { + props = (PropertyArrayList)CastorXMLUtility.unmarshall(propsString); + } + catch( Exception ex ) + { + //any exception during unmarshall indicates that data was + //incorrect or the castor mapping was not set up + Logger.error(ex); + throw new InvalidDataException(ex.toString(), null); + } + + Iterator iter = props.list.iterator(); + + while( iter.hasNext() ) + mDatabase.put( mSystemKey, iter.next(), props ); + } + else + { + Logger.warning("ActiveEntity::initProps() - NO Properties!"); + } + + return props; + } + + /************************************************************************** + * + * + **************************************************************************/ + @Override + public org.omg.PortableServer.POA _default_POA() + { + if(mPOA != null) + return mPOA; + else + return super._default_POA(); + } + + + /************************************************************************** + * + * + **************************************************************************/ + @Override + public int getSystemKey() + { + return mSystemKey; + } + + + /************************************************************************** + * + * + **************************************************************************/ + @Override + public String queryData(String xpath) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + String result = ""; + int allPos = -1; + + Logger.msg(1, "ActiveEntity::queryData("+mSystemKey+") - " + xpath ); + + try + { + if( (allPos=xpath.indexOf("all")) != -1 ) + { + String query = xpath.substring(0,allPos); + String[] ids = mDatabase.getClusterContents( mSystemKey, query ); + + for( int i=0; i 0) + try + { + Viewpoint view = (Viewpoint) Gateway.getStorage().get(getItemSysKey(), ClusterStorage.VIEWPOINT + "/" + getSchemaType() + "/" + viewName, null); + mOutcome = view.getOutcome().getData(); + } catch (Exception ex) + { // not found, return null + } + } + return mOutcome; + } + + public Outcome getOutcome() + { + Logger.msg(1, "Get outcome"); + return new Outcome(-1, getOutcomeString(), getSchemaType(), getSchemaVersion()); + } + + public int getAgentId() throws ObjectNotFoundException + { + if (mAgentId == -1) + mAgentId = Gateway.getLDAPLookup().getRoleManager().getAgentPath(getAgentName()).getSysKey(); + return mAgentId; + } + + public void setAgentId(int id) + { + mAgentId = id; + agent = null; + } + + public String getAgentName() + { + if (mAgentName == null) + mAgentName = (String) mActProps.get("AgentName"); + return mAgentName; + } + + public void setAgentName(String agentName) + { + mAgentName = agentName; + } + + public String getAgentRole() + { + if (mAgentRole == null) + mAgentRole = (String) mActProps.get("Agent Role"); + return mAgentRole; + } + + public void setAgentRole(String role) + { + mAgentRole = role; + } + + public boolean isOutcomeUsed() + { + String schemaType = getSchemaType(); + return (Boolean.TRUE.equals(getActProp("AlwaysUseOutcome")) || mPossibleTransition == Transitions.DONE || mPossibleTransition == Transitions.COMPLETE) && !(schemaType == null || schemaType.equals("")); + } + + public int getID() + { + return mID; + } + + @Override + public String getName() + { + return mName; + } + + public void setID(int id) + { + mID = id; + mName = String.valueOf(id); + } + + @Override + public void setName(String name) + { + mName = name; + try + { + mID = Integer.parseInt(name); + } catch (NumberFormatException ex) + { + mID = -1; + } + } + + public void setItemSysKey(int sysKey) + { + mItemSysKey = sysKey; + item = null; + } + + @Override + public String getClusterType() + { + return ClusterStorage.JOB; + } + + public boolean equals(Job job) + { + return (getItemSysKey() == job.getItemSysKey()) && this.mStepPath.equals(job.mStepPath) && this.mPossibleTransition == job.mPossibleTransition; + } + + public Object getActProp(String name) + { + return mActProps.get(name); + } + + public String getActPropString(String name) + { + try + { + return mActProps.get(name).toString(); + } catch (NullPointerException ex) + { + return null; + } + } + + public String getStepName() + { + return mStepName; + } + + public void setStepName(String string) + { + mStepName = string; + } + + public String getStepPath() + { + return mStepPath; + } + + public void setStepPath(String string) + { + mStepPath = string; + } + + public int getPossibleTransition() + { + return mPossibleTransition; + } + + public void setPossibleTransition(int lint) + { + mPossibleTransition = lint; + } + + public CastorHashMap getActProps() + { + return mActProps; + } + + public void setActProps(CastorHashMap map) + { + mActProps = map; + } + + public KeyValuePair[] getKeyValuePairs() + { + return mActProps.getKeyValuePairs(); + } + + public void setKeyValuePairs(KeyValuePair[] pairs) + { + mActProps.setKeyValuePairs(pairs); + } + + public int getCurrentState() + { + return mCurrentState; + } + + public void setCurrentState(int string) + { + mCurrentState = string; + } + + public int getTargetState() { + return mTargetState; + } + + public void setTargetState(int mTargetState) { + this.mTargetState = mTargetState; + } + + /** + * Returns the actType. + * + * @return String + */ + public String getStepType() + { + return mStepType; + } + + /** + * Sets the actType. + * + * @param actType + * The actType to set + */ + public void setStepType(String actType) + { + mStepType = actType; + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/entity/agent/JobArrayList.java b/src/main/java/com/c2kernel/entity/agent/JobArrayList.java new file mode 100644 index 0000000..dcb3215 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/agent/JobArrayList.java @@ -0,0 +1,30 @@ +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2003/06/20 11:44:30 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.agent; + +import java.util.ArrayList; + +import com.c2kernel.utils.CastorArrayList; + +public class JobArrayList extends CastorArrayList +{ + + public JobArrayList() + { + super(); + } + + public JobArrayList(ArrayList aList) + { + super(aList); + } + + +} diff --git a/src/main/java/com/c2kernel/entity/agent/JobList.java b/src/main/java/com/c2kernel/entity/agent/JobList.java new file mode 100644 index 0000000..f8a88ee --- /dev/null +++ b/src/main/java/com/c2kernel/entity/agent/JobList.java @@ -0,0 +1,108 @@ +package com.c2kernel.entity.agent; + +import java.util.Iterator; +import java.util.Vector; + +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.RemoteMap; +import com.c2kernel.utils.Logger; + + +/************************************************************************** +* +* @author $Author: abranson $ $Date: 2006/03/03 13:52:21 $ +* @version $Revision: 1.15 $ +***************************************************************************/ +public class JobList extends RemoteMap +{ + + /************************************************************************** + * Empty constructor for Castor + **************************************************************************/ + public JobList(int sysKey, Object locker) + { + super(sysKey, ClusterStorage.JOB, locker); + } + + + /************************************************************************** + * + **************************************************************************/ + public void addJob( Job job ) + { + synchronized(this) { + int jobId = getLastId()+1; + job.setID(jobId); + put(String.valueOf(jobId), job); + } + } + + /** + * Cannot be stored + */ + @Override + public String getClusterType() { + return null; + } + + + public Job getJob(int id) { + return get(String.valueOf(id)); + } + + + /** + * @param job + */ + public void removeJobsWithSysKey( int sysKey ) + { + Iterator currentMembers = values().iterator(); + Job j = null; + + while( currentMembers.hasNext() ) + { + j = currentMembers.next(); + + if( j.getItemSysKey() == sysKey ) + remove( String.valueOf(j.getID()) ); + } + + Logger.msg(5, "JobList::removeJobsWithSysKey() - " + sysKey + " DONE." ); + } + + public void removeJobsForStep( int sysKey, String stepPath ) + { + Iterator currentMembers = values().iterator(); + while( currentMembers.hasNext() ) + { + Job j = currentMembers.next(); + if( j.getItemSysKey() == sysKey && j.getStepPath().equals(stepPath)) + remove( String.valueOf(j.getID()) ); + } + + Logger.msg(5, "JobList::removeJobsForStep() - " + sysKey + " DONE." ); + } + /** + * @param itemKey + * @param string + * @return + */ + public Vector getJobsOfSysKey(int sysKey) + { + Iterator currentMembers = values().iterator(); + Job j = null; + Vector jobs = new Vector(); + + while( currentMembers.hasNext() ) + { + j = currentMembers.next(); + + if( j.getItemSysKey() == sysKey ) + jobs.add(j); + } + + Logger.msg(5, "JobList::getJobsOfSysKey() - returning " + jobs.size() + " Jobs." ); + + return jobs; + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/entity/proxy/AgentProxy.java b/src/main/java/com/c2kernel/entity/proxy/AgentProxy.java new file mode 100644 index 0000000..72ed088 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/AgentProxy.java @@ -0,0 +1,302 @@ +/************************************************************************** + * AgentProxy.java + * + * $Revision: 1.37 $ + * $Date: 2005/10/05 07:39:36 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.proxy; + +import java.util.Date; +import java.util.Enumeration; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.common.PersistencyException; +import com.c2kernel.entity.Agent; +import com.c2kernel.entity.AgentHelper; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.ManageableEntity; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStep; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.outcome.OutcomeValidator; +import com.c2kernel.persistency.outcome.Schema; +import com.c2kernel.process.Gateway; +import com.c2kernel.scripting.ErrorInfo; +import com.c2kernel.scripting.Script; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +/****************************************************************************** + * It is a wrapper for the connection and communication with Agent + * It caches data loaded from the Agent to reduce communication + * + * @version $Revision: 1.37 $ $Date: 2005/10/05 07:39:36 $ + * @author $Author: abranson $ + ******************************************************************************/ +public class AgentProxy extends EntityProxy +{ + AgentPath path; + + /************************************************************************** + * Creates an AgentProxy without cache and change notification + **************************************************************************/ + public AgentProxy( org.omg.CORBA.Object ior, + int systemKey) + throws ObjectNotFoundException + { + super(ior, systemKey); + try { + path = new AgentPath(systemKey); + } catch (InvalidEntityPathException e) { + throw new ObjectNotFoundException(); + } + } + + @Override + public ManageableEntity narrow() throws ObjectNotFoundException + { + try { + return AgentHelper.narrow(mIOR); + } catch (org.omg.CORBA.BAD_PARAM ex) { } + throw new ObjectNotFoundException("CORBA Object was not an Agent, or the server is down."); + } + /************************************************************************** + * + * + **************************************************************************/ + public void initialise( String agentProps, String collector ) + throws AccessRightsException, + InvalidDataException, + PersistencyException, + ObjectNotFoundException + { + Logger.msg(7, "AgentProxy::initialise - started"); + + ((Agent)getEntity()).initialise( agentProps ); + } + + public AgentPath getPath() { + return path; + } + + /** + * Executes a job on the given item using this agent. + * + * @param item - item holding this job + * @param job - the job to execute + */ + public void execute(ItemProxy item, Job job) + throws AccessRightsException, + InvalidTransitionException, + ObjectNotFoundException, + InvalidDataException, + PersistencyException, + ObjectAlreadyExistsException + { + OutcomeValidator validator = null; + String scriptName = job.getActPropString("ScriptName"); + Date startTime = new Date(); + Logger.msg(3, "AgentProxy - executing "+job.getStepPath()+" for "+path.getAgentName()); + // get the outcome validator if present + if (job.isOutcomeUsed()) + { + + // get schema info from act props + String schemaName = job.getActPropString("SchemaType"); + int schemaVersion; + try { + schemaVersion = Integer.parseInt(job.getActPropString("SchemaVersion")); + } catch (Exception e) { + throw new InvalidDataException(e.getClass().getName()+" extracing schema version", ""); + } + Logger.msg(5, "AgentProxy - fetching schema "+schemaName+"_"+schemaVersion+" for validation"); + // retrieve schema + Schema schema = LocalObjectLoader.getSchema(schemaName, schemaVersion); + + if (schema == null) + throw new InvalidDataException("Job references outcome type "+schemaName+" version "+schemaVersion+" that does not exist in this centre.", ""); + + try { + validator = OutcomeValidator.getValidator(schema); + } catch (Exception e) { + throw new InvalidDataException("Could not create validator: "+e.getMessage(), ""); + } + } + + if(scriptName != null && scriptName.length() > 0 && + (job.getPossibleTransition() == Transitions.DONE || job.getPossibleTransition() == Transitions.COMPLETE)) { + Logger.msg(3, "AgentProxy - executing script "+scriptName); + try { + + // pre-validate outcome from script if there is one + if (job.getOutcomeString()!= null && validator != null) { + Logger.msg(5, "AgentProxy - validating outcome before script execution"); + String error = validator.validate(job.getOutcomeString()); + if (error.length() > 0) { + Logger.error("Outcome not valid: \n " + error); + throw new InvalidDataException(error, ""); + } + } + + // load script + ErrorInfo scriptErrors = (ErrorInfo)callScript(item, job); + + if (scriptErrors.getFatal()) { + Logger.msg(3, "AgentProxy - fatal script error"); + Logger.error(scriptErrors.getErrors()); + throw new InvalidDataException("Fatal Script Error: \n"+scriptErrors.getErrors(), ""); + } + if (scriptErrors.getErrors().length() > 0) + Logger.warning("Script errors: "+scriptErrors.getErrors()); + } catch (ScriptingEngineException ex) { + Logger.error(ex); + throw new InvalidDataException(ex.getMessage(), ""); + } + } + + if (job.isOutcomeUsed()) { + Logger.msg(3, "AgentProxy - validating outcome"); + String error = validator.validate(job.getOutcomeString()); + if (error.length() > 0) + throw new InvalidDataException(error, ""); + } + + job.setAgentId(getSystemKey()); + Logger.msg(3, "AgentProxy - submitting job to item proxy"); + item.requestAction(job); + if (Logger.doLog(3)) { + Date timeNow = new Date(); + long secsNow = (timeNow.getTime()-startTime.getTime())/1000; + Logger.msg(3, "Execution took "+secsNow+" seconds"); + } + } + + public Object callScript(ItemProxy item, Job job) throws ScriptingEngineException { + Script script = new Script(item, this, job); + return script.execute(); + } + + /** + * Standard execution of jobs. Note that this method should always be the one used from clients - all execution + * parameters are taken from the job where they're probably going to be correct. + * + * @param job + * @throws AccessRightsException + * @throws InvalidDataException + * @throws InvalidTransitionException + * @throws ObjectNotFoundException + * @throws PersistencyException + * @throws ObjectAlreadyExistsException + */ + public void execute(Job job) + throws AccessRightsException, + InvalidDataException, + InvalidTransitionException, + ObjectNotFoundException, + PersistencyException, + ObjectAlreadyExistsException + { + try { + ItemProxy targetItem = (ItemProxy)Gateway.getProxyManager().getProxy(new EntityPath(job.getItemSysKey())); + execute(targetItem, job); + } catch (InvalidEntityPathException e) { + throw new ObjectNotFoundException("Job contained invalid item sysKey: "+job.getItemSysKey(), ""); + } + } + + public void execute(ItemProxy item, String predefStep, C2KLocalObject obj) + throws AccessRightsException, + InvalidDataException, + InvalidTransitionException, + ObjectNotFoundException, + PersistencyException, + ObjectAlreadyExistsException + { + String param; + try { + param = marshall(obj); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidDataException("Error on marshall", ""); + } + execute(item, predefStep, param); + } + + public void execute(ItemProxy item, String predefStep, String param) + throws AccessRightsException, + InvalidDataException, + InvalidTransitionException, + ObjectNotFoundException, + PersistencyException, + ObjectAlreadyExistsException + { + String[] params = new String[1]; + params[0] = param; + execute(item, predefStep, params); + } + + public void execute(ItemProxy item, String predefStep, String[] params) + throws AccessRightsException, + InvalidDataException, + InvalidTransitionException, + ObjectNotFoundException, + PersistencyException, + ObjectAlreadyExistsException + { + item.requestAction(getSystemKey(), "workflow/predefined/"+predefStep, Transitions.DONE, PredefinedStep.bundleData(params)); + } + + /** Wrappers for scripts */ + public String marshall(Object obj) throws Exception { + return CastorXMLUtility.marshall(obj); + } + + public Object unmarshall(String obj) throws Exception { + return CastorXMLUtility.unmarshall(obj); + } + + /** Let scripts resolve items */ + public ItemProxy searchItem(String name) throws ObjectNotFoundException { + Enumeration results = Gateway.getLDAPLookup().search(new DomainPath(""),name); + + Path returnPath = null; + if (!results.hasMoreElements()) + throw new ObjectNotFoundException(name, ""); + + while(results.hasMoreElements()) { + Path nextMatch = results.nextElement(); + if (returnPath != null && nextMatch.getSysKey() != -1 && returnPath.getSysKey() != nextMatch.getSysKey()) + throw new ObjectNotFoundException("Too many items with that name"); + returnPath = nextMatch; + } + + return (ItemProxy)Gateway.getProxyManager().getProxy(returnPath); + } + + public ItemProxy getItem(String path) throws ObjectNotFoundException { + return (getItem(new DomainPath(path))); + } + + public ItemProxy getItem(DomainPath path) throws ObjectNotFoundException { + return (ItemProxy)Gateway.getProxyManager().getProxy(path); + } + + public ItemProxy getItemBySysKey(int sysKey) throws ObjectNotFoundException, InvalidEntityPathException { + return (ItemProxy)Gateway.getProxyManager().getProxy(new EntityPath(sysKey)); + } +} diff --git a/src/main/java/com/c2kernel/entity/proxy/DomainPathSubscriber.java b/src/main/java/com/c2kernel/entity/proxy/DomainPathSubscriber.java new file mode 100644 index 0000000..4089325 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/DomainPathSubscriber.java @@ -0,0 +1,18 @@ +package com.c2kernel.entity.proxy; + +import com.c2kernel.lookup.DomainPath; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2004/02/05 16:11:57 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public interface DomainPathSubscriber { + + public void pathAdded(DomainPath path); + public void pathRemoved(DomainPath path); +} diff --git a/src/main/java/com/c2kernel/entity/proxy/EntityProxy.java b/src/main/java/com/c2kernel/entity/proxy/EntityProxy.java new file mode 100644 index 0000000..fae2e28 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/EntityProxy.java @@ -0,0 +1,248 @@ +/************************************************************************** + * EntityProxy.java + * + * $Revision: 1.35 $ + * $Date: 2005/05/10 11:40:09 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.proxy; + +import java.util.HashMap; +import java.util.Iterator; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.ManageableEntity; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + + +/****************************************************************************** +* It is a wrapper for the connection and communication with Entities. +* It can cache data loaded from the Entity to reduce communication with it. +* This cache is syncronised with corresponding Entity through an event mechanism. +* +* @version $Revision: 1.35 $ $Date: 2005/05/10 11:40:09 $ +* @author $Author: abranson $ +******************************************************************************/ + +abstract public class EntityProxy implements ManageableEntity +{ + + protected ManageableEntity mEntity = null; + protected org.omg.CORBA.Object mIOR; + protected int mSystemKey; + private HashMap, EntityProxyObserver> mSubscriptions; + + /************************************************************************** + * + **************************************************************************/ + protected EntityProxy( org.omg.CORBA.Object ior, + int systemKey) + throws ObjectNotFoundException + { + Logger.msg(8,"EntityProxy::EntityProxy() - Initialising '" +systemKey+ "' entity"); + + initialise( ior, systemKey); + } + + /************************************************************************** + * + **************************************************************************/ + private void initialise( org.omg.CORBA.Object ior, + int systemKey) + throws ObjectNotFoundException + { + Logger.msg(8, "EntityProxy::initialise() - Initialising '" +systemKey+ "' entity"); + + mIOR = ior; + mSystemKey = systemKey; + mSubscriptions = new HashMap, EntityProxyObserver>(); + } + + + /************************************************************************** + * + **************************************************************************/ + public ManageableEntity getEntity() throws ObjectNotFoundException + { + if (mEntity == null) { + mEntity = narrow(); + } + return mEntity; + } + + abstract public ManageableEntity narrow() throws ObjectNotFoundException; + + /************************************************************************** + * + **************************************************************************/ + //check who is using.. and if toString() is sufficient + @Override + public int getSystemKey() + { + return mSystemKey; + } + + + /************************************************************************** + * + **************************************************************************/ + @Override + public String queryData( String path ) + throws ObjectNotFoundException + { + + try { + Logger.msg(7, "EntityProxy.queryData() - "+mSystemKey+"/"+path); + if (path.endsWith("all")) { + Logger.msg(7, "EntityProxy.queryData() - listing contents"); + String[] result = Gateway.getStorage().getClusterContents(mSystemKey, path.substring(0, path.length()-3)); + StringBuffer retString = new StringBuffer(); + for (int i = 0; i < result.length; i++) { + retString.append(result[i]); + if (i"+e.getMessage()+""; + } + } + + public String[] getContents( String path ) throws ObjectNotFoundException { + try { + return Gateway.getStorage().getClusterContents(mSystemKey, path.substring(0, path.length())); + } catch (ClusterStorageException e) { + throw new ObjectNotFoundException(e.toString()); + } + } + + + /************************************************************************** + * + **************************************************************************/ + public C2KLocalObject getObject( String xpath ) + throws ObjectNotFoundException + { + // load from storage, falling back to proxy loader if not found in others + try + { + return Gateway.getStorage().get( mSystemKey, xpath , null); + } + catch( ClusterStorageException ex ) + { + Logger.msg(4, "Exception loading object :"+mSystemKey+"/"+xpath); + throw new ObjectNotFoundException( ex.toString() ); + } + } + + + + public String getProperty( String name ) + throws ObjectNotFoundException + { + Logger.msg(5, "Get property "+name+" from syskey/"+mSystemKey); + Property prop = (Property)getObject("Property/"+name); + try + { + return prop.getValue(); + } + catch (NullPointerException ex) + { + throw new ObjectNotFoundException(); + } + } + + public String getName() + { + try { + return getProperty("Name"); + } catch (ObjectNotFoundException ex) { + return null; + } + } + + + /************************************************************************** + * Subscription methods + **************************************************************************/ + + public void subscribe (MemberSubscription newSub) { + + newSub.setSubject(this); + synchronized (this){ + mSubscriptions.put( newSub, newSub.getObserver() ); + } + new Thread(newSub).start(); + Logger.msg(7, "Subscribed "+newSub.getObserver().getClass().getName()+" for "+newSub.interest); + } + + public void unsubscribe(EntityProxyObserver observer) + { + synchronized (this){ + for (Iterator> e = mSubscriptions.keySet().iterator(); e.hasNext();) { + MemberSubscription thisSub = e.next(); + if (mSubscriptions.get( thisSub ) == observer) { + e.remove(); + Logger.msg(7, "Unsubscribed "+observer.getClass().getName()); + } + } + } + } + + public void dumpSubscriptions(int logLevel) { + if (mSubscriptions.size() == 0) return; + Logger.msg(logLevel, "Subscriptions to proxy "+mSystemKey+":"); + synchronized(this) { + for (MemberSubscription element : mSubscriptions.keySet()) { + EntityProxyObserver obs = element.getObserver(); + if (obs != null) + Logger.msg(logLevel, " "+element.getObserver().getClass().getName()+" subscribed to "+element.interest); + else + Logger.msg(logLevel, " Phantom subscription to "+element.interest); + } + } + } + + public void notify(ProxyMessage message) { + Logger.msg(4, "EntityProxy.notify() - Received change notification for "+message.getPath()+" on "+mSystemKey); + synchronized (this){ + if (!message.getServer().equals(EntityProxyManager.serverName)) + Gateway.getStorage().clearCache(mSystemKey, message.getPath()); + for (Iterator> e = mSubscriptions.keySet().iterator(); e.hasNext();) { + MemberSubscription newSub = e.next(); + if (newSub.getObserver() == null) { // phantom + Logger.msg(4, "Removing phantom subscription to "+newSub.interest); + e.remove(); + } + else + newSub.update(message.getPath(), message.getState()); + } + } + } + + /** + * If this is reaped, clear out the cache for it too. + */ + @Override + protected void finalize() throws Throwable { + Logger.msg(7, "Proxy "+mSystemKey+" reaped"); + Gateway.getStorage().clearCache(mSystemKey, null); + Gateway.getProxyManager().removeProxy(mSystemKey); + super.finalize(); + } + +} diff --git a/src/main/java/com/c2kernel/entity/proxy/EntityProxyManager.java b/src/main/java/com/c2kernel/entity/proxy/EntityProxyManager.java new file mode 100644 index 0000000..192a984 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/EntityProxyManager.java @@ -0,0 +1,339 @@ +/************************************************************************** + * EntityProxyFactory.java + * + * $Revision: 1.45 $ + * $Date: 2005/05/10 11:40:09 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.proxy; + +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.SoftCache; +import com.c2kernel.utils.server.SimpleTCPIPServer; + + +public class EntityProxyManager +{ + SoftCache proxyPool = new SoftCache(50); + HashMap treeSubscribers = new HashMap(); + HashMap connections = new HashMap(); + + // server objects + static ArrayList proxyClients = new ArrayList(); + static SimpleTCPIPServer proxyServer = null; + static String serverName = null; + + /** + * Create an entity proxy manager to listen for proxy events and reap unused proxies + */ + public EntityProxyManager() + { + Logger.msg(5, "EntityProxyManager - Starting....."); + + Enumeration servers = Gateway.getLDAPLookup().searchEntities(new DomainPath("/servers")); + while(servers.hasMoreElements()) { + Path thisServerPath = servers.nextElement(); + try { + int syskey = thisServerPath.getSysKey(); + String remoteServer = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/Name", null)).getValue(); + String portStr = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/ProxyPort", null)).getValue(); + int remotePort = Integer.parseInt(portStr); + connectToProxyServer(remoteServer, remotePort); + + } catch (Exception ex) { + Logger.error("Exception retrieving proxy server connection data for "+thisServerPath); + Logger.error(ex); + } + } + } + + public void connectToProxyServer(String name, int port) { + ProxyServerConnection oldConn = connections.get(name); + if (oldConn != null) + oldConn.shutdown(); + connections.put(name, new ProxyServerConnection(name, port, this)); + } + + + protected void resubscribe(ProxyServerConnection conn) { + synchronized (proxyPool) { + for (Integer key : proxyPool.keySet()) { + ProxyMessage sub = new ProxyMessage(key.intValue(), ProxyMessage.ADDPATH, false); + Logger.msg(5, "Subscribing to entity "+key); + conn.sendMessage(sub); + } + } + } + + /** + * @param sub + */ + private void sendMessage(ProxyMessage sub) { + for (ProxyServerConnection element : connections.values()) { + element.sendMessage(sub); + } + + } + + public void shutdown() { + Logger.msg("EntityProxyManager.shutdown() - flagging shutdown of server connections"); + for (ProxyServerConnection element : connections.values()) { + element.shutdown(); + } + } + + protected void processMessage(ProxyMessage thisMessage) throws InvalidDataException { + if (Logger.doLog(9)) Logger.msg(9, thisMessage.toString()); + + if (thisMessage.getPath().equals(ProxyMessage.PINGPATH)) // ping response + return; + + if (thisMessage.getSysKey() == ProxyMessage.NA) // must be domain path info + informTreeSubscribers(thisMessage.getState(), thisMessage.getPath()); + else { + // proper proxy message + Logger.msg(5, "Received proxy message: "+thisMessage.toString()); + Integer key = new Integer(thisMessage.getSysKey()); + EntityProxy relevant = proxyPool.get(key); + if (relevant == null) + Logger.warning("Received proxy message for sysKey "+thisMessage.getSysKey()+" which we don't have a proxy for."); + else + try { + relevant.notify(thisMessage); + } catch (Throwable ex) { + Logger.error("Error caught notifying proxy listener "+relevant.toString()+" of "+thisMessage.toString()); + Logger.error(ex); + } + } + } + + private void informTreeSubscribers(boolean state, String path) { + DomainPath last = new DomainPath(path); + DomainPath parent; boolean first = true; + synchronized(treeSubscribers) { + while((parent = last.getParent()) != null) { + + for (DomainPathSubscriber sub : treeSubscribers.keySet()) { + DomainPath interest = treeSubscribers.get(sub); + if (interest.equals(parent)) { + if (state == ProxyMessage.ADDED) + sub.pathAdded(last); + else if (first) + sub.pathRemoved(last); + } + } + last = parent; + first = false; + } + } + } + + public void subscribeTree(DomainPathSubscriber sub, DomainPath interest) { + synchronized(treeSubscribers) { + treeSubscribers.put(sub, interest); + } + } + + public void unsubscribeTree(DomainPathSubscriber sub) { + synchronized(treeSubscribers) { + treeSubscribers.remove(sub); + } + } + + /************************************************************************** + * + **************************************************************************/ + private EntityProxy createProxy( org.omg.CORBA.Object ior, + int systemKey, + boolean isItem ) + throws ObjectNotFoundException + { + + EntityProxy newProxy = null; + + Logger.msg(5, "EntityProxyFactory::creating proxy on entity " + systemKey); + + if( isItem ) + { + newProxy = new ItemProxy(ior, systemKey); + } + else + { + newProxy = new AgentProxy(ior, systemKey); + } + + // subscribe to changes from server + ProxyMessage sub = new ProxyMessage(systemKey, ProxyMessage.ADDPATH, false); + sendMessage(sub); + reportCurrentProxies(9); + return ( newProxy ); + } + + protected void removeProxy( int systemKey ) + { + ProxyMessage sub = new ProxyMessage(systemKey, ProxyMessage.DELPATH, true); + Logger.msg(5,"EntityProxyManager.removeProxy() - Unsubscribing to proxy informer for "+systemKey); + sendMessage(sub); + } + + + /************************************************************************** + * EntityProxy getProxy( ManageableEntity, SystemKey) + * + * Called by the other GetProxy methods. Fills in either the ior or the + * SystemKey + **************************************************************************/ + private EntityProxy getProxy( org.omg.CORBA.Object ior, + int systemKey, + boolean isItem ) + throws ObjectNotFoundException + { + Integer key = new Integer(systemKey); + + synchronized(proxyPool) { + EntityProxy newProxy; + // return it if it exists + newProxy = proxyPool.get(key); + if (newProxy == null) { + // create a new one + newProxy = createProxy(ior, systemKey, isItem ); + proxyPool.put(key, newProxy); + } + return newProxy; + + } + } + + /************************************************************************** + * EntityProxy getProxy( String ) + * + * Proxy from Alias + **************************************************************************/ + public EntityProxy getProxy( Path path ) + throws ObjectNotFoundException + { + + //convert namePath to dn format + Logger.msg(8,"EntityProxyFactory::getProxy(" + path.toString() + ")"); + boolean isItem = !(path.getEntity() instanceof AgentPath); + return getProxy( Gateway.getLDAPLookup().getIOR(path), + path.getSysKey(), + isItem ); + + } + + /************************************************************************** + * void reportCurrentProxies() + * + * A utility to Dump the current proxies loaded + **************************************************************************/ + public void reportCurrentProxies(int logLevel) + { + if (!Logger.doLog(logLevel)) return; + Logger.msg(logLevel, "Current proxies: "); + try { + synchronized(proxyPool) { + Iterator i = proxyPool.keySet().iterator(); + + for( int count=0; i.hasNext(); count++ ) + { + Integer nextProxy = i.next(); + EntityProxy thisProxy = proxyPool.get(nextProxy); + if (thisProxy != null) + Logger.msg(logLevel, + "" + count + ": " + + proxyPool.get(nextProxy).getClass().getName() + + ": " + nextProxy); + } + } + } catch (ConcurrentModificationException ex) { + Logger.msg(logLevel, "Proxy cache modified. Aborting."); + } + } + + + /************************************************************************** + * Static Proxy Server methods + **************************************************************************/ + + /** + * Initialises the Proxy event UDP server listening on 'Host.Proxy.port' from c2kprops + * @param c2kProps + */ + public static void initServer() + { + Logger.msg(5, "EntityProxyFactory::initServer - Starting....."); + String port = Gateway.getProperty("ItemServer.Proxy.port"); + serverName = Gateway.getProperty("ItemServer.name"); + if (port == null) { + Logger.error("ItemServer.Proxy.port not defined in connect file. Remote proxies will not be informed of entity changes."); + return; + } + + // set up the proxy server + try { + int portNo = Integer.parseInt(port); + Logger.msg(5, "EntityProxyFactory::initServer - Initialising proxy informer on port "+port); + proxyServer = new SimpleTCPIPServer(portNo, ProxyClientConnection.class, 200); + proxyServer.startListening(); + } catch (Exception ex) { + Logger.error("Error setting up Proxy Server. Remote proxies will not be informed of entity changes."); + Logger.error(ex); + } + } + + public static void sendProxyEvent(ProxyMessage message) { + if (proxyServer != null && message.getPath() != null) + synchronized(proxyClients) { + for (ProxyClientConnection client : proxyClients) { + client.sendMessage(message); + } + } + } + + public static void reportConnections(int logLevel) { + synchronized(proxyClients) { + Logger.msg(logLevel, "Currently connected proxy clients:"); + for (ProxyClientConnection client : proxyClients) { + Logger.msg(logLevel, " "+client); + } + } + } + + public static void shutdownServer() { + if (proxyServer != null) { + Logger.msg(1, "EntityProxyManager: Closing Server."); + proxyServer.stopListening(); + } + } + + public static void registerProxyClient(ProxyClientConnection client) { + synchronized(proxyClients) { + proxyClients.add(client); + } + } + + public static void unRegisterProxyClient(ProxyClientConnection client) { + synchronized(proxyClients) { + proxyClients.remove(client); + } + } +} + diff --git a/src/main/java/com/c2kernel/entity/proxy/EntityProxyObserver.java b/src/main/java/com/c2kernel/entity/proxy/EntityProxyObserver.java new file mode 100644 index 0000000..3ddb99c --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/EntityProxyObserver.java @@ -0,0 +1,27 @@ +package com.c2kernel.entity.proxy; + +import com.c2kernel.entity.C2KLocalObject; + + + +public interface EntityProxyObserver +{ + /************************************************************************** + * Subscribed items are broken apart and fed one by one to these methods. + * Replacement after an event is done by feeding the new memberbase with the same id. + * ID could be an XPath? + **************************************************************************/ + public void add(V contents); + + /************************************************************************** + * the 'type' parameter should be an indication of the type of object + * supplied so that the subscriber can associate the call back with + * one of its subscriptions. If we go with an Xpath subscription form, + * then the id will probably be sufficient. + * Should be comparable (substring whatever) with the parameter given to + * the subscribe method of ItemProxy. + **************************************************************************/ + public void remove(String id); + + public void control(String control, String msg); +} diff --git a/src/main/java/com/c2kernel/entity/proxy/ItemProxy.java b/src/main/java/com/c2kernel/entity/proxy/ItemProxy.java new file mode 100644 index 0000000..658e0c8 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/ItemProxy.java @@ -0,0 +1,213 @@ +/************************************************************************** + * ItemProxy.java + * + * $Revision: 1.25 $ + * $Date: 2005/05/10 11:40:09 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.proxy; + +import java.util.ArrayList; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.common.PersistencyException; +import com.c2kernel.entity.Item; +import com.c2kernel.entity.ItemHelper; +import com.c2kernel.entity.ManageableEntity; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.agent.JobArrayList; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +/****************************************************************************** + * It is a wrapper for the connection and communication with Item + * It caches data loaded from the Item to reduce communication + * + * @version $Revision: 1.25 $ $Date: 2005/05/10 11:40:09 $ + * @author $Author: abranson $ + ******************************************************************************/ +public class ItemProxy extends EntityProxy +{ + + /************************************************************************** + * + **************************************************************************/ + protected ItemProxy( org.omg.CORBA.Object ior, + int systemKey) + throws ObjectNotFoundException + { + super(ior, systemKey); + + } + + @Override + public ManageableEntity narrow() throws ObjectNotFoundException + { + try { + return ItemHelper.narrow(mIOR); + } catch (org.omg.CORBA.BAD_PARAM ex) { } + throw new ObjectNotFoundException("CORBA Object was not an Item, or the server is down."); + } + /************************************************************************** + * + * + **************************************************************************/ + public void initialise( int agentId, + String itemProps, + String workflow ) + throws AccessRightsException, + InvalidDataException, + PersistencyException, + ObjectNotFoundException + { + Logger.msg(7, "ItemProxy::initialise - started"); + + ((Item)getEntity()).initialise( agentId, itemProps, workflow ); + } + + public void setProperty(AgentProxy agent, String name, String value) + throws AccessRightsException, + PersistencyException + { + String[] params = new String[2]; + params[0] = name; + params[1] = value; + try { + agent.execute(this, "WriteProperty", params); + } catch (AccessRightsException e) { + throw (e); + } catch (PersistencyException e) { + throw (e); + } catch (Exception e) { + Logger.error(e); + throw new PersistencyException("Could not store property"); + } + } + /************************************************************************** + * + **************************************************************************/ + protected void requestAction( Job thisJob ) + throws AccessRightsException, + InvalidTransitionException, + ObjectNotFoundException, + InvalidDataException, + PersistencyException, + ObjectAlreadyExistsException + { + String outcome = thisJob.getOutcomeString(); + // check fields that should have been filled in + if (outcome==null) + if (thisJob.isOutcomeUsed()) + throw new InvalidDataException("Outcome is required.", ""); + else + outcome=""; + + if (thisJob.getAgentId() == -1) + throw new InvalidDataException("No Agent specified.", ""); + + Logger.msg(7, "ItemProxy - executing "+thisJob.getStepPath()+" for "+thisJob.getAgentName()); + requestAction (thisJob.getAgentId(), thisJob.getStepPath(), + thisJob.getPossibleTransition(), outcome); + } + + //requestData is xmlString + public void requestAction( int agentId, + String stepPath, + int transitionID, + String requestData + ) + throws AccessRightsException, + InvalidTransitionException, + ObjectNotFoundException, + InvalidDataException, + PersistencyException, + ObjectAlreadyExistsException + { + ((Item)getEntity()).requestAction( agentId, + stepPath, + transitionID, + requestData ); + } + + /************************************************************************** + * + **************************************************************************/ + public String queryLifeCycle( int agentId, + boolean filter + ) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + return ((Item)getEntity()).queryLifeCycle( agentId, + filter ); + } + + + /************************************************************************** + * + **************************************************************************/ + private ArrayList getJobList(int agentId, boolean filter) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + JobArrayList thisJobList; + try { + String jobs = queryLifeCycle(agentId, filter); + thisJobList = (JobArrayList)CastorXMLUtility.unmarshall(jobs); + } + catch (Exception e) { + Logger.error(e); + throw new PersistencyException("Exception::ItemProxy::getJobList() - Cannot unmarshall the jobs", null); + } + return thisJobList.list; + } + + public ArrayList getJobList(AgentProxy agent) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + return getJobList(agent.getSystemKey()); + } + + private ArrayList getJobList(int agentId) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException + { + return getJobList(agentId, true); + } + + private Job getJobByName(String actName, int agentId) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException { + + ArrayList jobList = getJobList(agentId); + for (Job job : jobList) { + int transition = job.getPossibleTransition(); + if (job.getStepName().equals(actName)) + if (transition == Transitions.COMPLETE || transition == Transitions.DONE) + return job; + } + return null; + + } + + public Job getJobByName(String actName, AgentProxy agent) + throws AccessRightsException, + ObjectNotFoundException, + PersistencyException { + return getJobByName(actName, agent.getSystemKey()); + } +} diff --git a/src/main/java/com/c2kernel/entity/proxy/MemberSubscription.java b/src/main/java/com/c2kernel/entity/proxy/MemberSubscription.java new file mode 100644 index 0000000..157297f --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/MemberSubscription.java @@ -0,0 +1,118 @@ + +package com.c2kernel.entity.proxy; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.utils.Logger; + +public class MemberSubscription implements Runnable { + public static final String ERROR = "Error"; + public static final String END = "theEND"; + + EntityProxy subject; + String interest; + // keep the subscriber by weak reference, so it is not kept from the garbage collector if no longer used + WeakReference> observerReference; + ArrayList contents = new ArrayList(); + boolean preLoad; + + public MemberSubscription(EntityProxyObserver observer, String interest, boolean preLoad) { + setObserver(observer); + this.interest = interest; + this.preLoad = preLoad; + } + + @Override + public void run() { + Thread.currentThread().setName("Member Subscription: "+subject.getSystemKey()+":"+interest); + if (preLoad) loadChildren(); + } + + private void loadChildren() { + C newMember; + EntityProxyObserver observer = getObserver(); + if (observer == null) return; //reaped + try { + // fetch contents of path + String children = subject.queryData(interest+"/all"); + StringTokenizer tok = new StringTokenizer(children, ","); + ArrayList newContents = new ArrayList(); + while (tok.hasMoreTokens()) + newContents.add(tok.nextToken()); + + // look to see what's new + for (String newChild: newContents) { + + // load child object + try { + newMember = (C)subject.getObject(interest+"/"+newChild); + contents.remove(newChild); + observer.add(newMember); + } catch (ObjectNotFoundException ex) { + observer.control(ERROR, "Listed member "+newChild+" was not found."); + } + } + // report what's left in old contents as deleted + for (String oldChild: contents) { + observer.remove(interest+"/"+oldChild); + } + //replace contents arraylist + contents = newContents; + //report that we're done + observer.control(END, null); + } catch (Exception ex) { + observer.control(ERROR, "Query on "+interest+" failed with "+ex); + } + } + + public boolean isRelevant(String path) { + Logger.msg(7, "Checking relevance of "+path+" to "+interest); + return (path.startsWith(interest)); + } + + public void update(String path, boolean deleted) { + EntityProxyObserver observer = getObserver(); + if (observer == null) return; //reaped + Logger.msg(7, "Processing proxy message path "+path +" for "+observer+". Interest: "+interest+" Was Deleted:"+deleted); + if (!path.startsWith(interest)) // doesn't concern us + return; + + if (path.equals(interest)) // refresh contents + loadChildren(); + else { + String name = path.substring(interest.length()); + if (deleted) { + Logger.msg(4, "Removing "+path); + contents.remove(name); + observer.remove(name); + } + else { + try { + C newMember = (C)subject.getObject(path); + Logger.msg(4, "Adding "+path); + contents.add(name); + observer.add(newMember); + } catch (ObjectNotFoundException e) { + Logger.error("Member Subscription: could not load "+path); + Logger.error(e); + } + } + } + } + + public void setObserver(EntityProxyObserver observer) { + observerReference = new WeakReference>(observer); + } + + public void setSubject(EntityProxy subject) { + this.subject = subject; + } + + public EntityProxyObserver getObserver() { + return observerReference.get(); + } +} + diff --git a/src/main/java/com/c2kernel/entity/proxy/ProxyClientConnection.java b/src/main/java/com/c2kernel/entity/proxy/ProxyClientConnection.java new file mode 100644 index 0000000..9687f22 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/ProxyClientConnection.java @@ -0,0 +1,185 @@ +package com.c2kernel.entity.proxy; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.InterruptedIOException; +import java.io.PrintWriter; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Iterator; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.server.SocketHandler; + +/************************************************************************** + * + * $Revision: 1.18 $ + * $Date: 2005/05/10 11:40:09 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ProxyClientConnection implements SocketHandler { + + Socket clientSocket = null; + static int clientId = -1; + int thisClientId; + ArrayList sysKeys; + PrintWriter response; + BufferedReader request; + boolean closing = false; + + public ProxyClientConnection() { + super(); + thisClientId = ++clientId; + EntityProxyManager.registerProxyClient(this); + Logger.msg(1, "Proxy Client Connection Handler "+thisClientId+" ready."); + } + + + @Override + public String getName() { + return "Proxy Client Connection"; + } + + @Override + public boolean isBusy() { + return clientSocket != null; + } + + @Override + public synchronized void setSocket(Socket newSocket) { + try { + Logger.msg(1, "Proxy Client Connection "+thisClientId+" connect from "+newSocket.getInetAddress()+":"+newSocket.getPort()); + newSocket.setSoTimeout(500); + clientSocket = newSocket; + response = new PrintWriter(clientSocket.getOutputStream(), true); + sysKeys = new ArrayList(); + } catch (SocketException ex) { + Logger.msg("Could not set socket timeout:"); + Logger.error(ex); + closeSocket(); + } catch (IOException ex) { + Logger.msg("Could not setup output stream:"); + Logger.error(ex); + closeSocket(); + } + } + + /** + * Main loop. Reads proxy commands from the client and acts on them. + */ + @Override + public void run() { + Thread.currentThread().setName("Proxy Client Connection: "+clientSocket.getInetAddress()); + Logger.msg(7, "ProxyClientConnection "+thisClientId+" - Setting up proxy client connection with "+clientSocket.getInetAddress()); + try { + request = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); + String input = null; + ProxyMessage thisMessage; + while (clientSocket != null) { + try { + input = request.readLine(); + Logger.msg(9, "ProxyClientConnection "+thisClientId+" - received "+input); + thisMessage = new ProxyMessage(input); + processMessage(thisMessage); + } catch (InterruptedIOException ex) { //timeout + } catch (InvalidDataException ex) { // invalid proxy message + Logger.error("ProxyClientConnection "+thisClientId+" - Invalid proxy message: "+input); + } + + } + } catch (IOException ex) { + if (!closing) + Logger.error("ProxyClientConnection "+thisClientId+" - Error reading from socket."); + } + closeSocket(); + Logger.msg(1, "ProxyClientConnection "+thisClientId+" closed."); + } + + private void processMessage(ProxyMessage message) throws InvalidDataException { + + // proxy disconnection + if (message.getPath().equals(ProxyMessage.BYEPATH)) { + Logger.msg(7, "ProxyClientConnection "+thisClientId+" disconnecting"); + closeSocket(); + } + + // proxy checking connection + else if (message.getPath().equals(ProxyMessage.PINGPATH)) + response.println(ProxyMessage.pingMessage); + + // new subscription to entity changes + else if (message.getPath().equals(ProxyMessage.ADDPATH)) { + Logger.msg(7, "ProxyClientConnection "+thisClientId+" subscribed to "+message.getSysKey()); + synchronized (sysKeys) { + sysKeys.add(new Integer(message.getSysKey())); + } + } + + // remove of subscription to entity changes + else if (message.getPath().equals(ProxyMessage.DELPATH)) { + synchronized (sysKeys) { + sysKeys.remove(new Integer(message.getSysKey())); + } + Logger.msg(7, "ProxyClientConnection "+thisClientId+" unsubscribed from "+message.getSysKey()); + } + + else // unknown message + Logger.error("ProxyClientConnection "+thisClientId+" - Unknown message type: "+message); + + } + + public synchronized void sendMessage(ProxyMessage message) { + if (clientSocket==null) return; // idle + boolean relevant = message.getSysKey() == ProxyMessage.NA; + synchronized (sysKeys) { + for (Iterator iter = sysKeys.iterator(); iter.hasNext() && !relevant;) { + Integer thisKey = iter.next(); + if (thisKey.intValue() == message.getSysKey()) + relevant = true; + } + } + if (!relevant) return; // not for our client + + response.println(message); + } + + @Override + public void shutdown() { + if (isBusy()) { + closing = true; + Logger.msg("ProxyClientConnection "+thisClientId+" closing."); + closeSocket(); + } + } + + @Override + public String toString() { + if (clientSocket == null) return thisClientId+": idle"; + else return thisClientId+": "+clientSocket.getInetAddress(); + } + + private synchronized void closeSocket() { + if (clientSocket==null) return; + try { + request.close(); + response.close(); + clientSocket.close(); + } catch (IOException e) { + Logger.error("ProxyClientConnection "+thisClientId+" - Could not close socket."); + Logger.error(e); + } + synchronized (sysKeys) { + sysKeys = null; + } + + clientSocket = null; + + } + +} diff --git a/src/main/java/com/c2kernel/entity/proxy/ProxyMessage.java b/src/main/java/com/c2kernel/entity/proxy/ProxyMessage.java new file mode 100644 index 0000000..62866eb --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/ProxyMessage.java @@ -0,0 +1,102 @@ +package com.c2kernel.entity.proxy; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.util.StringTokenizer; + +import com.c2kernel.common.InvalidDataException; + + +/************************************************************************** + * + * $Revision: 1.11 $ + * $Date: 2005/05/10 11:40:09 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ProxyMessage { + + // special server message paths + public static final String BYEPATH = "bye"; + public static final String ADDPATH = "add"; + public static final String DELPATH = "del"; + public static final String PINGPATH = "ping"; + public static final boolean ADDED = false; + public static final boolean DELETED = true; + public static final int NA = -1; + + static ProxyMessage byeMessage = new ProxyMessage(NA, BYEPATH, ADDED); + static ProxyMessage pingMessage = new ProxyMessage(NA, PINGPATH, ADDED); + + private int sysKey = NA; + private String path = ""; + private String server = null; + private boolean state = ADDED; + + public ProxyMessage() { + super(); + } + public ProxyMessage(int sysKey, String path, boolean state) { + this(); + setSysKey(sysKey); + setPath(path); + setState(state); + } + + public ProxyMessage(String line) throws InvalidDataException, IOException { + if (line == null) + throw new IOException("Null proxy message"); + StringTokenizer tok = new StringTokenizer(line,":"); + if (tok.countTokens()!=2) + throw new InvalidDataException("String '"+line+"' does not constitute a valid proxy message.", ""); + sysKey = Integer.parseInt(tok.nextToken()); + path = tok.nextToken(); + if (path.startsWith("-")) { + state = DELETED; + path = path.substring(1); + } + } + + public ProxyMessage(DatagramPacket packet) throws InvalidDataException, IOException { + this(new String(packet.getData())); + } + + public int getSysKey() { + return sysKey; + } + + public void setSysKey(int sysKey) { + this.sysKey = sysKey; + } + + public String getPath() { + return path; + } + + public void setPath(String newPath) { + this.path = newPath; + } + + public boolean getState() { + return state; + } + + public void setState(boolean state) { + this.state = state; + } + + @Override + public String toString() { + return sysKey+":"+(state?"-":"")+path; + } + + public String getServer() { + return server; + } + + public void setServer(String server) { + this.server = server; + } +} diff --git a/src/main/java/com/c2kernel/entity/proxy/ProxyServerConnection.java b/src/main/java/com/c2kernel/entity/proxy/ProxyServerConnection.java new file mode 100644 index 0000000..6807953 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/proxy/ProxyServerConnection.java @@ -0,0 +1,134 @@ +/************************************************************************** + * EntityProxyFactory.java + * + * $Revision: 1.3 $ + * $Date: 2005/05/25 12:11:44 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.entity.proxy; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.InterruptedIOException; +import java.io.PrintWriter; +import java.net.Socket; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.utils.Logger; + + +public class ProxyServerConnection extends Thread +{ + + public boolean serverIsActive = true; + // proxy client details + String serverName; + int serverPort; + Socket serverConnection; + EntityProxyManager manager; + // for talking to the proxy server + PrintWriter serverStream; + boolean listening = false; + static boolean isServer = false; + + /** + * Create an entity proxy manager to listen for proxy events and reap unused proxies + */ + public ProxyServerConnection(String host, int port, EntityProxyManager manager) + { + Logger.msg(5, "ProxyServerConnection - Initialising connection to "+host+":"+port); + serverName = host; + serverPort = port; + this.manager = manager; + listening = true; + start(); + } + + @Override + public void run() { + Thread.currentThread().setName("Proxy Client Connection Listener to "+serverName+":"+serverPort); + while (listening) { + try { + if (serverConnection == null) connect(); + if (serverConnection != null) { + BufferedReader request = new BufferedReader(new InputStreamReader(serverConnection.getInputStream())); + String input = null; + ProxyMessage thisMessage; + while (listening && serverConnection != null) { + try { + input = request.readLine(); + thisMessage = new ProxyMessage(input); + thisMessage.setServer(serverName); + manager.processMessage(thisMessage); + } catch (InterruptedIOException ex) { // timeout - send a ping + sendMessage(ProxyMessage.pingMessage); + } catch (InvalidDataException ex) { // invalid proxy message + if (input != null) + Logger.error("EntityProxyManager - Invalid proxy message: "+input); + } + } + } + } catch (IOException ex) { + Logger.error("ProxyServerConnection - Disconnected from "+serverName+":"+serverPort); + try { + serverStream.close(); + serverConnection.close(); + } catch (IOException e1) { } + + + serverStream = null; + serverConnection = null; + } + } + + if (serverStream != null) { + try { + Logger.msg(1, "Disconnecting from proxy server on "+serverName+":"+serverPort); + serverStream.println(ProxyMessage.byeMessage.toString()); + serverStream.close(); + serverConnection.close(); + serverConnection = null; + } catch (Exception e) { + Logger.error("Error disconnecting from proxy server."); + } + } + } + + public void connect() { + Logger.msg(3, "ProxyServerConnection - connecting to proxy server on "+serverName+":"+serverPort); + try { + serverConnection = new Socket(serverName, serverPort); + serverConnection.setKeepAlive(true); + serverIsActive = true; + serverConnection.setSoTimeout(5000); + serverStream = new PrintWriter(serverConnection.getOutputStream(), true); + Logger.msg("Connected to proxy server on "+serverName+":"+serverPort); + manager.resubscribe(this); + } catch (Exception e) { + Logger.msg(3, "Could not connect to proxy server. Retrying in 5s"); + try { Thread.sleep(5000); } catch (InterruptedException ex) { } + serverStream = null; + serverConnection = null; + serverIsActive = false; + } + } + + public void shutdown() { + Logger.msg("Proxy Client: flagging shutdown."); + listening = false; + } + + /** + * @param sub + */ + public void sendMessage(ProxyMessage sub) { + if (serverStream != null) + serverStream.println(sub); + } + +} + diff --git a/src/main/java/com/c2kernel/entity/transfer/TransferItem.java b/src/main/java/com/c2kernel/entity/transfer/TransferItem.java new file mode 100644 index 0000000..0e3b764 --- /dev/null +++ b/src/main/java/com/c2kernel/entity/transfer/TransferItem.java @@ -0,0 +1,133 @@ +package com.c2kernel.entity.transfer; + +import java.io.File; +import java.util.ArrayList; +import java.util.Enumeration; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.TraceableEntity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +public class TransferItem { + public ArrayList domainPaths; + public int sysKey; + static int importAgentId; + + public TransferItem() throws Exception { + try { + importAgentId = Gateway.getLDAPLookup().getRoleManager().getAgentPath("system").getSysKey(); + } catch (ObjectNotFoundException e) { + Logger.error("TransferItem - System user not found!"); + throw e; + } + } + + public TransferItem(int sysKey) throws Exception { + this.sysKey = sysKey; + domainPaths = new ArrayList(); + Property name = (Property)Gateway.getStorage().get(sysKey, ClusterStorage.PROPERTY + "/Name", null); + Enumeration paths = Gateway.getLDAPLookup().search(new DomainPath(), name.getValue()); + while (paths.hasMoreElements()) { + DomainPath thisPath = (DomainPath)paths.nextElement(); + domainPaths.add(thisPath.toString()); + } + } + + public void exportItem(File dir, String path) throws Exception { + Logger.msg("Path " + path + " in " + sysKey); + String[] contents = Gateway.getStorage().getClusterContents(sysKey, path); + if (contents.length > 0) { + FileStringUtility.createNewDir(dir.getCanonicalPath()); + for (String content : contents) { + exportItem(new File(dir, content), path + "/" + content); + } + } else { //no children, try to dump object + try { + C2KLocalObject obj = Gateway.getStorage().get(sysKey, path, null); + Logger.msg("Dumping object " + path + " in " + sysKey); + File dumpPath = new File(dir.getCanonicalPath() + ".xml"); + FileStringUtility.string2File(dumpPath, CastorXMLUtility.marshall(obj)); + return; + } catch (ObjectNotFoundException ex) { + } // not an object + } + } + + public void importItem(File dir) throws Exception { + // check if already exists + try { + Property name = (Property)Gateway.getStorage().get(sysKey, ClusterStorage.PROPERTY + "/Name", null); + throw new Exception("Syskey " + sysKey + " already in use as " + name.getValue()); + } catch (Exception ex) { + } + + // retrieve objects + ArrayList objectFiles = FileStringUtility.listDir(dir.getCanonicalPath(), false, true); + ArrayList objects = new ArrayList(); + for (String element : objectFiles) { + String xmlFile = FileStringUtility.file2String(element); + C2KLocalObject newObj; + String choppedPath = element.substring(dir.getCanonicalPath().length()+1, element.length()-4); + Logger.msg(choppedPath); + if (choppedPath.startsWith(ClusterStorage.OUTCOME)) + newObj = new Outcome(choppedPath, xmlFile); + else + newObj = (C2KLocalObject)CastorXMLUtility.unmarshall(xmlFile); + + objects.add(newObj); + } + + // create item + EntityPath entityPath = new EntityPath(sysKey); + TraceableEntity newItem = (TraceableEntity)Gateway.getCorbaServer().createEntity(entityPath); + Gateway.getLDAPLookup().add(entityPath); + + PropertyArrayList props = new PropertyArrayList(); + Workflow wf = null; + // put objects + for (C2KLocalObject obj : objects) { + if (obj instanceof Property) + props.list.add((Property)obj); + else if (obj instanceof Workflow) + wf = (Workflow)obj; + } + + if (wf == null) + throw new Exception("No workflow found in import for "+sysKey); + + // init item + newItem.initialise(importAgentId, CastorXMLUtility.marshall(props), CastorXMLUtility.marshall(wf.search("workflow/domain"))); + + // store objects + importByType(ClusterStorage.COLLECTION, objects); + importByType(ClusterStorage.HISTORY, objects); + importByType(ClusterStorage.OUTCOME, objects); + importByType(ClusterStorage.VIEWPOINT, objects); + Gateway.getStorage().commit(this); + // add domPaths + for (String element : domainPaths) { + DomainPath newPath = new DomainPath(element, entityPath); + Gateway.getLDAPLookup().add(newPath); + } + } + + private void importByType(String type, ArrayList objects) throws Exception { + for (C2KLocalObject element : objects) { + if (element.getClusterType().equals(type)) + Gateway.getStorage().put(sysKey, element, this); + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/entity/transfer/TransferSet.java b/src/main/java/com/c2kernel/entity/transfer/TransferSet.java new file mode 100644 index 0000000..71a593a --- /dev/null +++ b/src/main/java/com/c2kernel/entity/transfer/TransferSet.java @@ -0,0 +1,103 @@ +package com.c2kernel.entity.transfer; + +import java.io.File; +import java.util.ArrayList; + +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.NextKeyManager; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.5 $ + * $Date: 2005/04/26 06:48:13 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class TransferSet { + + public ArrayList items; + + public TransferSet() { + } + + public TransferSet(int[] sysKeys) { + items = new ArrayList(); + for (int sysKey : sysKeys) { + try { + items.add(new TransferItem(sysKey)); + } catch (Exception ex) { + Logger.error("Could not add item "+sysKey); + Logger.error(ex); + } + } + } + + public void exportPackage(File dir) throws Exception { + if (items==null || items.size() == 0) + throw new Exception("Nothing to dump"); + FileStringUtility.createNewDir(dir.getAbsolutePath()); + for (TransferItem element : items) { + try { + element.exportItem(new File(dir, String.valueOf(element.sysKey)), "/"); + } catch (Exception ex) { + Logger.error("Error dumping item "+element.sysKey); + Logger.error(ex); + } + } + + try { + String self = CastorXMLUtility.marshall(this); + FileStringUtility.string2File(new File(dir, "transferSet.xml"), self); + } catch (Exception ex) { + Logger.error("Error writing header file"); + Logger.error(ex); + } + } + + public void importPackage(File rootDir) { + for (TransferItem element : items) { + Logger.msg(5, "Importing "+element.sysKey); + try { + element.importItem(new File(rootDir, String.valueOf(element.sysKey))); + } catch (Exception ex) { + Logger.error("Import of item "+element.sysKey+" failed. Rolling back"); + Logger.error(ex); + Gateway.getStorage().abort(element); + } + } + checkLastKey(); + } + + private void checkLastKey() + { + // find highest key in out import set + int packageLastKey = 0; + for (TransferItem element : items) { + if (element.sysKey > packageLastKey) + packageLastKey = element.sysKey; + } + + try + { // find the current last key + NextKeyManager nextKeyMan = Gateway.getLDAPLookup().getNextKeyManager(); + EntityPath lastKey = nextKeyMan.getLastEntityPath(); + Logger.msg(1, "Last key imported was "+packageLastKey+". LDAP lastkey was "+lastKey.getSysKey()); + + + if (packageLastKey > lastKey.getSysKey()) { // set new last + Logger.msg(1, "Updating lastKey to "+packageLastKey); + nextKeyMan.writeLastEntityKey(packageLastKey); + } + } + catch (Exception ex) + { + Logger.error("Exception::LoadKeys::processFile() " + ex); + } + } +} diff --git a/src/main/java/com/c2kernel/events/Event.java b/src/main/java/com/c2kernel/events/Event.java new file mode 100644 index 0000000..b52ac7a --- /dev/null +++ b/src/main/java/com/c2kernel/events/Event.java @@ -0,0 +1,276 @@ +/* + * $Revision: 1.13 $ + * + * $Date: 2004/11/22 09:12:28 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + */ + +package com.c2kernel.events; + +import java.util.Calendar; + +import com.c2kernel.common.GTimeStamp; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.persistency.ClusterStorage; + + +/** + * The data structure of events, which are passed over the event service. + * + * Events are incrementaly numbered objects maintained by the History. + * + * @version $Revision: 1.13 $ $Date: 2004/11/22 09:12:28 $ + * @author $Author: abranson $ + */ +public class Event implements C2KLocalObject +{ + + int mID, mEntitySystemKey, mCurrentState, mTransition; + String mName, mStepName, mStepPath, mStepType, mAgentName, mAgentRole; + GTimeStamp mTimeStamp; + + public void setID( int id ) { + mID = id; + mName = String.valueOf(id); + } + + /** + */ + public void setEntitySystemKey( int systemKey ) + { + mEntitySystemKey = systemKey; + } + + /** + * Set the Event Name, in parameter is a String + */ + @Override + public void setName(String name) + { + mName = name; + try { + mID = Integer.parseInt(name); + } catch (NumberFormatException ex) { + mID = -1; + } + } + + /** + * Set the StepPath of the Event, in parameter is a String + */ + public void setStepName(String name) + { + mStepName = name; + } + + /** + * Set the StepPath of the Event, in parameter is a String + */ + public void setStepPath(String path) + { + mStepPath = path; + } + + /** + * Set the StepType of the Event, in parameter is a String + */ + public void setStepType(String type) + { + mStepType = type; + } + + public void setCurrentState(int state) + { + mCurrentState = state; + } + + /** + * Set the AgentInfo in the Event, in parameter is an AgentInfo + */ + public void setAgentName(String agentName) + { + mAgentName = agentName; + } + + public void setAgentRole(String agentRole) + { + mAgentRole = agentRole; + } + + /** + * Set the TimeStamp in the Event, in parameter is an GTimeStamp + */ + public void setTimeStamp(GTimeStamp inTimeStamp) + { + mTimeStamp = inTimeStamp; + } + + + /** + * Return the Event's ID + */ + public int getID() + { + return mID; + } + + /** + */ + public int getEntitySystemKey() + { + return mEntitySystemKey; + } + + /** + * Return the Event Name + */ + @Override + public String getName() + { + return mName; + } + + /** + * Return the StepPath of the Event. + */ + public String getStepName() + { + return mStepName; + } + + /** + * Return the StepPath of the Event. + */ + public String getStepPath() + { + return mStepPath; + } + + /** + * Return the StepPath of the Event. + */ + public String getStepType() + { + return mStepType; + } + + public int getCurrentState() + { + return mCurrentState; + } + + /** + * Return the AgentInfo of the Event. + */ + public String getAgentName() + { + return mAgentName; + } + + public String getAgentRole() + { + return mAgentRole; + } + + /** + * Return the Event's TimeStamp. + */ + public GTimeStamp getTimeStamp() + { + return mTimeStamp; + } + + /** + * Return the TimeStamp in a form that will + * convert nicely to a String + * YYYY-MM-DD HH:MI:SS + */ + public String getTimeString() + { + return Event.timeToString(mTimeStamp); + } + + public static String timeToString(GTimeStamp timeStamp) { + StringBuffer time = new StringBuffer().append(timeStamp.mYear).append("-"); + + if (timeStamp.mMonth<10) time.append("0"); + time.append(timeStamp.mMonth).append("-"); + + if (timeStamp.mDay<10) time.append("0"); + time.append(timeStamp.mDay).append(" "); + + if (timeStamp.mHour<10) time.append("0"); + time.append(timeStamp.mHour).append(":"); + + if (timeStamp.mMinute<10) time.append("0"); + time.append(timeStamp.mMinute).append(":"); + + if (timeStamp.mSecond<10) time.append("0"); + time.append(timeStamp.mSecond); + + return time.toString(); + } + + public void setTimeString(String time) throws Exception + { + if (time.length() == 19) + mTimeStamp = new GTimeStamp( + Integer.parseInt(time.substring(0,4)), + Integer.parseInt(time.substring(5,7)), + Integer.parseInt(time.substring(8,10)), + Integer.parseInt(time.substring(11,13)), + Integer.parseInt(time.substring(14,16)), + Integer.parseInt(time.substring(17,19)), + Calendar.getInstance().get(Calendar.ZONE_OFFSET)); + else if (time.length() == 14) // support for some sql formats + mTimeStamp = new GTimeStamp( + Integer.parseInt(time.substring(0,4)), + Integer.parseInt(time.substring(4,6)), + Integer.parseInt(time.substring(6,8)), + Integer.parseInt(time.substring(8,10)), + Integer.parseInt(time.substring(10,12)), + Integer.parseInt(time.substring(12,14)), + Calendar.getInstance().get(Calendar.ZONE_OFFSET)); + else + throw new Exception("Unknown time format: "+time); + } + + + + static public GTimeStamp getGMT() + { + java.util.Calendar now = Calendar.getInstance(); + + return new GTimeStamp( now.get(Calendar.YEAR), + now.get(Calendar.MONTH)+1, + now.get(Calendar.DAY_OF_MONTH), + now.get(Calendar.HOUR_OF_DAY), + now.get(Calendar.MINUTE), + now.get(Calendar.SECOND), + now.get(Calendar.ZONE_OFFSET) ); + } + /** + * @see com.c2kernel.entity.C2KLocalObject#getClusterType() + */ + @Override + public String getClusterType() { + return ClusterStorage.HISTORY; + } + + /** + * @return + */ + public int getTransition() { + return mTransition; + } + + /** + * @param i + */ + public void setTransition(int i) { + mTransition = i; + } + +} diff --git a/src/main/java/com/c2kernel/events/History.java b/src/main/java/com/c2kernel/events/History.java new file mode 100644 index 0000000..868eaea --- /dev/null +++ b/src/main/java/com/c2kernel/events/History.java @@ -0,0 +1,87 @@ +package com.c2kernel.events; + + +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.RemoteMap; +import com.c2kernel.utils.Logger; + +/** + * @author Andrew Branson + * + * $Revision: 1.20 $ + * $Date: 2004/07/21 09:55:11 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + */ + +public class History extends RemoteMap { + + int lastID = -1; + + public History(int sysKey, Object locker) { + super(sysKey, ClusterStorage.HISTORY, locker); + } + + public Event addEvent(String agentName, String agentRole, + int stepTransitionId, + String stepName, + String stepPath, + String stepType, + int stepCurrentState) { + Logger.msg(7, "History.addEvent() - creating new event for "+stepTransitionId+" on "+stepName+" in "+mSysKey); + Event newEvent = new Event(); + newEvent.setEntitySystemKey(mSysKey); + newEvent.setAgentName(agentName); + newEvent.setAgentRole(agentRole); + newEvent.setTransition(stepTransitionId); + newEvent.setStepName(stepName); + newEvent.setStepPath(stepPath); + newEvent.setStepType(stepType); + newEvent.setCurrentState(stepCurrentState); + newEvent.setTimeStamp(Event.getGMT()); + return storeNewEvent(newEvent); + } + + public Event addEvent(String agentName, String agentRole, + int stepTransitionId, + String stepName, + String stepPath, + String stepType, + int stepCurrentState, + String timeString) throws Exception { + Logger.msg(7, "History.addEvent() - creating new event for "+stepTransitionId+" on "+stepName+" in "+mSysKey); + Event newEvent = new Event(); + newEvent.setEntitySystemKey(mSysKey); + newEvent.setAgentName(agentName); + newEvent.setAgentRole(agentRole); + newEvent.setTransition(stepTransitionId); + newEvent.setStepName(stepName); + newEvent.setStepPath(stepPath); + newEvent.setStepType(stepType); + newEvent.setCurrentState(stepCurrentState); + newEvent.setTimeString(timeString); + return storeNewEvent(newEvent); + } + + private Event storeNewEvent(Event newEvent) { + synchronized (this) { + int newEventID = getLastId()+1; + newEvent.setID(newEventID); + put(newEvent.getName(), newEvent); + lastID = newEventID; + return newEvent; + } + } + + public Event getEvent(int id) { + return get(String.valueOf(id)); + } + + @Override + public Event remove(Object key) { + // forbidden + return null; + } + +} diff --git a/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java b/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java new file mode 100644 index 0000000..aa04609 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/AutoScrollController.java @@ -0,0 +1,41 @@ +package com.c2kernel.graph.controller; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; + +import com.c2kernel.graph.view.GraphPanel; + + +public class AutoScrollController implements MouseMotionListener +{ + private GraphPanel mGraphPanel = null; + + + public void setGraphPanel(GraphPanel graphPanel) + { + mGraphPanel = graphPanel; + mGraphPanel.addMouseMotionListener(this); + } + + + @Override + public void mouseDragged(MouseEvent me) + { + Point mousePoint = null; + + + if(mGraphPanel != null) + { + mousePoint = me.getPoint(); + mGraphPanel.scrollRectToVisible(new Rectangle(mousePoint.x, mousePoint.y, 1, 1)); + } + } + + + @Override + public void mouseMoved(MouseEvent me) + { + } +} diff --git a/src/main/java/com/c2kernel/graph/controller/DeletionController.java b/src/main/java/com/c2kernel/graph/controller/DeletionController.java new file mode 100644 index 0000000..44ea990 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/DeletionController.java @@ -0,0 +1,92 @@ +package com.c2kernel.graph.controller; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JButton; + +import com.c2kernel.graph.event.SelectionChangedEvent; +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.Vertex; + + +// The deletion controller is responsible for deleting the present +// selection within the graph. +// +// The controller listens to: +// * The graph model to determine if there is a selection +// * The delete button +// * The graph panel for the typing of the delete key +// +// The controller modifies: +// * The graph model to delete the current selection +// * The delete button to enable it only when there is a selection +public class DeletionController extends KeyAdapter implements Observer, ActionListener +{ + private GraphModelManager mGraphModelManager = null; + private JButton mDeleteButton = null; + + + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + mGraphModelManager.addObserver(this); + } + + + public void setDeleteButton(JButton deleteButton) + { + mDeleteButton = deleteButton; + mDeleteButton.addActionListener(this); + } + + + // Invoked by the graph model + @Override + public void update(Observable o, Object arg) + { + SelectionChangedEvent event = null; + DirectedEdge selectedEdge = null; + Vertex[] selectedVertices = null; + + + // If the selected edge has changed + if(arg instanceof SelectionChangedEvent && mDeleteButton != null && mGraphModelManager.isEditable()) + { + // Enable the button if a single edge or single vertex is selected + event = (SelectionChangedEvent)arg; + + selectedEdge = event.mSelection.mEdge; + selectedVertices = event.mSelection.mVertices; + + mDeleteButton.setEnabled((selectedEdge != null) || (selectedVertices != null)); + } + } + + + // Invoked by the graph panel + @Override + public void keyPressed(KeyEvent e) + { + if(e.getKeyCode() == KeyEvent.VK_DELETE && mGraphModelManager.isEditable()) + { + mGraphModelManager.getModel().deleteSelection(); + } + } + + + // Invoked by the delete button + @Override + public void actionPerformed(ActionEvent ae) + { + if(mGraphModelManager != null && mGraphModelManager.isEditable()) + { + mGraphModelManager.getModel().deleteSelection(); + } + } +} diff --git a/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java b/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java new file mode 100644 index 0000000..00ea45b --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/EdgeConstructionController.java @@ -0,0 +1,253 @@ +package com.c2kernel.graph.controller; + +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.EditorModeListener; +import com.c2kernel.graph.view.EditorToolBar; + + +public class EdgeConstructionController extends MouseAdapter implements EditorModeListener +{ + private GraphModelManager mGraphModelManager = null; + private EditorToolBar mEditorToolBar = null; + + + /**********/ + /* States */ + /**********/ + private final Integer kOtherMode = new Integer(0); + private final Integer kWaitOrigin = new Integer(1); + private final Integer kWaitTerminus = new Integer(2); + + + /**********/ + /* Events */ + /**********/ + private final int kEdgeEntered = 0; + private final int kOtherEntered = 1; + private final int kPressOnVertex = 2; + private final int kDrag = 3; + private final int kReleaseOnTerminus = 4; + private final int kReleaseOnNothing = 5; + + + /***********/ + /* Actions */ + /***********/ + + private interface Action + { + public void doIt(Object data); + } + + + private Action mSetOriginVertex = new Action() + { + @Override + public void doIt(Object data) + { + if(mGraphModelManager != null) + { + mGraphModelManager.getModel().setNewEdgeOriginVertex((Vertex)data); + } + } + }; + + + private Action mSetEndPoint = new Action() + { + @Override + public void doIt(Object data) + { + if(mGraphModelManager != null) + { + mGraphModelManager.getModel().setNewEdgeEndPoint((Point)data); + } + } + }; + + + private Action mClearEdge = new Action() + { + @Override + public void doIt(Object data) + { + if(mGraphModelManager != null) + { + mGraphModelManager.getModel().setNewEdgeOriginVertex(null); + mGraphModelManager.getModel().setNewEdgeEndPoint(null); + } + } + }; + + + private Action mCreateEdge = new Action() + { + @Override + public void doIt(Object data) + { + if((mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable()) + { + mGraphModelManager.getModel().createDirectedEdge + ( + mGraphModelManager.getModel().getNewEdgeOriginVertex(), + (Vertex)data, + mEditorToolBar.getSelectedEdgeType() + ); + mGraphModelManager.getModel().setNewEdgeOriginVertex(null); + mGraphModelManager.getModel().setNewEdgeEndPoint(null); + } + } + }; + + + /***********************************/ + /* Finite State Transition Network */ + /***********************************/ + + private Object[][][] mFSTN = + {// OtherMode WaitOrigin WaitTerminus + /* EdgeEntered */ {{null, kWaitOrigin}, null , null }, + /* OtherEntered */ { null , {null , kOtherMode} , null }, + /* PressOnVertex */ { null , {mSetOriginVertex, kWaitTerminus}, null }, + /* Drag */ { null , null , {mSetEndPoint, null} }, + /* ReleaseOnTerminus */ { null , null , {mCreateEdge , kWaitOrigin}}, + /* ReleaseOnNothing */ { null , null , {mClearEdge , kWaitOrigin}} + }; + + + /*****************/ + /* Current state */ + /*****************/ + + private Integer mState = kOtherMode; + + + /**************************/ + /* Event processing logic */ + /**************************/ + + private void processEvent(int event, Object data) + { + Object[] transition = mFSTN[event][mState.intValue()]; + Action action = null; + Integer nextState = null; + + if(transition != null) + { + action = (Action)transition[0]; + nextState = (Integer)transition[1]; + + if(action != null) + { + action.doIt(data); + } + + if(nextState != null) + { + mState = nextState; + } + } + } + + + /********************/ + /* Public interface */ + /********************/ + + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + } + + + public void setEditorToolBar(EditorToolBar editorToolBar) + { + mEditorToolBar = editorToolBar; + mEditorToolBar.addEditorModeListener(this); + } + + + @Override + public void editorModeChanged(String idOfNewMode) + { + if(idOfNewMode.equals("Edge")) + { + processEvent(kEdgeEntered, null); + } + else + { + processEvent(kOtherEntered, null); + } + } + + + @Override + public void mousePressed(MouseEvent me) + { + Vertex vertex = null; + Point mousePoint = null; + + if(mGraphModelManager != null) + { + // Determine if there is a vertex under the mouse cursor + mousePoint = me.getPoint(); + vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y)); + + // If the mouse has been pressed on a vertex + if(vertex != null) + { + processEvent(kPressOnVertex, vertex); + } + } + } + + + @Override + public void mouseReleased(MouseEvent me) + { + Vertex vertex = null; + Point mousePoint = null; + + if(mGraphModelManager != null) + { + // Determine if there is a vertex under the mouse cursor + mousePoint = me.getPoint(); + vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y)); + + // If the mouse has been released on a vertex which is not the origin vertex + if((vertex != null) && (vertex != mGraphModelManager.getModel().getNewEdgeOriginVertex())) + { + processEvent(kReleaseOnTerminus, vertex); + } + else + { + processEvent(kReleaseOnNothing, null); + } + } + } + + + @Override + public void mouseExited(MouseEvent me) + { + } + + + @Override + public void mouseDragged(MouseEvent me) + { + processEvent(kDrag, me.getPoint()); + } + + + @Override + public void mouseMoved(MouseEvent me) + { + } +} diff --git a/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java b/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java new file mode 100644 index 0000000..eda5c1c --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/MultiSelectionDragController.java @@ -0,0 +1,571 @@ +package com.c2kernel.graph.controller; + +import java.awt.Point; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.ElasticBand; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.graph.model.Selection; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.EditorModeListener; + + +public class MultiSelectionDragController +extends MouseAdapter +implements EditorModeListener, KeyListener +{ + private class ResizeInf + { + public int mMousePressedX = 0; + public int mMousePressedY = 0; + public Vertex mSelectedVertex = null; + public GraphPoint[] mOldOutline = null; + public int mCentreX = 0; + public int mCentreY = 0; + public int mOldHeight = 0; + public int mOldWidth = 0; + } + private ResizeInf mResizeInf = new ResizeInf(); + + private class DispForSelection + { + public int mXDisp = 0; + public int mYDisp = 0; + } + private DispForSelection mDispForSelection = null; + + private class VertexAndDisp + { + public Vertex mVertex = null; + public int mXDisp = 0; + public int mYDisp = 0; + } + + protected GraphModelManager mGraphModelManager = null; + + + /**********/ + /* States */ + /**********/ + protected final Integer kOtherMode = new Integer(0); + protected final Integer kWaiting = new Integer(1); + protected final Integer kResizing = new Integer(2); + protected final Integer kDraggingSelection = new Integer(3); + protected final Integer kStretching = new Integer(4); + + + /**********/ + /* Events */ + /**********/ + protected final int kSelectEntered = 0; + protected final int kOtherEntered = 1; + protected final int kPressOnEdge = 2; + protected final int kPressOnVertex = 3; + protected final int kPressOnSelection = 4; + protected final int kPressOnResizePad = 5; + protected final int kCTRLPressOnVertex = 6; + protected final int kCTRL_A = 7; + protected final int kPressOnNothing = 8; + protected final int kDrag = 9; + protected final int kRelease = 10; + protected final int kZoomIn = 11; + + /***********/ + /* Actions */ + /***********/ + + protected interface Action + { + public void doIt(Object data); + } + + + protected Action mStoreResizeInf = new Action() + { + @Override + public void doIt(Object data) + { + Point mousePoint = (Point)data; + GraphPoint centre = null; + + mResizeInf.mMousePressedX = mousePoint.x; + mResizeInf.mMousePressedY = mousePoint.y; + mResizeInf.mSelectedVertex = mGraphModelManager.getModel().getSelection().mVertices[0]; + mResizeInf.mOldOutline = mResizeInf.mSelectedVertex.getOutlinePoints(); + centre = mResizeInf.mSelectedVertex.getCentrePoint(); + mResizeInf.mCentreX = centre.x; + mResizeInf.mCentreY = centre.y; + mResizeInf.mOldHeight = mResizeInf.mSelectedVertex.getHeight(); + mResizeInf.mOldWidth = mResizeInf.mSelectedVertex.getWidth(); + } + }; + + + protected Action mResizeVertex = new Action() + { + @Override + public void doIt(Object data) + { + Point mousePoint = (Point)data; + int resizeX = 0; + int resizeY = 0; + + + // Calculate how much the old outline should be resized + resizeX = mousePoint.x - mResizeInf.mMousePressedX; + resizeY = mousePoint.y - mResizeInf.mMousePressedY; + + // Clip the resize so that outline does not get any + // smaller than 10 x 10 pixels + if(resizeX < -mResizeInf.mOldWidth/2 + 10) + { + resizeX = -mResizeInf.mOldWidth/2 + 10; + } + + if(resizeY < -mResizeInf.mOldHeight/2 + 10) + { + resizeY = -mResizeInf.mOldHeight/2 + 10; + } + + if (mGraphModelManager.isEditable()) { + mResizeInf.mSelectedVertex.setOutlinePoints(newOutline(resizeX, resizeY)); + mGraphModelManager.forceNotify(); + } + } + + + private GraphPoint[] newOutline(int resizeX, int resizeY) + { + GraphPoint[] newOutline = new GraphPoint[mResizeInf.mOldOutline.length]; + int x = 0; + int y = 0; + int i = 0; + + + for(i=0; i mResizeInf.mCentreX) + { + x = mResizeInf.mOldOutline[i].x + resizeX; + } + else if(mResizeInf.mOldOutline[i].x < mResizeInf.mCentreX) + { + x = mResizeInf.mOldOutline[i].x - resizeX; + } + else + { + x = mResizeInf.mOldOutline[i].x; + } + + if(mResizeInf.mOldOutline[i].y > mResizeInf.mCentreY) + { + y = mResizeInf.mOldOutline[i].y + resizeY; + } + else if(mResizeInf.mOldOutline[i].y < mResizeInf.mCentreY) + { + y = mResizeInf.mOldOutline[i].y - resizeY; + } + else + { + y = mResizeInf.mOldOutline[i].y; + } + + newOutline[i] = new GraphPoint(x, y); + } + + return newOutline; + } + }; + + + protected Action mSelectEdge = new Action() + { + @Override + public void doIt(Object data) + { + Selection selection = new Selection((DirectedEdge)data, null, 0, 0, 0, 0); + + mGraphModelManager.getModel().setSelection(selection); + } + }; + + + protected Action mSelectVertexAndStoreDisp = new Action() + { + @Override + public void doIt(Object data) + { + VertexAndDisp vertexAndDisp = (VertexAndDisp)data; + GraphPoint centrePoint = vertexAndDisp.mVertex.getCentrePoint(); + Selection selection = new Selection(null, + new Vertex[] {vertexAndDisp.mVertex}, + centrePoint.x, + centrePoint.y, + centrePoint.x, + centrePoint.y); + + mGraphModelManager.getModel().setSelection(selection); + mDispForSelection = new DispForSelection(); + mDispForSelection.mXDisp = vertexAndDisp.mXDisp; + mDispForSelection.mYDisp = vertexAndDisp.mYDisp; + } + }; + + + protected Action mStoreDisp = new Action() + { + @Override + public void doIt(Object data) + { + mDispForSelection = (DispForSelection)data; + } + }; + + + protected Action mToggleVertex = new Action() + { + @Override + public void doIt(Object data) + { + Vertex vertex = (Vertex)data; + + if(mGraphModelManager.getModel().inSelection(vertex)) + { + mGraphModelManager.getModel().removeFromSelection(vertex); + } + else + { + mGraphModelManager.getModel().addToSelection(vertex); + } + } + }; + + + protected Action mSelectAll = new Action() + { + @Override + public void doIt(Object data) + { + mGraphModelManager.getModel().selectAll(); + } + }; + + + protected Action mCreateBand = new Action() + { + @Override + public void doIt(Object data) + { + Point fixedCorner = (Point)data; + + mGraphModelManager.getModel().setElasticBand(new ElasticBand(fixedCorner, fixedCorner)); + } + }; + + + protected Action mMoveSelection = new Action() + { + @Override + public void doIt(Object data) + { + Point mousePoint = (Point)data; + int topLeftX = mousePoint.x - mDispForSelection.mXDisp; + int topLeftY = mousePoint.y - mDispForSelection.mYDisp; + if (mGraphModelManager.isEditable()) { + mGraphModelManager.getModel().moveAbsoluteSelection(topLeftX, topLeftY); + } + } + }; + + + protected Action mResizeBand = new Action() + { + @Override + public void doIt(Object data) + { + mGraphModelManager.getModel().resizeElasticBand((Point)data); + } + }; + + + protected Action mSelectContents = new Action() + { + @Override + public void doIt(Object data) + { + mGraphModelManager.getModel().selectContentsOfElasticBand(); + } + }; + + protected Action mZoomIn = new Action() + { + @Override + public void doIt(Object data) // data is the clicked vertex + { + // Need to get child graph model out of the vertex before we can zoom in + if (data instanceof Vertex) { + Vertex zoomTo = (Vertex)data; + if (((GraphableVertex)zoomTo).getIsComposite()) mGraphModelManager.zoomIn(zoomTo); + } + } + }; + + /***********************************/ + /* Finite State Transition Network */ + /***********************************/ + + protected Object[][][] mFSTN = + {// OtherMode Waiting Resizing DraggingSelection Stretching + /* SelectEntered */ {{null, kWaiting}, null , null , null , null }, + /* OtherEntered */ { null , {null , kOtherMode }, null , null , null }, + /* PressOnEdge */ { null , {mSelectEdge , null }, null , null , null }, + /* PressOnVertex */ { null , {mSelectVertexAndStoreDisp, kDraggingSelection}, null , null , null }, + /* PressOnSelection */ { null , {mStoreDisp , kDraggingSelection}, null , null , null }, + /* PressOnResizePad */ { null , {mStoreResizeInf , kResizing }, null , null , null }, + /* CTRLPressOnVertex */ { null , {mToggleVertex , null }, null , null , null }, + /* CTRL_A */ { null , {mSelectAll , null }, null , null , null }, + /* PressOnNothing */ { null , {mCreateBand , kStretching }, null , null , null }, + /* Drag */ { null , null , {mResizeVertex, null }, {mMoveSelection, null }, {mResizeBand , null }}, + /* Release */ { null , null , {null , kWaiting}, {null , kWaiting}, {mSelectContents, kWaiting}}, + /* Double Click */ { null , {mZoomIn , null }, null , null , null }, + }; + + + /*****************/ + /* Current state */ + /*****************/ + + private Integer mState = kWaiting; + + + /**************************/ + /* Event processing logic */ + /**************************/ + + protected void processEvent(int event, Object data) + { + Object[] transition = mFSTN[event][mState.intValue()]; + Action action = null; + Integer nextState = null; + + if(transition != null) + { + action = (Action)transition[0]; + nextState = (Integer)transition[1]; + + if(action != null) + { + action.doIt(data); + } + + if(nextState != null) + { + mState = nextState; + } + } + } + + + /********************/ + /* Public interface */ + /********************/ + + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + } + + + @Override + public void editorModeChanged(String idOfNewMode) + { + if(idOfNewMode.equals("Select")) + { + processEvent(kSelectEntered, null); + } + else + { + processEvent(kOtherEntered, null); + } + } + + + @Override + public void mousePressed(MouseEvent me) + { + int modifiers = me.getModifiers(); + + if(mGraphModelManager != null) + { + if((modifiers & InputEvent.CTRL_MASK) == 0) + { + mousePressedWithoutCTRL(me.getPoint()); + } + else + { + mousePressedWithCTRL(me.getPoint()); + } + } + } + + @Override + public void mouseClicked(MouseEvent me) + { + if (me.getClickCount() == 2) { // want double click + Point clickedSpot = me.getPoint(); + GraphPoint mouseGPoint = new GraphPoint(clickedSpot.x, clickedSpot.y); + Vertex clicked = mGraphModelManager.getModel().getVertex(mouseGPoint); + if (clicked != null) + processEvent(kZoomIn, clicked); + } + } + + private void mousePressedWithoutCTRL(Point mousePoint) + { + GraphPoint mouseGPoint = new GraphPoint(mousePoint.x, mousePoint.y); + DirectedEdge edge = mGraphModelManager.getModel().getEdge(mouseGPoint); + Vertex vertex = mGraphModelManager.getModel().getVertex(mouseGPoint); + GraphPoint vertexCentrePoint = null; + VertexAndDisp vertexAndDisp = null; + Selection selection = null; + DispForSelection dispForSelection = null; + + + // In order of priority: + // 1. Click on resize pad + // 2. Click on vertex + // 3. Click on edge + if(onResizePad(mouseGPoint)) + { + processEvent(kPressOnResizePad, mousePoint); + } + else if(vertex != null) + { + if(mGraphModelManager.getModel().inSelection(vertex)) + { + selection = mGraphModelManager.getModel().getSelection(); + dispForSelection = new DispForSelection(); + dispForSelection.mXDisp = mousePoint.x - selection.mTopLeftX; + dispForSelection.mYDisp = mousePoint.y - selection.mTopLeftY; + + processEvent(kPressOnSelection, dispForSelection); + } + else + { + vertexCentrePoint = vertex.getCentrePoint(); + + vertexAndDisp = new VertexAndDisp(); + vertexAndDisp.mVertex = vertex; + vertexAndDisp.mXDisp = mousePoint.x - vertexCentrePoint.x; + vertexAndDisp.mYDisp = mousePoint.y - vertexCentrePoint.y; + + processEvent(kPressOnVertex, vertexAndDisp); + } + } + // vertex == null + else + { + if(edge == null) + { + processEvent(kPressOnNothing, mousePoint); + } + else + { + processEvent(kPressOnEdge, edge); + } + } + } + + + private boolean onResizePad(GraphPoint mouseGPoint) + { + Selection selection = mGraphModelManager.getModel().getSelection(); + GraphPoint vertexCentre = null; + int bottomRightX = 0; + int bottomRightY = 0; + + + if(selection.mVertices == null) return false; + + if(selection.mVertices.length == 1) + { + vertexCentre = selection.mVertices[0].getCentrePoint(); + if (vertexCentre == null) return false; + bottomRightX = vertexCentre.x + selection.mVertices[0].getWidth()/2; + bottomRightY = vertexCentre.y + selection.mVertices[0].getHeight()/2; + + return + ( + (mouseGPoint.x > bottomRightX) && + (mouseGPoint.x < bottomRightX + 10) && + (mouseGPoint.y > bottomRightY) && + (mouseGPoint.y < bottomRightY + 10) + ); + } + else + { + return false; + } + } + + + private void mousePressedWithCTRL(Point mousePoint) + { + Vertex vertex = mGraphModelManager.getModel().getVertex(new GraphPoint(mousePoint.x, mousePoint.y)); + + if(vertex != null) + { + processEvent(kCTRLPressOnVertex, vertex); + } + } + + + @Override + public void mouseReleased(MouseEvent me) + { + processEvent(kRelease, null); + } + + + @Override + public void mouseMoved(MouseEvent me) + { + } + + + @Override + public void mouseDragged(MouseEvent e) + { + processEvent(kDrag, e.getPoint()); + } + + + @Override + public void keyPressed(KeyEvent e) + { + if((e.getKeyCode() == KeyEvent.VK_A) && e.isControlDown()) + { + processEvent(kCTRL_A, null); + } + } + + + @Override + public void keyReleased(KeyEvent e) + { + } + + + @Override + public void keyTyped(KeyEvent e) + { + } + +} diff --git a/src/main/java/com/c2kernel/graph/controller/StartVertexController.java b/src/main/java/com/c2kernel/graph/controller/StartVertexController.java new file mode 100644 index 0000000..3984cb7 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/StartVertexController.java @@ -0,0 +1,79 @@ +package com.c2kernel.graph.controller; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JButton; + +import com.c2kernel.graph.event.SelectionChangedEvent; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.Vertex; + + +// The start vertex controller is responsible for selecting +// the vertex at the start of the graph. +// +// The controller listens to: +// * The graph model to determine if there is a single +// vertex selected +// * The start vertex button +// +// The controller modifies: +// * The graph model to select the start vertex +// * The start button to enable it only when there is a +// single vertex selected +public class StartVertexController implements Observer, ActionListener +{ + private GraphModelManager mGraphModelManager = null; + private JButton mStartButton = null; + + + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + mGraphModelManager.addObserver(this); + } + + + public void setStartButton(JButton startButton) + { + mStartButton = startButton; + mStartButton.addActionListener(this); + } + + + @Override + public void update(Observable o, Object arg) + { + SelectionChangedEvent event = null; + Vertex[] selectedVertices = null; + + // If the selected vertex has changed + if(arg instanceof SelectionChangedEvent && mStartButton != null) + { + event = (SelectionChangedEvent)arg; + selectedVertices = event.mSelection.mVertices; + + if(selectedVertices == null) + { + mStartButton.setEnabled(false); + } + else if (mGraphModelManager.isEditable()) + { + mStartButton.setEnabled(selectedVertices.length == 1); + } + } + } + + + @Override + public void actionPerformed(ActionEvent ae) + { + if(mGraphModelManager != null) + { + mGraphModelManager.getModel().setSelectedVertexToBeStart(); + } + } +} diff --git a/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java b/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java new file mode 100644 index 0000000..1eb91f6 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/controller/VertexConstructionController.java @@ -0,0 +1,47 @@ +package com.c2kernel.graph.controller; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.view.EditorModeListener; +import com.c2kernel.graph.view.EditorToolBar; + + +public class VertexConstructionController extends MouseAdapter implements EditorModeListener +{ + private GraphModelManager mGraphModelManager = null; + private EditorToolBar mEditorToolBar = null; + private boolean mCreatingVertices = false; + + + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + } + + + public void setEditorToolBar(EditorToolBar editorToolBar) + { + mEditorToolBar = editorToolBar; + mEditorToolBar.addEditorModeListener(this); + } + + + @Override + public void editorModeChanged(String idOfNewMode) + { + mCreatingVertices = idOfNewMode.equals("Vertex"); + } + + + @Override + public void mouseClicked(MouseEvent me) + { + if(mCreatingVertices && (mGraphModelManager != null) && (mEditorToolBar != null) && mGraphModelManager.isEditable()) + { + mGraphModelManager.getModel().createVertex(me.getPoint(), mEditorToolBar.getSelectedVertexType()); + mEditorToolBar.enterSelectMode(); + } + } +} diff --git a/src/main/java/com/c2kernel/graph/event/ClearedEvent.java b/src/main/java/com/c2kernel/graph/event/ClearedEvent.java new file mode 100644 index 0000000..128e671 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/ClearedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class ClearedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java b/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java new file mode 100644 index 0000000..d895132 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/EdgeRemovedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class EdgeRemovedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java b/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java new file mode 100644 index 0000000..7835836 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/EdgesChangedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class EdgesChangedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java b/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java new file mode 100644 index 0000000..cb8ae3e --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/ElasticBandResizedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class ElasticBandResizedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java b/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java new file mode 100644 index 0000000..6211513 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/ElasticBandSetEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class ElasticBandSetEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java b/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java new file mode 100644 index 0000000..6e13e8b --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/EntireModelChangedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class EntireModelChangedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java b/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java new file mode 100644 index 0000000..d8dd646 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/ForcedNotifyEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class ForcedNotifyEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java b/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java new file mode 100644 index 0000000..95cd6fb --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/GraphModelEvent.java @@ -0,0 +1,7 @@ +package com.c2kernel.graph.event; + +import java.io.Serializable; + +public abstract class GraphModelEvent implements Serializable +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java b/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java new file mode 100644 index 0000000..20980c3 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/GraphModelResizedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class GraphModelResizedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java b/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java new file mode 100644 index 0000000..d1bb6f2 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/NewEdgeEndPointChangedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class NewEdgeEndPointChangedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java b/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java new file mode 100644 index 0000000..f95e6d3 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/SelectionChangedEvent.java @@ -0,0 +1,9 @@ +package com.c2kernel.graph.event; + +import com.c2kernel.graph.model.Selection; + + +public class SelectionChangedEvent extends GraphModelEvent +{ + public Selection mSelection = null; +} diff --git a/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java b/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java new file mode 100644 index 0000000..2d892a9 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/SelectionMovedEvent.java @@ -0,0 +1,7 @@ +package com.c2kernel.graph.event; + + + +public class SelectionMovedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java b/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java new file mode 100644 index 0000000..f875626 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/StartVertexIdChangedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class StartVertexIdChangedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java new file mode 100644 index 0000000..353aacb --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/VertexAddedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class VertexAddedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java new file mode 100644 index 0000000..e72ca4a --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/VertexCreatedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class VertexCreatedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java new file mode 100644 index 0000000..807ca36 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/VertexMovedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class VertexMovedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java b/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java new file mode 100644 index 0000000..e24700d --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/VertexRemovedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class VertexRemovedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java b/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java new file mode 100644 index 0000000..5d83834 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/event/VerticesChangedEvent.java @@ -0,0 +1,6 @@ +package com.c2kernel.graph.event; + + +public class VerticesChangedEvent extends GraphModelEvent +{ +} diff --git a/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java b/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java new file mode 100644 index 0000000..8ab91ef --- /dev/null +++ b/src/main/java/com/c2kernel/graph/layout/DefaultGraphLayoutGenerator.java @@ -0,0 +1,116 @@ +package com.c2kernel.graph.layout; + +import java.util.Vector; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.GraphModel; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.utils.Logger; + +public class DefaultGraphLayoutGenerator { + private static int mTopMargin = 100; + private static int mLeftMargin = 100; + private static int mHorzGap = 180; + private static int mVertGap = 100; + + private DefaultGraphLayoutGenerator() { + } + + public static void layoutGraph(GraphModel graphModel) { + Vertex start = graphModel.getStartVertex(); + Vector> rowVector = new Vector>(10, 10); + int[] midPoints = null; + IntegerWrapper valueOfLargestMidPoint = new IntegerWrapper(0); + if (start == null) { + Logger.msg(1,"Error graph must have a starting vertex to be layed out"); + return; + } + graphModel.clearTags(start); + visitVertex(graphModel, start, 0, rowVector, start); + midPoints = new int[rowVector.size()]; + calculateRowMidPoints(rowVector, midPoints, valueOfLargestMidPoint); + fillInVertexLocations(graphModel, rowVector, valueOfLargestMidPoint, midPoints); + fillInEdgeLocations(graphModel); + graphModel.forceNotify(); + } + + private static void visitVertex(GraphModel graphModel, Vertex vertex, int rowIndex, Vector> rowVector, Object tag) { + int i = 0; + Vertex[] children = graphModel.getOutVertices(vertex); + vertex.setTag(tag); + addVertexToRow(vertex, rowIndex, rowVector); + for (i = 0; i < children.length; i++) { + if (!(children[i].hasTag(tag))) { + visitVertex(graphModel, children[i], rowIndex + 1, rowVector, tag); + } + } + } + + private static void addVertexToRow(Vertex vertex, int rowIndex, Vector> rowVector) { + Vector rowsVertices = null; + // If there is no vector of vertices already created for this row, + // then create one + if (rowVector.size() == rowIndex) { + rowVector.add(new Vector(10, 10)); + } + // Add the vertex to the row's vector of vertices + rowsVertices = rowVector.elementAt(rowIndex); + rowsVertices.add(vertex); + } + + private static void calculateRowMidPoints(Vector> rowVector, int[] midPoints, IntegerWrapper valueOfLargestMidPoint) { + Vector rowsVertices = null; + int rowsWidth = 0; + int i = 0; + for (i = 0; i < midPoints.length; i++) { + rowsVertices = rowVector.elementAt(i); + rowsWidth = mHorzGap * (rowsVertices.size() - 1); + midPoints[i] = rowsWidth / 2; + if (midPoints[i] > valueOfLargestMidPoint.mValue) { + valueOfLargestMidPoint.mValue = midPoints[i]; + } + } + } + + private static void fillInVertexLocations(GraphModel graphModel, Vector> rowVector, + IntegerWrapper valueOfLargestMidPoint, int[] midPoints) { + Vector rowsVertices = null; + Vertex vertex = null; + int rowIndex = 0; + int column = 0; + int rowsLeftMargin = 0; + GraphPoint point = new GraphPoint(0, 0); + for (rowIndex = 0; rowIndex < rowVector.size(); rowIndex++) { + rowsVertices = rowVector.elementAt(rowIndex); + rowsLeftMargin = mLeftMargin + valueOfLargestMidPoint.mValue - midPoints[rowIndex]; + for (column = 0; column < rowsVertices.size(); column++) { + vertex = rowsVertices.elementAt(column); + point.x = rowsLeftMargin + column * mHorzGap; + point.y = mTopMargin + rowIndex * mVertGap; + vertex.moveAbsolute(point); + graphModel.checkSize(vertex); + } + } + } + + private static void fillInEdgeLocations(GraphModel graphModel) { + Vertex[] vertices = graphModel.getVertices(); + GraphPoint centrePoint = null; + DirectedEdge[] inEdges = null; + DirectedEdge[] outEdges = null; + int i = 0; + int j = 0; + for (i = 0; i < vertices.length; i++) { + centrePoint = vertices[i].getCentrePoint(); + inEdges = graphModel.getInEdges(vertices[i]); + outEdges = graphModel.getOutEdges(vertices[i]); + for (j = 0; j < inEdges.length; j++) { + inEdges[j].setTerminusPoint(centrePoint); + } + for (j = 0; j < outEdges.length; j++) { + outEdges[j].setOriginPoint(centrePoint); + } + } + } +} diff --git a/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java b/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java new file mode 100644 index 0000000..aaee858 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/layout/IntegerWrapper.java @@ -0,0 +1,13 @@ +package com.c2kernel.graph.layout; + + +public class IntegerWrapper +{ + public int mValue = 0; + + + public IntegerWrapper(int value) + { + mValue = value; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/DirectedEdge.java b/src/main/java/com/c2kernel/graph/model/DirectedEdge.java new file mode 100644 index 0000000..830d70d --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/DirectedEdge.java @@ -0,0 +1,99 @@ +package com.c2kernel.graph.model; + +import java.io.Serializable; + + + +public abstract class DirectedEdge implements Serializable +{ + // Persistent data + private int mId = -1; + private GraphPoint mOriginPoint = new GraphPoint(0, 0); + private GraphPoint mTerminusPoint = new GraphPoint(0, 0); + private int mOriginVertexId = -1; + private int mTerminusVertexId = -1; + + + public void setID(int id) + { + mId = id; + } + + + public int getID() + { + return mId; + } + + + public void setOriginPoint(GraphPoint p) + { + mOriginPoint = p; + } + + + public GraphPoint getOriginPoint() + { + return mOriginPoint; + } + + + public void setTerminusPoint(GraphPoint p) + { + mTerminusPoint = p; + } + + + public GraphPoint getTerminusPoint() + { + return mTerminusPoint; + } + + + public boolean containsPoint(GraphPoint p) + { + int midX = mOriginPoint.x + (mTerminusPoint.x - mOriginPoint.x)/2; + int midY = mOriginPoint.y + (mTerminusPoint.y - mOriginPoint.y)/2; + int minX = midX - 10; + int minY = midY - 10; + int maxX = midX + 10; + int maxY = midY + 10; + + return (p.x >= minX) && (p.x <= maxX) && (p.y >= minY) && (p.y <= maxY); + } + + + public void setOriginVertexId(int id) + { + mOriginVertexId = id; + } + + + public int getOriginVertexId() + { + return mOriginVertexId; + } + + + public void setTerminusVertexId(int id) + { + mTerminusVertexId = id; + } + + + public int getTerminusVertexId() + { + return mTerminusVertexId; + } + + + public void setName(String name) + { + } + + + public String getName() + { + return null; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/EdgeFactory.java b/src/main/java/com/c2kernel/graph/model/EdgeFactory.java new file mode 100644 index 0000000..083f616 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/EdgeFactory.java @@ -0,0 +1,14 @@ +package com.c2kernel.graph.model; + + + +public interface EdgeFactory +{ + public void create + ( + GraphModelManager graphModelManager, + Vertex origin, + Vertex terminus, + TypeNameAndConstructionInfo typeNameAndConstructionInfo + ); +} diff --git a/src/main/java/com/c2kernel/graph/model/ElasticBand.java b/src/main/java/com/c2kernel/graph/model/ElasticBand.java new file mode 100644 index 0000000..38497ef --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/ElasticBand.java @@ -0,0 +1,17 @@ +package com.c2kernel.graph.model; + +import java.awt.Point; + + +public class ElasticBand +{ + public Point mFixedCorner = null; + public Point mMovingCorner = null; + + + public ElasticBand(Point fixedCorner, Point movingCorner) + { + mFixedCorner = fixedCorner; + mMovingCorner = movingCorner; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphModel.java b/src/main/java/com/c2kernel/graph/model/GraphModel.java new file mode 100644 index 0000000..47f368d --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphModel.java @@ -0,0 +1,900 @@ +package com.c2kernel.graph.model; + +import java.awt.Point; +import java.awt.Polygon; +import java.io.Serializable; +import java.util.Hashtable; +import java.util.Vector; + +import com.c2kernel.graph.event.ClearedEvent; +import com.c2kernel.graph.event.EdgeRemovedEvent; +import com.c2kernel.graph.event.EdgesChangedEvent; +import com.c2kernel.graph.event.ElasticBandResizedEvent; +import com.c2kernel.graph.event.ElasticBandSetEvent; +import com.c2kernel.graph.event.ForcedNotifyEvent; +import com.c2kernel.graph.event.GraphModelEvent; +import com.c2kernel.graph.event.GraphModelResizedEvent; +import com.c2kernel.graph.event.NewEdgeEndPointChangedEvent; +import com.c2kernel.graph.event.SelectionChangedEvent; +import com.c2kernel.graph.event.SelectionMovedEvent; +import com.c2kernel.graph.event.StartVertexIdChangedEvent; +import com.c2kernel.graph.event.VertexAddedEvent; +import com.c2kernel.graph.event.VertexCreatedEvent; +import com.c2kernel.graph.event.VertexMovedEvent; +import com.c2kernel.graph.event.VertexRemovedEvent; +import com.c2kernel.graph.event.VerticesChangedEvent; +import com.c2kernel.utils.Logger; + +public class GraphModel implements Serializable{ + /* Persistant data */ + + private int mWidth = 0; + private int mHeight = 0; + private int mNextId = 0; + protected int mStartVertexId = -1; + protected Hashtable mVertexHashtable = new Hashtable(); + protected Hashtable mEdgeHashtable = new Hashtable(); + private GraphableVertex mContainingVertex; + + /* Transient data */ + + // There should always be a Selection object + protected Selection mSelection = new Selection(null, null, 0, 0, 0, 0); + protected Vertex mNewEdgeOriginVertex = null; + protected Point mNewEdgeEndPoint = null; + private ElasticBand mElasticBand = null; + private GraphModelManager mManager = null; + + /* External factories */ + + private VertexFactory mExternalVertexFactory = null; + private EdgeFactory mExternalEdgeFactory = null; + + /* Vertex outline creator */ + + private VertexOutlineCreator mVertexOutlineCreator = null; + + /* Notification Events */ + + private ClearedEvent mClearedEvent = new ClearedEvent(); + private EdgeRemovedEvent mEdgeRemovedEvent = new EdgeRemovedEvent(); + private EdgesChangedEvent mEdgesChangedEvent = new EdgesChangedEvent(); + private ForcedNotifyEvent mForcedNotifyEvent = new ForcedNotifyEvent(); + private NewEdgeEndPointChangedEvent mNewEdgeEndPointChangedEvent = new NewEdgeEndPointChangedEvent(); + private SelectionChangedEvent mSelectionChangedEvent = new SelectionChangedEvent(); + private StartVertexIdChangedEvent mStartVertexIdChangedEvent = new StartVertexIdChangedEvent(); + private VertexAddedEvent mVertexAddedEvent = new VertexAddedEvent(); + private VertexCreatedEvent mVertexCreatedEvent = new VertexCreatedEvent(); + private VertexMovedEvent mVertexMovedEvent = new VertexMovedEvent(); + private SelectionMovedEvent mSelectionMovedEvent = new SelectionMovedEvent(); + private VertexRemovedEvent mVertexRemovedEvent = new VertexRemovedEvent(); + private VerticesChangedEvent mVerticesChangedEvent = new VerticesChangedEvent(); + private ElasticBandSetEvent mElasticBandSetEvent = new ElasticBandSetEvent(); + private ElasticBandResizedEvent mElasticBandResizedEvent = new ElasticBandResizedEvent(); + private GraphModelResizedEvent mGraphModelResizedEvent = new GraphModelResizedEvent(); + + // Calling this constructor does not create a vertex outline creator + // which is required by the method addVertexAndCreateId() + + private static int count=0; + + // count instances for debugging + private int number; + + public GraphModel() { + number=++count; + + } + + public int getNumber() { + return number; + } + + private void setChanged() { + if (mManager != null) + mManager.setChanged(); + } + + private void notifyObservers(GraphModelEvent ev) { + if (mManager != null) + mManager.notifyObservers(ev); + } + + public void setNextId(int id) { + mNextId = id; + } + + public int getNextId() { + return mNextId; + } + + public void setManager(GraphModelManager mgr) { + mManager = mgr; + } + + public GraphModelManager getManager() { + return mManager; + } + + public GraphModel(VertexOutlineCreator vertexOutlineCreator) { + mVertexOutlineCreator = vertexOutlineCreator; + } + + public void setWidth(int width) { + + mWidth = width; + } + + public int getWidth() { + return mWidth; + } + + public void setHeight(int height) { + + mHeight = height; + } + + public int getHeight() { + return mHeight; + } + + public void checkSize(Vertex v) { + boolean resized = false; + GraphPoint centre = v.getCentrePoint(); + if (getWidth() < centre.x + v.getWidth()/2 +10 ) { + setWidth( centre.x + v.getWidth()/2 +10 ); + resized = true; + } + + if (getHeight() < centre.y + v.getHeight()/2 +10 ) { + setHeight(centre.y + v.getHeight()/2 +10 ); + resized = true; + } + + if (resized) { + setChanged(); + notifyObservers(mGraphModelResizedEvent); + } + + } + + public void setStartVertexId(int id) { + mStartVertexId = id; + } + + public int getStartVertexId() { + return mStartVertexId; + } + + public Vertex getStartVertex() { + return resolveVertex(getStartVertexId()); + } + + /** + * @return Returns the mParentVertex. + */ + public GraphableVertex getContainingVertex() { + return mContainingVertex; + } + /** + * @param parentVertex The mParentVertex to set. + */ + public void setContainingVertex(GraphableVertex vertex) { + mContainingVertex = vertex; + } + + public void setVertices(Vertex[] vertices) { + mVertexHashtable = new Hashtable(); + for (Vertex vertice : vertices) { + mVertexHashtable.put(String.valueOf(vertice.getID()), vertice); + checkSize(vertice); + + } + setChanged(); + notifyObservers(mVerticesChangedEvent); + } + + public Vertex[] getVertices() { + Object[] vertexObjs = mVertexHashtable.values().toArray(); + Vertex[] vertices = new Vertex[vertexObjs.length]; + int i = 0; + for (i = 0; i < vertices.length; i++) { + vertices[i] = (Vertex)vertexObjs[i]; + } + return vertices; + } + + public void setEdges(DirectedEdge[] edges) { + mEdgeHashtable = new Hashtable(); + for (DirectedEdge edge : edges) { + mEdgeHashtable.put(String.valueOf(edge.getID()), edge); + } + setChanged(); + notifyObservers(mEdgesChangedEvent); + } + + public DirectedEdge[] getEdges() { + Object[] edgeObjs = mEdgeHashtable.values().toArray(); + DirectedEdge[] edges = new DirectedEdge[edgeObjs.length]; + int i = 0; + for (i = 0; i < edges.length; i++) { + edges[i] = (DirectedEdge)edgeObjs[i]; + } + return edges; + } + + // If the specified point is within more than one vertex, + // then the smallest vertex is returned. + public Vertex getVertex(GraphPoint p) { + Object[] vertexObjs = mVertexHashtable.values().toArray(); + Vertex vertex = null; + Vector vertexVector = new Vector(10, 10); + int numVerticesFound = 0; + Vertex smallestVertex = null; + int sizeOfSmallestVertex = 0; + int sizeOfVertex = 0; + int i = 0; + for (i = 0; i < vertexObjs.length; i++) { + vertex = (Vertex)vertexObjs[i]; + if (vertex.containsPoint(p)) { + vertexVector.add(vertex); + } + } + numVerticesFound = vertexVector.size(); + if (numVerticesFound == 0) { + return null; + } + else { + smallestVertex = vertexVector.elementAt(0); + sizeOfSmallestVertex = smallestVertex.getHeight() * smallestVertex.getWidth(); + // Determine the smallest vertex + for (i = 1; i < numVerticesFound; i++) { + vertex = vertexVector.elementAt(i); + sizeOfVertex = vertex.getHeight() * vertex.getWidth(); + if (sizeOfVertex < sizeOfSmallestVertex) { + smallestVertex = vertex; + sizeOfSmallestVertex = sizeOfVertex; + } + } + return smallestVertex; + } + } + + public Vertex getVertexById(int id) { + return mVertexHashtable.get(String.valueOf(id)); + } + + public DirectedEdge getEdge(GraphPoint p) { + Object[] edgeObjs = mEdgeHashtable.values().toArray(); + DirectedEdge edge = null; + int i = 0; + for (i = 0; i < edgeObjs.length; i++) { + edge = (DirectedEdge)edgeObjs[i]; + if (edge.containsPoint(p)) { + return edge; + } + } + return null; + } + + public int addEdgeAndCreateId(DirectedEdge e, int originId, int terminusId) { + return addEdgeAndCreateId(e, resolveVertex(originId), resolveVertex(terminusId)); + } + + public int addEdgeAndCreateId(DirectedEdge e, Vertex origin, Vertex terminus) { + e.setID(mNextId); + e.setOriginVertexId(origin.getID()); + e.setOriginPoint(origin.getCentrePoint()); + e.setTerminusVertexId(terminus.getID()); + e.setTerminusPoint(terminus.getCentrePoint()); + origin.addOutEdgeId(mNextId); + terminus.addInEdgeId(mNextId); + mEdgeHashtable.put(String.valueOf(mNextId), e); + mNextId++; + return mNextId - 1; + } + + // Removes an edge, but does not modify the selection + public void removeEdge(DirectedEdge e) { + Vertex origin = getOrigin(e); + Vertex terminus = getTerminus(e); + int edgeId = e.getID(); + // Remove the id of the edge from the origin and terminus vertices + origin.removeOutEdgeId(edgeId); + terminus.removeInEdgeId(edgeId); + // Remove the edge + mEdgeHashtable.remove(String.valueOf(e.getID())); + setChanged(); + notifyObservers(mEdgeRemovedEvent); + } + + public int addVertexAndCreateId(Vertex v, Point location) { + return addVertexAndCreateId(v, new GraphPoint(location.x, location.y)); + } + + public int addVertexAndCreateId(Vertex v, GraphPoint location) { + if (location!= null) + { + if (mVertexOutlineCreator == null) { + Logger.msg(1,"You cannot add a vertex with no outline creator"); + return -1; + + } + mVertexHashtable.put(String.valueOf(mNextId), v); + placeVertex(v, location); + } + v.setID(mNextId); + return mNextId++; + } + + public void placeVertex(Vertex v, GraphPoint location) { + v.setCentrePoint(location); + if (mVertexOutlineCreator != null) { + mVertexOutlineCreator.setOutline(v); + } + setChanged(); + notifyObservers(mVertexAddedEvent); + checkSize(v); + } + + // Removes a vertex, but does not modify the selection + public void removeVertex(Vertex v) { + DirectedEdge[] inEdges = getInEdges(v); + DirectedEdge[] outEdges = getOutEdges(v); + Vertex origin = null; + Vertex terminus = null; + int edgeId = -1; + int i = 0; + // For each in edge + for (i = 0; i < inEdges.length; i++) { + edgeId = inEdges[i].getID(); + origin = getOrigin(inEdges[i]); + // Remove the id of the edge from the origin vertex + origin.removeOutEdgeId(edgeId); + // Remove the edge + mEdgeHashtable.remove(String.valueOf(edgeId)); + } + // Remove all the out edges + for (i = 0; i < outEdges.length; i++) { + edgeId = outEdges[i].getID(); + terminus = getTerminus(outEdges[i]); + // Remove the id of the edge from the terminus vertex + terminus.removeInEdgeId(edgeId); + // Remove the edge + mEdgeHashtable.remove(String.valueOf(edgeId)); + } + // Remove the vertex + mVertexHashtable.remove(String.valueOf(v.getID())); + setChanged(); + notifyObservers(mVertexRemovedEvent); + } + + public void moveAbsoluteVertex(Vertex v, GraphPoint p) { + // Make sure the new position stays within the graph + if (p.x < 0) p.x = 0; + if (p.y < 0) p.y = 0; + if (p.x > mWidth) p.x = mWidth; + if (p.y > mHeight) p.y = mHeight; + moveAbsoluteVertexAndConnectingEdges(v, p); + setChanged(); + notifyObservers(mVertexMovedEvent); + } + + private void moveAbsoluteVertexAndConnectingEdges(Vertex v, GraphPoint p) { + DirectedEdge[] inEdges = getInEdges(v); + DirectedEdge[] outEdges = getOutEdges(v); + int i = 0; + // Move the vertex to the new position + v.moveAbsolute(p); + // Move the ends of the incoming edges to the new position + for (i = 0; i < inEdges.length; i++) { + inEdges[i].setTerminusPoint(p); + } + // Move the ends of the outgoing edges to the new position + for (i = 0; i < outEdges.length; i++) { + outEdges[i].setOriginPoint(p); + } + checkSize(v); + } + + public void moveAbsoluteSelection(int newTopLeftX, int newTopLeftY) { + int selectionHeight = mSelection.mBottomRightY - mSelection.mTopLeftY; + int selectionWidth = mSelection.mBottomRightX - mSelection.mTopLeftX; + int bottomRightX = newTopLeftX + selectionWidth; + int bottomRightY = newTopLeftY + selectionHeight; + GraphPoint oldCentrePoint = null; + GraphPoint newCentrePoint = null; + int distXFromTopLeft = 0; + int distYFromTopLeft = 0; + int i = 0; + // Make sure the selection does not move + // outside the boundaries of the graph + if (newTopLeftX < 0) newTopLeftX = 0; + if (newTopLeftY < 0) newTopLeftY = 0; + if (bottomRightX > mWidth) newTopLeftX = mWidth - selectionWidth; + if (bottomRightY > mHeight) newTopLeftY = mHeight - selectionHeight; + // For each selected vertex + for (i = 0; i < mSelection.mVertices.length; i++) { + // Calculate the new centre point of the vertex. + // First calculate the distance of the centre point + // from the old top left hand corner of the selection, + // then move the point to the new top left hand + // corner plus the distance. + oldCentrePoint = mSelection.mVertices[i].getCentrePoint(); + distXFromTopLeft = oldCentrePoint.x - mSelection.mTopLeftX; + distYFromTopLeft = oldCentrePoint.y - mSelection.mTopLeftY; + newCentrePoint = new GraphPoint(newTopLeftX + distXFromTopLeft, newTopLeftY + distYFromTopLeft); + moveAbsoluteVertexAndConnectingEdges(mSelection.mVertices[i], newCentrePoint); + } + // Update the top left and bottom right corners + mSelection.mTopLeftX = newTopLeftX; + mSelection.mTopLeftY = newTopLeftY; + mSelection.mBottomRightX = newTopLeftX + selectionWidth; + mSelection.mBottomRightY = newTopLeftY + selectionHeight; + setChanged(); + notifyObservers(mSelectionMovedEvent); + } + + public Vertex resolveVertex(int id) { + return mVertexHashtable.get(String.valueOf(id)); + } + + public DirectedEdge resolveEdge(int id) { + return mEdgeHashtable.get(String.valueOf(id)); + } + + public DirectedEdge[] getInEdges(Vertex v) { + int[] ids = v.getInEdgeIds(); + return resolveEdges(ids); + } + + public DirectedEdge[] getOutEdges(Vertex v) { + int[] ids = v.getOutEdgeIds(); + return resolveEdges(ids); + } + + private DirectedEdge[] resolveEdges(int[] ids) { + DirectedEdge[] edges = new DirectedEdge[ids.length]; + int i = 0; + for (i = 0; i < ids.length; i++) { + edges[i] = resolveEdge(ids[i]); + } + return edges; + } + + public Vertex getOrigin(DirectedEdge e) { + return resolveVertex(e.getOriginVertexId()); + } + + public Vertex getTerminus(DirectedEdge e) { + return resolveVertex(e.getTerminusVertexId()); + } + + public Vertex[] getInVertices(Vertex v) { + DirectedEdge[] inEdges = getInEdges(v); + Vertex[] inVertices = new Vertex[inEdges.length]; + int i = 0; + for (i = 0; i < inEdges.length; i++) { + inVertices[i] = getOrigin(inEdges[i]); + } + return inVertices; + } + + public Vertex[] getOutVertices(Vertex v) { + DirectedEdge[] outEdges = getOutEdges(v); + Vertex[] outVertices = new Vertex[outEdges.length]; + int i = 0; + for (i = 0; i < outEdges.length; i++) { + outVertices[i] = getTerminus(outEdges[i]); + } + return outVertices; + } + + public DirectedEdge[] getConnectingEdges(int originVertexId, int terminusVertexId) { + Vertex origin = resolveVertex(originVertexId); + DirectedEdge[] outEdges = null; + int numEdgesFound = 0; + DirectedEdge[] edgesFound = null; + int i = 0; + int j = 0; + if (origin == null) return null; + outEdges = getOutEdges(origin); + for (i = 0; i < outEdges.length; i++) { + if (outEdges[i].getTerminusVertexId() == terminusVertexId) { + numEdgesFound++; + } + } + edgesFound = new DirectedEdge[numEdgesFound]; + for (i = 0; i < outEdges.length; i++) { + if (outEdges[i].getTerminusVertexId() == terminusVertexId) { + edgesFound[j] = outEdges[i]; + j++; + } + } + return edgesFound; + } + + public void clearTags(Object tag) { + Vertex vertex = null; + Object[] vertexObjs = mVertexHashtable.values().toArray(); + int i = 0; + for (i = 0; i < vertexObjs.length; i++) { + vertex = (Vertex)vertexObjs[i]; + vertex.clearTag(tag); + } + } + + public void forceNotify() { + setChanged(); + notifyObservers(mForcedNotifyEvent); + } + + public void clear() { + mVertexHashtable = new Hashtable(); + mEdgeHashtable = new Hashtable(); + mStartVertexId = -1; + setChanged(); + notifyObservers(mClearedEvent); + } + + public void setSelection(Selection s) { + // If the there is a change + if (selectionChanged(s)) { + mSelection = s; + mSelectionChangedEvent.mSelection = s; + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + } + + private boolean selectionChanged(Selection newValue) { + int i = 0; + if (mSelection.mEdge != newValue.mEdge) { + return true; + } + if (mSelection.mVertices == null) { + if (newValue.mVertices == null) { + return false; + } + else { + return true; + } + } + else { + if (newValue.mVertices == null) { + return true; + } + else { + if (mSelection.mVertices.length != newValue.mVertices.length) { + return true; + } + for (i = 0; i < mSelection.mVertices.length; i++) { + if (mSelection.mVertices[i] != newValue.mVertices[i]) { + return true; + } + } + return false; + } + } + } + + public Selection getSelection() { + return mSelection; + } + + public void setNewEdgeOriginVertex(Vertex v) { + mNewEdgeOriginVertex = v; + } + + public Vertex getNewEdgeOriginVertex() { + return mNewEdgeOriginVertex; + } + + public void setNewEdgeEndPoint(Point p) { + mNewEdgeEndPoint = p; + setChanged(); + notifyObservers(mNewEdgeEndPointChangedEvent); + } + + public Point getNewEdgeEndPoint() { + return mNewEdgeEndPoint; + } + + public void setExternalVertexFactory(VertexFactory factory) { + mExternalVertexFactory = factory; + } + + public void createVertex(Point location, TypeNameAndConstructionInfo typeNameAndConstructionInfo) { + if (mExternalVertexFactory != null) { + mExternalVertexFactory.create(mManager, location, typeNameAndConstructionInfo); + setChanged(); + notifyObservers(mVertexCreatedEvent); + } + } + + public void setExternalEdgeFactory(EdgeFactory factory) { + mExternalEdgeFactory = factory; + } + + public void setVertexOutlineCreator(VertexOutlineCreator outlineCreator) { + mVertexOutlineCreator = outlineCreator; + } + + public void createDirectedEdge(Vertex origin, Vertex terminus, TypeNameAndConstructionInfo typeNameAndConstructionInfo) { + if (mExternalEdgeFactory != null) { + mExternalEdgeFactory.create(mManager, origin, terminus, typeNameAndConstructionInfo); + } + } + + public void selectAll() { + Vertex[] allVertices = getVertices(); + if (allVertices.length > 0) { + mSelection.mEdge = null; + mSelection.mVertices = allVertices; + updateSelectionCorners(); + mSelectionChangedEvent.mSelection = mSelection; + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + } + + public void selectContentsOfElasticBand() { + if (mElasticBand == null) return; + Polygon bandPolygon = new Polygon(); + Vertex[] allVertices = getVertices(); + GraphPoint centrePoint = null; + Vector verticesInside = new Vector(10, 10); + int i = 0; + // Create a polygon representing the elastic band + bandPolygon.addPoint(mElasticBand.mFixedCorner.x, mElasticBand.mFixedCorner.y); + bandPolygon.addPoint(mElasticBand.mMovingCorner.x, mElasticBand.mFixedCorner.y); + bandPolygon.addPoint(mElasticBand.mMovingCorner.x, mElasticBand.mMovingCorner.y); + bandPolygon.addPoint(mElasticBand.mFixedCorner.x, mElasticBand.mMovingCorner.y); + // Create a vector of all of the vertices within the elastic band polygon + for (i = 0; i < allVertices.length; i++) { + centrePoint = allVertices[i].getCentrePoint(); + if (bandPolygon.contains(centrePoint.x, centrePoint.y)) { + verticesInside.add(allVertices[i]); + } + } + + // Select the vertices found within the elastic band polygon + if (verticesInside.size() == 0) { + mSelection.mTopLeftX = 0; + mSelection.mTopLeftY = 0; + mSelection.mBottomRightX = 0; + mSelection.mBottomRightY = 0; + mSelection.mEdge = null; + if (mContainingVertex != null) + verticesInside.add(mContainingVertex); + else + mSelection.mVertices = null; + } + + if (verticesInside.size() > 0) { + mSelection.mEdge = null; + mSelection.mVertices = new Vertex[verticesInside.size()]; + for (i = 0; i < verticesInside.size(); i++) { + mSelection.mVertices[i] = verticesInside.elementAt(i); + } + updateSelectionCorners(); + } + // Remove the elastic band + mElasticBand = null; + mSelectionChangedEvent.mSelection = mSelection; + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + + // Updates the top left and bottom right corners of the selection + private void updateSelectionCorners() { + Vertex vertex = mSelection.mVertices[0]; + GraphPoint centrePoint = vertex.getCentrePoint(); + if (centrePoint == null) return; + mSelection.mTopLeftX = centrePoint.x; + mSelection.mTopLeftY = centrePoint.y; + mSelection.mBottomRightX = centrePoint.x; + mSelection.mBottomRightY = centrePoint.y; + for (Vertex mVertice : mSelection.mVertices) { + vertex = mVertice; + centrePoint = vertex.getCentrePoint(); + if (centrePoint.x < mSelection.mTopLeftX) { + mSelection.mTopLeftX = centrePoint.x; + } + if (centrePoint.y < mSelection.mTopLeftY) { + mSelection.mTopLeftY = centrePoint.y; + } + if (centrePoint.x > mSelection.mBottomRightX) { + mSelection.mBottomRightX = centrePoint.x; + } + if (centrePoint.y > mSelection.mBottomRightY) { + mSelection.mBottomRightY = centrePoint.y; + } + } + } + + public void deleteSelection() { + int i = 0; + if (mSelection.mVertices != null) { + for (i = 0; i < mSelection.mVertices.length; i++) { + removeVertex(mSelection.mVertices[i]); + } + } + else if (mSelection.mEdge != null) { + removeEdge(mSelection.mEdge); + } + // Make sure nothing is selected + if ((mSelection.mEdge != null) || (mSelection.mVertices != null)) { + mSelection.mEdge = null; + mSelection.mVertices = null; + mSelectionChangedEvent.mSelection = mSelection; + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + } + + public void setSelectedVertexToBeStart() { + if (mSelection.mVertices != null) { + if (mSelection.mVertices.length == 1) { + setStartVertexId(mSelection.mVertices[0].getID()); + setChanged(); + notifyObservers(mStartVertexIdChangedEvent); + } + } + } + + public void setElasticBand(ElasticBand elasticBand) { + mElasticBand = elasticBand; + setChanged(); + notifyObservers(mElasticBandSetEvent); + } + + public ElasticBand getElasticBand() { + return mElasticBand; + } + + public void resizeElasticBand(Point movingCorner) { + mElasticBand.mMovingCorner = movingCorner; + setChanged(); + notifyObservers(mElasticBandResizedEvent); + } + + public boolean inSelection(Vertex v) { + int i = 0; + if (mSelection.mVertices == null) { + return false; + } + else { + for (i = 0; i < mSelection.mVertices.length; i++) { + if (mSelection.mVertices[i] == v) { + return true; + } + } + return false; + } + } + + // Only use this method to remove one vertex. + // If you wish to remove more, it would + // propably be more efficient to create a + // new Selection object. + public void removeFromSelection(Vertex v) { + Vertex[] vertices = null; + int i = 0; + int j = 0; + if (mSelection.mVertices.length == 1) { + mSelection.mVertices = null; + mSelection.mTopLeftX = 0; + mSelection.mTopLeftY = 0; + mSelection.mBottomRightX = 0; + mSelection.mBottomRightY = 0; + } + else { + vertices = new Vertex[mSelection.mVertices.length - 1]; + for (i = 0; i < mSelection.mVertices.length; i++) { + if (mSelection.mVertices[i] != v) { + vertices[j] = mSelection.mVertices[i]; + j++; + } + } + mSelection.mVertices = vertices; + updateSelectionCorners(); + } + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + + // Only use this method to add one vertex. + // If you wish to add more, it would + // propably be more efficient to create a + // new Selection object. + public void addToSelection(Vertex v) { + Vertex[] vertices = new Vertex[mSelection.mVertices.length + 1]; + GraphPoint centrePoint = null; + int i = 0; + if (mSelection.mVertices == null) { + centrePoint = v.getCentrePoint(); + mSelection.mVertices = new Vertex[] { v }; + mSelection.mTopLeftX = centrePoint.x; + mSelection.mTopLeftY = centrePoint.y; + mSelection.mBottomRightX = centrePoint.x; + mSelection.mBottomRightY = centrePoint.y; + } + else { + for (i = 0; i < mSelection.mVertices.length; i++) { + vertices[i] = mSelection.mVertices[i]; + } + vertices[mSelection.mVertices.length] = v; + mSelection.mVertices = vertices; + updateSelectionCorners(); + } + setChanged(); + notifyObservers(mSelectionChangedEvent); + } + + public void resetVertexOutlines() { + Vertex[] vertices = getVertices(); + int i = 0; + for (i = 0; i < vertices.length; i++) { + mVertexOutlineCreator.setOutline(vertices[i]); + } + } + + public void setGraphModelCastorData(GraphModelCastorData data) { + Class vertexOutlineCreatorClass = null; + int i = 0; + // Create the vertex outline creator + if (data.mClassNameOfVertexOutlineCreator.equals("")) { + mVertexOutlineCreator = null; + } + else { + try { + vertexOutlineCreatorClass = Class.forName(data.mClassNameOfVertexOutlineCreator); + mVertexOutlineCreator = (VertexOutlineCreator)vertexOutlineCreatorClass.newInstance(); + } + catch (Exception e) { + e.printStackTrace(); + mVertexOutlineCreator = null; + } + } + // Create and populate the vertex hashtable + mVertexHashtable = new Hashtable(); + for (i = 0; i < data.mVertexImpls.length; i++) { + mVertexHashtable.put(String.valueOf(data.mVertexImpls[i].getID()), data.mVertexImpls[i]); + checkSize(data.mVertexImpls[i]); + } + // Create and populate the edge hastable + mEdgeHashtable = new Hashtable(); + for (i = 0; i < data.mEdgeImpls.length; i++) { + mEdgeHashtable.put(String.valueOf(data.mEdgeImpls[i].getID()), data.mEdgeImpls[i]); + } + // Set the start vertex id and the id generation counter + mStartVertexId = data.mStartVertexId; + mNextId = data.mNextId; + } + + public GraphModelCastorData getGraphModelCastorData() { + Object[] vertexObjs = mVertexHashtable.values().toArray(); + Vertex[] vertexImpls = new Vertex[vertexObjs.length]; + Object[] edgeObjs = mEdgeHashtable.values().toArray(); + DirectedEdge[] directedEdgeImpls = new DirectedEdge[edgeObjs.length]; + String className = null; + int i = 0; + // Put in the vertices + for (i = 0; i < vertexImpls.length; i++) { + vertexImpls[i] = (Vertex)vertexObjs[i]; + } + // Put in the edges + for (i = 0; i < directedEdgeImpls.length; i++) { + directedEdgeImpls[i] = (DirectedEdge)edgeObjs[i]; + } + // Determine the class name of the vertex outline creator + if (mVertexOutlineCreator == null) { + className = ""; + } + else { + className = mVertexOutlineCreator.getClass().getName(); + } + return new GraphModelCastorData(className, vertexImpls, directedEdgeImpls, mStartVertexId, mNextId); + } +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java b/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java new file mode 100644 index 0000000..7717c33 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphModelCastorData.java @@ -0,0 +1,29 @@ +package com.c2kernel.graph.model; + + +public class GraphModelCastorData +{ + public String mClassNameOfVertexOutlineCreator = ""; + public Vertex[] mVertexImpls = {}; + public DirectedEdge[] mEdgeImpls = {}; + public int mStartVertexId = 0; + public int mNextId = 0; + + + public GraphModelCastorData() + { + } + + public GraphModelCastorData(String classNameOfVertexOutlineCreator, + Vertex[] vertexImpls, + DirectedEdge[] edgeImpls, + int startVertexId, + int nextId) + { + mClassNameOfVertexOutlineCreator = classNameOfVertexOutlineCreator; + mVertexImpls = vertexImpls; + mEdgeImpls = edgeImpls; + mStartVertexId = startVertexId; + mNextId = nextId; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphModelManager.java b/src/main/java/com/c2kernel/graph/model/GraphModelManager.java new file mode 100644 index 0000000..68d47e0 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphModelManager.java @@ -0,0 +1,143 @@ +package com.c2kernel.graph.model; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Observable; +import java.util.Stack; + +import com.c2kernel.graph.event.EntireModelChangedEvent; +import com.c2kernel.graph.event.ForcedNotifyEvent; +import com.c2kernel.graph.event.GraphModelEvent; +import com.c2kernel.utils.Logger; + + +public class GraphModelManager extends Observable +{ + + private GraphModel mGraphModel; + private EdgeFactory mEdgeFactory; + private VertexFactory mVertexFactory; + private VertexOutlineCreator mVertexOutlineCreator; + private EntireModelChangedEvent mEntireModelChangedEvent = new EntireModelChangedEvent(); + private ForcedNotifyEvent mForcedNotifyEvent = new ForcedNotifyEvent(); + private Stack mParentModels = new Stack(); + private ArrayList mParentIds = new ArrayList(); + private boolean mEditable = true; + + // Calling this constructor does not create a vertex outline creator + // which is required by the method addVertexAndCreateId() + public GraphModelManager() + { + mGraphModel = new GraphModel(); + mGraphModel.setManager(this); + } + + public GraphModelManager(GraphModel newModel) { + newModel.setManager(this); + mGraphModel = newModel; + } + + public void replace(GraphModel newModel) { + mParentModels.clear(); + + //zoom back to where we were + for (Iterator iter = mParentIds.iterator(); iter.hasNext();) { + Integer parentId = iter.next(); + GraphableVertex childModelVertex = (GraphableVertex)newModel.getVertexById(parentId.intValue()); + if (childModelVertex == null) { // we've been deleted, stay here + Logger.msg(7, "Didn't find "+parentId+" in new model tree. Stopping here."); + do { iter.remove(); } while (iter.hasNext()); + break; + } + else { + mParentModels.push(newModel); + Logger.msg(7, "Pushing model and switching to "+parentId); + newModel = childModelVertex.getChildGraphModel(); + } + } + setModel(newModel); + } + + public void setModel(GraphModel newModel) { + // reset transient data + newModel.mSelection = new Selection(null, null, 0, 0, 0, 0); + newModel.mNewEdgeOriginVertex = null; + newModel.mNewEdgeEndPoint = null; + + // copy factories over + newModel.setExternalEdgeFactory(mEdgeFactory); + newModel.setExternalVertexFactory(mVertexFactory); + newModel.setVertexOutlineCreator(mVertexOutlineCreator); + mVertexFactory.setCreationContext(newModel.getContainingVertex()); + newModel.setManager(this); + mGraphModel.setManager(null); + mGraphModel = newModel; + + // notify + setChanged(); + notifyObservers(mEntireModelChangedEvent); + } + + public void zoomIn(Vertex child) { + GraphModel childModel = child.getChildGraphModel(); + if (childModel != null) { + mParentModels.push(mGraphModel); + mParentIds.add(new Integer(child.getID())); + setModel(childModel); + Logger.msg(7, "ZoomIn - Stack size: "+mParentModels.size()+" ids:"+mParentIds.size()); + } + } + + public void zoomOut() { + if (!mParentModels.empty()) { + setModel(mParentModels.pop()); + mParentIds.remove(mParentIds.size()-1); + } + Logger.msg(7, "ZoomOut - Stack size: "+mParentModels.size()+" ids:"+mParentIds.size()); + + } + + public void forceNotify() + { + setChanged(); + notifyObservers(mForcedNotifyEvent); + } + + public GraphModel getModel() { + return mGraphModel; + } + + public void setExternalEdgeFactory(EdgeFactory newEdgeFactory) { + mEdgeFactory = newEdgeFactory; + mGraphModel.setExternalEdgeFactory(newEdgeFactory); + } + + public void setExternalVertexFactory(VertexFactory newVertexFactory) { + mVertexFactory = newVertexFactory; + mGraphModel.setExternalVertexFactory(newVertexFactory); + } + + public void setVertexOutlineCreator(VertexOutlineCreator newVertexOutlineCreator) { + mVertexOutlineCreator = newVertexOutlineCreator; + mGraphModel.setVertexOutlineCreator(newVertexOutlineCreator); + } + + @Override + protected void setChanged() { + super.setChanged(); + } + + protected void notifyObservers(GraphModelEvent ev) { + super.notifyObservers(ev); + } + + public void setEditable(boolean editable) { + mEditable = editable; + } + + public boolean isEditable() { + return mEditable; + } + + +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphPoint.java b/src/main/java/com/c2kernel/graph/model/GraphPoint.java new file mode 100644 index 0000000..f2aa165 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphPoint.java @@ -0,0 +1,18 @@ +package com.c2kernel.graph.model; + +import java.io.Serializable; + +public class GraphPoint implements Serializable{ + + public int x; + public int y; + + public GraphPoint() { + x=0; y=0; + } + + public GraphPoint(int x, int y) { + this.x = x; + this.y = y; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/Graphable.java b/src/main/java/com/c2kernel/graph/model/Graphable.java new file mode 100644 index 0000000..ed55271 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/Graphable.java @@ -0,0 +1,55 @@ +package com.c2kernel.graph.model; + +/** +* @version $Revision: 1.6 $ $Date: 2003/05/12 13:10:20 $ +* @author $Author: abranson $ +*/ + +import com.c2kernel.utils.CastorHashMap; + +abstract public class Graphable extends Vertex +{ + + protected CastorHashMap mProperties = null; + public GraphModel children; + + public void setProperties(CastorHashMap props) + { + mProperties = props; + } + + public CastorHashMap getProperties() + { + return mProperties; + } + /** @associates Graphable that is directly containing it*/ + private Graphable parent; + + /** + * Returns the parent. + * @return Graphable + */ + public Graphable getParent() + { + return parent; + } + + /** + * Sets the parent. + * @param parent The parent to set + */ + public void setParent(Graphable parent) + { + this.parent = parent; + } + @Override + public GraphModel getChildGraphModel() { + return children; + } + + @Override + public Object getCreationContext() { + return this; + } + +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphableEdge.java b/src/main/java/com/c2kernel/graph/model/GraphableEdge.java new file mode 100644 index 0000000..23499be --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphableEdge.java @@ -0,0 +1,71 @@ +package com.c2kernel.graph.model; + +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.KeyValuePair; + +/** +* @version $Revision: 1.2 $ $Date: 2003/05/12 13:10:20 $ +* @author $Author: abranson $ +*/ +public abstract class GraphableEdge extends DirectedEdge +{ + + private GraphableVertex mParent; + private CastorHashMap mProperties = null; + + public GraphableEdge() + { + mProperties = new CastorHashMap(); + } + + public GraphableEdge(GraphableVertex pre, GraphableVertex nex) + { + mProperties = new CastorHashMap(); + setParent(pre.getParent()); + pre.getParent().getChildrenGraphModel().addEdgeAndCreateId(this, pre, nex); + } + + /** + * Returns the parent. + * @return GraphableVertex + */ + public GraphableVertex getParent() + { + return mParent; + } + + /** + * Sets the parent. + * @param parent The parent to set + */ + public void setParent(GraphableVertex parent) + { + mParent = parent; + } + + /** + * Returns the properties. + * @return CastorHashMap + */ + public CastorHashMap getProperties() + { + return mProperties; + } + + /** + * Sets the properties. + * @param properties The properties to set + */ + public void setProperties(CastorHashMap properties) + { + mProperties = properties; + } + + public KeyValuePair[] getKeyValuePairs() { + return mProperties.getKeyValuePairs(); + } + + public void setKeyValuePairs(KeyValuePair[] pairs) { + mProperties.setKeyValuePairs(pairs); + } +} diff --git a/src/main/java/com/c2kernel/graph/model/GraphableVertex.java b/src/main/java/com/c2kernel/graph/model/GraphableVertex.java new file mode 100644 index 0000000..fc04743 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/GraphableVertex.java @@ -0,0 +1,261 @@ +package com.c2kernel.graph.model; +/** +* @version $Revision: 1.24 $ $Date: 2005/10/05 07:39:37 $ +* @author $Author: abranson $ +*/ +import java.awt.Point; + +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.KeyValuePair; +public abstract class GraphableVertex extends Vertex +{ + private CastorHashMap mProperties = null; + private boolean mIsLayoutable; + protected boolean mIsComposite; + private GraphModel mChildrenGraphModel; + public GraphableVertex() + { + mProperties = new CastorHashMap(); + } + public void setProperties(CastorHashMap props) + { + mProperties = props; + } + public CastorHashMap getProperties() + { + return mProperties; + } + public KeyValuePair[] getKeyValuePairs() + { + return mProperties.getKeyValuePairs(); + } + public void setKeyValuePairs(KeyValuePair[] pairs) + { + mProperties.setKeyValuePairs(pairs); + } + /** @associates Graphable that is directly containing it*/ + private GraphableVertex parent; + /** + * Returns the parent. + * @return Graphable + */ + public GraphableVertex getParent() + { + return parent; + } + /** + * Sets the parent. + * @param parent The parent to set + */ + public void setParent(GraphableVertex parent) + { + if (this.equals(parent)) + throw new ExceptionInInitializerError(); + this.parent = parent; + } + @Override + public GraphModel getChildGraphModel() + { + return mChildrenGraphModel; + } + @Override + public Object getCreationContext() + { + return this; + } + public Vertex[] getOutGraphables() + { + if (parent == null) + return new Vertex[0]; // none if no parent + return parent.mChildrenGraphModel.getOutVertices(this); + } + public DirectedEdge[] getOutEdges() + { + if (parent == null) + return new DirectedEdge[0]; // none if no parent + return parent.mChildrenGraphModel.getOutEdges(this); + } + public DirectedEdge[] getInEdges() + { + if (parent == null) + return new DirectedEdge[0]; // none if no parent + DirectedEdge[] edges = getParent().mChildrenGraphModel.getInEdges(this); + if (edges != null) + return edges; + else + return new DirectedEdge[0]; + } + public GraphableVertex[] getChildren() + { + return getLayoutableChildren(); + } + + public DirectedEdge[] getChildrenEdges() + { + if (getIsComposite()) + { + return getChildGraphModel().getEdges(); + } + return null; + } + + public GraphableVertex[] getLayoutableChildren() + { + if (getIsComposite()) + { + Vertex[] vs = mChildrenGraphModel.getVertices(); + GraphableVertex[] gvs = new GraphableVertex[vs.length]; + for (int i = 0; i < vs.length; i++) + { + gvs[i] = (GraphableVertex) vs[i]; + } + return gvs; + } + return null; + } + // deprecated methods + public GraphableVertex[] getCNonLayoutableChildren() { + return new GraphableVertex[0]; + } + public void setCNonLayoutableChildren(GraphableVertex[] dummy) { } + + /**@returns the Graphable searched or null if not this or children*/ + public GraphableVertex search(String ids) + { + if (getName().equals(ids)) + return this; + if (String.valueOf(getID()).equals(ids)) + return this; + if (getIsComposite()) + { + GraphableVertex[] graphables = getChildren(); + if (ids.startsWith(String.valueOf(getID()))) + ids = ids.substring(ids.indexOf("/") + 1); + else if (ids.startsWith(getName())) + ids = ids.substring(getName().length() + 1); + else if (ids.startsWith(getPath())) + ids = ids.substring(getPath().length() + 1); + else + return null; + + for (GraphableVertex graphable : graphables) { + GraphableVertex grap = graphable.search(ids); + if (grap != null) return grap; + } + } + return null; + } + /** + * Returns the isLayoutable. + * @return boolean + */ + public boolean getIsLayoutable() + { + return mIsLayoutable; + } + /** + * Sets the isLayoutable. + * @param isLayoutable The isLayoutable to set + */ + public void setIsLayoutable(boolean isLayoutable) + { + mIsLayoutable = isLayoutable; + } + /** + * Returns the isComposite. + * @return boolean + */ + public boolean getIsComposite() + { + return mIsComposite; + } + /** + * Sets the isComposite. + * @param isComposite The isComposite to set + */ + public void setIsComposite(boolean isComposite) + { + mIsComposite = isComposite; + } + public void addChild(GraphableVertex graphableVertex, Point p) + { + addChild(graphableVertex, new GraphPoint(p.x, p.y)); + } + public void addChild(GraphableVertex graphableVertex, GraphPoint g) + { + getChildGraphModel().addVertexAndCreateId(graphableVertex, g); + graphableVertex.setParent(this); + } + /** + * Returns the childrenGraph. + * @return GraphModel + */ + public GraphModel getChildrenGraphModel() + { + return mChildrenGraphModel; + } + /** + * Sets the childrenGraph. + * @param childrenGraph The childrenGraph to set + */ + public void setChildrenGraphModel(GraphModel childrenGraph) + { + mChildrenGraphModel = childrenGraph; + DirectedEdge[] edges = mChildrenGraphModel.getEdges(); + GraphableVertex[] graphables = this.getLayoutableChildren(); + if (graphables != null) + for (GraphableVertex graphable : graphables) + graphable.setParent(this); + if (edges != null) + for (DirectedEdge edge : edges) + ((GraphableEdge) edge).setParent(this); + childrenGraph.setContainingVertex(this); + } + + /** + * @see com.c2kernel.graph.model.Vertex#getCentrePoint() + */ + @Override + public GraphPoint getCentrePoint() + { + if (!getIsLayoutable()) + return null; + return super.getCentrePoint(); + } + /** + * @see com.c2kernel.graph.model.Vertex#getInEdgeIds() + */ + @Override + public int[] getInEdgeIds() + { + if (!getIsLayoutable()) + return null; + return super.getInEdgeIds(); + } + /** + * @see com.c2kernel.graph.model.Vertex#getOutEdgeIds() + */ + @Override + public int[] getOutEdgeIds() + { + if (!getIsLayoutable()) + return null; + return super.getOutEdgeIds(); + } + /** + * @see com.c2kernel.graph.model.Vertex#getOutlinePoints() + */ + @Override + public GraphPoint[] getOutlinePoints() + { + if (!getIsLayoutable()) + return null; + return super.getOutlinePoints(); + } + public String getPath() + { + if (getName() != null && !getName().equals("")) + return getParent().getPath() + "/" + getName(); + return getParent().getPath() + "/" + getID(); + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/graph/model/Selection.java b/src/main/java/com/c2kernel/graph/model/Selection.java new file mode 100644 index 0000000..dcc7b46 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/Selection.java @@ -0,0 +1,35 @@ +package com.c2kernel.graph.model; + +import java.io.Serializable; + + + +public class Selection implements Serializable +{ + // Either a single edge can be selected or + // one or more vertices can be selected. + // It is impossible to select an edge and a + // vertex at the same time. + public DirectedEdge mEdge = null; + public Vertex[] mVertices = null; + public int mTopLeftX = 0; + public int mTopLeftY = 0; + public int mBottomRightX = 0; + public int mBottomRightY = 0; + + + public Selection(DirectedEdge edge, + Vertex[] vertices, + int topLeftX, + int topLeftY, + int bottomRightX, + int bottomRightY) + { + mEdge = edge; + mVertices = vertices; + mTopLeftX = topLeftX; + mTopLeftY = topLeftY; + mBottomRightX = bottomRightX; + mBottomRightY = bottomRightY; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java b/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java new file mode 100644 index 0000000..e5b6c3d --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/TypeNameAndConstructionInfo.java @@ -0,0 +1,24 @@ +package com.c2kernel.graph.model; + +import java.io.Serializable; + + +public class TypeNameAndConstructionInfo implements Serializable +{ + public String mName = null; + public Object mInfo = null; + + + public TypeNameAndConstructionInfo(String name, Object info) + { + mName = name; + mInfo = info; + } + + + @Override + public String toString() + { + return mName; + } +} diff --git a/src/main/java/com/c2kernel/graph/model/Vertex.java b/src/main/java/com/c2kernel/graph/model/Vertex.java new file mode 100644 index 0000000..ccef437 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/model/Vertex.java @@ -0,0 +1,308 @@ +package com.c2kernel.graph.model; + +import java.awt.Polygon; +import java.io.Serializable; +import java.util.Vector; + + +public class Vertex implements Serializable +{ + private int mId = -1; + private String mName = ""; + private GraphPoint mCentrePoint = new GraphPoint(0, 0); + private int mHeight = 0; + private int mWidth = 0; + private Vector mInEdgeIdVector = new Vector(); + private Vector mOutEdgeIdVector = new Vector(); + private Vector mTags = new Vector(); + + // The Java Polygon class is used to determine if a point + // lies within the outline of a vertex. Unfortunately + // both the polygon and the set of outline points need to + // kept in memory because a polygon never has 0 points + // which is required by Castor's unmarshall object mechanism + private Polygon mOutlinePolygon = new Polygon(); + private GraphPoint[] mOutlinePoints = new GraphPoint[0]; + + + private GraphModel graphModel; + + public void setID(int id) + { + mId = id; + } + + + public int getID() + { + return mId; + } + + + public void setName(String n) + { + mName = n; + } + + + public String getName() + { + return mName; + } + + + public void setCentrePoint(GraphPoint p) + { + mCentrePoint = p; + } + + + public GraphPoint getCentrePoint() + { + return mCentrePoint; + } + + + public void setHeight(int h) + { + mHeight = h; + } + + + public int getHeight() + { + return mHeight; + } + + + public void setWidth(int w) + { + mWidth = w; + } + + + public int getWidth() + { + return mWidth; + } + + + // Sets the outline points and re-calculates the + // height and width + public void setOutlinePoints(GraphPoint[] outline) + { + int topLeftX = outline[0].x; + int topLeftY = outline[0].y; + int bottomRightX = 0; + int bottomRightY = 0; + int i = 0; + + mOutlinePoints = outline; + + // Construct a polygon in the outline of the vertex + // and calculate the top left and bottom right corners + mOutlinePolygon = new Polygon(); + + for(i=0; i bottomRightX) + { + bottomRightX = outline[i].x; + } + + + if(outline[i].y > bottomRightY) + { + bottomRightY = outline[i].y; + } + } + + // Set the height and width + mHeight = bottomRightY - topLeftY; + mWidth = bottomRightX - topLeftX; + } + + + public GraphPoint[] getOutlinePoints() + { + return mOutlinePoints; + } + + public void moveAbsolute(GraphPoint p) + { + int deltaX = p.x - mCentrePoint.x; + int deltaY = p.y - mCentrePoint.y; + int i = 0; + + // Update the outline points and the polygon + for(i=0; i(10, 10); + for(i=0; i(10, 10); + for(i=0; i vector) + { + int[] array = new int[vector.size()]; + Integer integer = null; + int i = 0; + + for(i=0; i path = new Vector(10, 10); + + graphModel.clearTags(startVertex); + visitVertex(startVertex, graphModel, path, direction, startVertex, ignoreBackLinks); + + return vectorToVertexArray(path); + } + + + private static void visitVertex(Vertex vertex, GraphModel graphModel, Vector path, int direction, Object tag, boolean ignoreBackLinks) + { + Vertex[] children = null; + int i = 0; + + if(direction == kDown) + { + children = graphModel.getOutVertices(vertex); + } + else + { + children = graphModel.getInVertices(vertex); + } + + vertex.setTag(tag); + path.add(vertex); + + for(i=0; i vector) + { + Vertex[] vertices = new Vertex[vector.size()]; + int i = 0; + + + for(i=0; i 0)) return Math.PI; + + if((width == 0) && (height < 0)) return 0; + + if((width > 0) && (height == 0)) return Math.PI/2.0; + + if((width < 0) && (height == 0)) return -1.0 * Math.PI/2.0; + + if((width > 0) && (height > 0)) return Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width)); + + if((width > 0) && (height < 0)) return Math.atan(Math.abs(width)/Math.abs(height)); + + if((width < 0) && (height < 0)) return -1.0 * Math.atan(Math.abs(width)/Math.abs(height)); + + if((width < 0) && (height > 0)) return -1.0 * (Math.PI/2.0 + Math.atan(Math.abs(height)/Math.abs(width))); + + return 0.0; + } +} diff --git a/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java b/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java new file mode 100644 index 0000000..e9b92d0 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/DefaultVertexRenderer.java @@ -0,0 +1,60 @@ +package com.c2kernel.graph.view; + +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Polygon; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; + + +public class DefaultVertexRenderer implements VertexRenderer +{ + private Paint mLinePaint = null; + private Paint mTextPaint = null; + private Paint mFillPaint = null; + + + public DefaultVertexRenderer(Paint linePaint, Paint textPaint, Paint fillPaint) + { + mLinePaint = linePaint; + mTextPaint = textPaint; + mFillPaint = fillPaint; + } + + + @Override + public void draw(Graphics2D g2d, Vertex vertex) + { + GraphPoint[] outlinePoints = vertex.getOutlinePoints(); + GraphPoint centrePoint = vertex.getCentrePoint(); + Polygon outline = new Polygon(); + + String vertexName = vertex.getName(); + FontMetrics metrics = g2d.getFontMetrics(); + int textWidth = metrics.stringWidth(vertexName); + int textHeight = metrics.getHeight(); + int textX = centrePoint.x - textWidth/2; + int textY = centrePoint.y + textHeight/3; + + int i = 0; + + + // Construct a shape in the outline of the vertex + for(i=0; i mListenerVector = new Vector(10, 10); + public EditorToolBar(boolean edgeCreationMode, // True if edges can be created + JButton[] otherButtons, GraphPanel graphP) + { + super(BoxLayout.X_AXIS); + mGraphPanel = graphP; + mEdgeCreationMode = edgeCreationMode; + mOtherButtons = otherButtons; + prepareModeButtons(); + mStartVertexController.setStartButton(mStartButton); + mDeletionController.setDeleteButton(mDeleteButton); + createLayout(); + createListeners(); + } + protected void prepareModeButtons() + { + // Set the tool tip texts + mVertexModeButton.setToolTipText(Language.translate("Create vertex")); + mSelectModeButton.setToolTipText(Language.translate("Multi-select and drag")); + mEdgeModeButton.setToolTipText(Language.translate("Create edge")); + mStartButton.setToolTipText(Language.translate("Select the start vertex of the graph")); + mDeleteButton.setToolTipText(Language.translate("Delete the selection")); + mPrintButton.setToolTipText(Language.translate("Print this graph")); + mPrintButton.setToolTipText(Language.translate("Copy an image of this graph to the clipboard")); + // Set the button margins to 0 + mVertexModeButton.setMargin(new Insets(0, 0, 0, 0)); + mSelectModeButton.setMargin(new Insets(0, 0, 0, 0)); + mEdgeModeButton.setMargin(new Insets(0, 0, 0, 0)); + // The initial mode is select mode + mSelectModeButton.setSelected(true); + // Add the mode buttons to the mode button group + mModeButtonGroup.add(mVertexModeButton); + mModeButtonGroup.add(mSelectModeButton); + mModeButtonGroup.add(mEdgeModeButton); + // Add the action listeners + mVertexModeButton.addActionListener(new ModeButtonListener("Vertex")); + mSelectModeButton.addActionListener(new ModeButtonListener("Select")); + mEdgeModeButton.addActionListener(new ModeButtonListener("Edge")); + } + public void enterSelectMode() + { + mSelectModeButton.setSelected(true); + notifyListeners("Select"); + } + public void updateVertexTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo) + { + int i = 0; + mVertexTypeBox.removeAllItems(); + for (i = 0; i < typeNameAndConstructionInfo.length; i++) + { + mVertexTypeBox.addItem(typeNameAndConstructionInfo[i]); + } + } + public void updateEdgeTypes(TypeNameAndConstructionInfo[] typeNameAndConstructionInfo) + { + int i = 0; + mEdgeTypeBox.removeAllItems(); + for (i = 0; i < typeNameAndConstructionInfo.length; i++) + { + mEdgeTypeBox.addItem(typeNameAndConstructionInfo[i]); + } + } + public TypeNameAndConstructionInfo getSelectedVertexType() + { + return (TypeNameAndConstructionInfo) mVertexTypeBox.getSelectedItem(); + } + public TypeNameAndConstructionInfo getSelectedEdgeType() + { + return (TypeNameAndConstructionInfo) mEdgeTypeBox.getSelectedItem(); + } + protected void createLayout() + { + int i = 0; + add(mSelectModeButton); + add(mVertexModeButton); + add(mVertexTypeBox); + add(Box.createHorizontalStrut(10)); + if (mEdgeCreationMode) + { + add(mEdgeModeButton); + add(mEdgeTypeBox); + } + add(Box.createGlue()); + mPrintButton.setEnabled(true); + mPrintButton.setMargin(new Insets(0, 0, 0, 0)); + add(mPrintButton); + mCopyButton.setEnabled(true); + mCopyButton.setMargin(new Insets(0, 0, 0, 0)); + add(mCopyButton); + mStartButton.setEnabled(false); + mStartButton.setMargin(new Insets(0, 0, 0, 0)); + mDeleteButton.setEnabled(false); + mDeleteButton.setMargin(new Insets(0, 0, 0, 0)); + add(mDeleteButton); + add(Box.createRigidArea(new Dimension(20, 0))); + add(mStartButton); + if (mOtherButtons != null) + { + for (i = 0; i < mOtherButtons.length; i++) + { + mOtherButtons[i].setMargin(new Insets(0, 0, 0, 0)); + add(mOtherButtons[i]); + } + } + } + protected void createListeners() + { + // The vertex mode button should be selected if the + // user select a vertex type from the vertex type box + mVertexTypeBox.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + mVertexModeButton.setSelected(true); + notifyListeners("Vertex"); + } + }); + // The edge mode button should be selected if the + // user select an edge type from the edge type box + mEdgeTypeBox.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + mEdgeModeButton.setSelected(true); + notifyListeners("Edge"); + } + }); + mPrintButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + PrinterJob _monJob = PrinterJob.getPrinterJob(); + if (_monJob.printDialog()) + _monJob.setPrintable(self()); + try + { + _monJob.print(); + } + catch (Exception ex) + { + } + } + }); + + try { + Class.forName("java.awt.datatransfer.DataFlavor").getDeclaredField("imageFlavor"); + mCopyButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + try + { + Image i = createImage(mGraphPanel.getWidth(),mGraphPanel.getHeight()); + Graphics g = i.getGraphics(); + mGraphPanel.paintComponent(g); + ImageTransferable it = new ImageTransferable(i, mGraphPanel.getWidth(), mGraphPanel.getHeight()); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(it, it); + } + catch (Exception e) + { + Logger.error(e); + } + } + }); + } catch (Exception ex) { //image clipboard transfer not supported + mCopyButton.setEnabled(false); + } + } + + protected class ImageTransferable implements Transferable, ClipboardOwner { + Image image; + int width,height; + DataFlavor javaImg; + public ImageTransferable(Image image, int width, int height) { + this.image = image; + this.width = width; + this.height = height; + try { + javaImg = new DataFlavor("image/x-java-image; class=java.awt.Image", "AWT Image"); + } catch (Exception ex){ } + } + @Override + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + if (!isDataFlavorSupported(flavor) || image == null) { + throw new UnsupportedFlavorException(flavor); + } + return image; + } + + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + boolean result = in(flavor, getTransferDataFlavors()); + return result; + } + + @Override + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { javaImg }; + } + protected boolean in(DataFlavor flavor, DataFlavor[] flavors) { + int f = 0; + while ((f < flavors.length) && !flavor.equals(flavors[f])) { + f++; + } + return f < flavors.length; + } + @Override + public void lostOwnership(Clipboard clipboard, Transferable contents) { + image = null; + } + } + + protected void notifyListeners(String newModeId) + { + int i = 0; + EditorModeListener listener = null; + for (i = 0; i < mListenerVector.size(); i++) + { + listener = mListenerVector.elementAt(i); + listener.editorModeChanged(newModeId); + } + } + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mStartVertexController.setGraphModelManager(graphModelManager); + mDeletionController.setGraphModelManager(graphModelManager); + } + public void setGraphPanel(GraphPanel graphPanel) + { + graphPanel.addKeyListener(mDeletionController); + } + public void addEditorModeListener(EditorModeListener listener) + { + mListenerVector.add(listener); + } + public void removeEditorModeListener(EditorModeListener listener) + { + mListenerVector.remove(listener); + } + public void setGraphEditable(boolean editable) + { + mVertexModeButton.setEnabled(editable); + mEdgeModeButton.setEnabled(editable); + } + public EditorToolBar self() + { + return this; + } + @Override + public int print(Graphics g, PageFormat pf, int i) throws PrinterException + { + if (i >= 1) + { + return Printable.NO_SUCH_PAGE; + } + Graphics2D g2d = (Graphics2D) g; + double scalex = pf.getImageableWidth() / mGraphPanel.getWidth(); + double scaley = pf.getImageableHeight() / mGraphPanel.getHeight(); + double scale = Math.min(Math.min(scalex, scaley), 1); + g2d.translate(pf.getImageableX(), pf.getImageableY()); + g2d.scale(scale, scale); + mGraphPanel.printComponent(g2d); + return Printable.PAGE_EXISTS; + } +} diff --git a/src/main/java/com/c2kernel/graph/view/GraphPanel.java b/src/main/java/com/c2kernel/graph/view/GraphPanel.java new file mode 100644 index 0000000..012fe25 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/GraphPanel.java @@ -0,0 +1,272 @@ +package com.c2kernel.graph.view; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JPanel; + +import com.c2kernel.graph.event.EntireModelChangedEvent; +import com.c2kernel.graph.event.GraphModelResizedEvent; +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.ElasticBand; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Selection; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.utils.Resource; +public class GraphPanel extends JPanel implements Observer +{ + protected final Paint mSelectionPaint = Color.black; + protected final Paint mStartPaint = Color.green; + protected final Image mResizePadImg = Resource.findImage("graph/resizepad.gif").getImage(); + protected final BasicStroke mDashed = + new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 5.0f }, 0.0f); + protected GraphModelManager mGraphModelManager = null; + protected VertexRenderer mVertexRenderer = null; + protected DirectedEdgeRenderer mDirectedEdgeRenderer = null; + public GraphPanel(DirectedEdgeRenderer eRenderer, VertexRenderer vRenderer) + { + mVertexRenderer = vRenderer; + mDirectedEdgeRenderer = eRenderer; + // Request the keyboard focus if the mouse + // is pressed on the graph panel + addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent me) + { + requestFocus(); + } + }); + } + public void setGraphModelManager(GraphModelManager graphModelManager) + { + mGraphModelManager = graphModelManager; + } + @Override + public void update(Observable o, Object arg) + { + if (arg instanceof GraphModelResizedEvent || arg instanceof EntireModelChangedEvent) + { + setPreferredSize(new Dimension(mGraphModelManager.getModel().getWidth(), mGraphModelManager.getModel().getHeight())); + revalidate(); + } + repaint(); + } + @Override + public void paintComponent(Graphics g) + { + Graphics2D g2d = (Graphics2D) g; + DirectedEdge[] edges = null; + Vertex[] vertices = null; + Vertex startVertex = null; + Selection selection = null; + ElasticBand elasticBand = null; + Vertex newEdgeOriginVertex = null; + GraphPoint newEdgeOriginPoint = null; + Point newEdgeEndPoint = null; + GraphPoint vertexCentre = null; + int i = 0; + super.paintComponent(g); + if (mGraphModelManager != null) + { + // Get the edges and vertices from the model + edges = mGraphModelManager.getModel().getEdges(); + vertices = mGraphModelManager.getModel().getVertices(); + //graphable = mGraphModelManager.getModel(). + // Draw the edges + for (i = 0; i < edges.length; i++) + { + mDirectedEdgeRenderer.draw(g2d, edges[i]); + } + // Draw the vertices + for (i = 0; i < vertices.length; i++) + { + mVertexRenderer.draw(g2d, vertices[i]); + } + g2d.setPaint(mStartPaint); + // Highlight the start vertex if there is one + startVertex = mGraphModelManager.getModel().getStartVertex(); + if (startVertex != null) + { + drawVertexHighlight(g2d, startVertex, 1); + } + // Get the present selection + selection = mGraphModelManager.getModel().getSelection(); + g2d.setPaint(mSelectionPaint); + // Draw the outline of the selected + // vertices if there are any + if (selection.mVertices != null) + { + g2d.setStroke(mDashed); + for (i = 0; i < selection.mVertices.length; i++) + { + if (selection.mVertices[i] != mGraphModelManager.getModel().getContainingVertex()) + drawVertexHighlight(g2d, selection.mVertices[i], 5); + } + // Draw the resize pads if there is one and only one vertex selected + if (selection.mVertices.length == 1 && + selection.mVertices[0] != mGraphModelManager.getModel().getContainingVertex()) + { + vertexCentre = selection.mVertices[0].getCentrePoint(); + g2d.drawImage( + mResizePadImg, + vertexCentre.x + selection.mVertices[0].getWidth() / 2, + vertexCentre.y + selection.mVertices[0].getHeight() / 2, + this); + } + } + // Draw the outline of the selected + // edge if there is one + if (selection.mEdge != null) + { + drawEdgeHighlight(g2d, selection.mEdge); + } + // Get the elastic band + elasticBand = mGraphModelManager.getModel().getElasticBand(); + // Draw the elastic band if there + // is one + if (elasticBand != null) + { + g2d.drawLine( + elasticBand.mFixedCorner.x, + elasticBand.mFixedCorner.y, + elasticBand.mMovingCorner.x, + elasticBand.mFixedCorner.y); + g2d.drawLine( + elasticBand.mMovingCorner.x, + elasticBand.mFixedCorner.y, + elasticBand.mMovingCorner.x, + elasticBand.mMovingCorner.y); + g2d.drawLine( + elasticBand.mMovingCorner.x, + elasticBand.mMovingCorner.y, + elasticBand.mFixedCorner.x, + elasticBand.mMovingCorner.y); + g2d.drawLine( + elasticBand.mFixedCorner.x, + elasticBand.mMovingCorner.y, + elasticBand.mFixedCorner.x, + elasticBand.mFixedCorner.y); + } + // Draw the new edge under construction if there is one + newEdgeEndPoint = mGraphModelManager.getModel().getNewEdgeEndPoint(); + newEdgeOriginVertex = mGraphModelManager.getModel().getNewEdgeOriginVertex(); + if ((newEdgeEndPoint != null) && (newEdgeOriginVertex != null)) + { + newEdgeOriginPoint = newEdgeOriginVertex.getCentrePoint(); + g2d.setPaint(Color.black); + g2d.drawLine(newEdgeOriginPoint.x, newEdgeOriginPoint.y, newEdgeEndPoint.x, newEdgeEndPoint.y); + } + } + } + // Draws the highlight of the specified vertex the specified dist from its outline + protected void drawVertexHighlight(Graphics2D g2d, Vertex vertex, int dist) + { + GraphPoint[] outlinePoints = vertex.getOutlinePoints(); + GraphPoint centrePoint = vertex.getCentrePoint(); + int i = 0; + /* + * float dash1[] ={5.0f}; BasicStroke bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,10.0f, dash1,0.0f); + */ + for (i = 0; i < outlinePoints.length - 1; i++) + { + drawShiftedLine(dist, g2d, centrePoint, outlinePoints[i].x, outlinePoints[i].y, outlinePoints[i + 1].x, outlinePoints[i + 1].y); + } + drawShiftedLine( + dist, + g2d, + centrePoint, + outlinePoints[outlinePoints.length - 1].x, + outlinePoints[outlinePoints.length - 1].y, + outlinePoints[0].x, + outlinePoints[0].y); + } + // Draws the specifed line the specified distance away from the specified centre point + private static void drawShiftedLine(int dist, Graphics2D g2d, GraphPoint centrePoint, int x1, int y1, int x2, int y2) + { + if (x1 > centrePoint.x) + x1 += dist; + if (x1 < centrePoint.x) + x1 -= dist; + if (y1 > centrePoint.y) + y1 += dist; + if (y1 < centrePoint.y) + y1 -= dist; + if (x2 > centrePoint.x) + x2 += dist; + if (x2 < centrePoint.x) + x2 -= dist; + if (y2 > centrePoint.y) + y2 += dist; + if (y2 < centrePoint.y) + y2 -= dist; + g2d.drawLine(x1, y1, x2, y2); + } + // Draws the highlight of the specified edge + protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge) + { + GraphPoint originPoint = edge.getOriginPoint(); + GraphPoint terminusPoint = edge.getTerminusPoint(); + int midX = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + int midY = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + int minX = midX - 10; + int minY = midY - 10; + int maxX = midX + 10; + int maxY = midY + 10; + g2d.drawLine(minX, minY, maxX, minY); + g2d.drawLine(maxX, minY, maxX, maxY); + g2d.drawLine(maxX, maxY, minX, maxY); + g2d.drawLine(minX, maxY, minX, minY); + } + @Override + public void printComponent(Graphics g) + { + super.paintComponent(g); + Graphics2D g2d = (Graphics2D) g; + DirectedEdge[] edges = null; + Vertex[] vertices = null; + Vertex startVertex = null; + int i = 0; + g.setColor(Color.white); + g2d.fillRect(0,0,getWidth(),getHeight()); + if (mGraphModelManager != null) + { + // Get the edges and vertices from the model + edges = mGraphModelManager.getModel().getEdges(); + vertices = mGraphModelManager.getModel().getVertices(); + //graphable = mGraphModelManager.getModel(). + // Draw the edges + for (i = 0; i < edges.length; i++) + { + mDirectedEdgeRenderer.draw(g2d, edges[i]); + } + // Draw the vertices + for (i = 0; i < vertices.length; i++) + { + mVertexRenderer.draw(g2d, vertices[i]); + } + g2d.setPaint(mStartPaint); + // Highlight the start vertex if there is one + startVertex = mGraphModelManager.getModel().getStartVertex(); + if (startVertex != null) + { + drawVertexHighlight(g2d, startVertex, 1); + } + } + } + + protected void superPaint(Graphics g) + { + super.paintComponent(g); + } +} diff --git a/src/main/java/com/c2kernel/graph/view/PropertyTable.java b/src/main/java/com/c2kernel/graph/view/PropertyTable.java new file mode 100644 index 0000000..c1257aa --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/PropertyTable.java @@ -0,0 +1,40 @@ +package com.c2kernel.graph.view; + +import javax.swing.JTable; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; + + +public class PropertyTable extends JTable +{ + public PropertyTable(PropertyTableModel tableModel) + { + super(tableModel); + } + + + @Override + public TableCellRenderer getCellRenderer(int row, int column) { + + + return getDefaultRenderer(getCellClass(row, column)); + + } + + @Override +public TableCellEditor getCellEditor(int row, int column) { + + return getDefaultEditor(getCellClass(row, column)); + + } + + private Class getCellClass(int row, int column) { + Class cellClass = String.class; + + try { + cellClass = dataModel.getValueAt(row, column).getClass(); + } catch (NullPointerException ex) { } + + return cellClass; + } +} diff --git a/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java b/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java new file mode 100644 index 0000000..b1e69b1 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/PropertyTableModel.java @@ -0,0 +1,135 @@ +package com.c2kernel.graph.view; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; + +import javax.swing.JOptionPane; +import javax.swing.event.TableModelEvent; +import javax.swing.table.AbstractTableModel; + +import com.c2kernel.utils.Language; + +/************************************************************************** + * + * $Revision: 1.4 $ + * $Date: 2005/08/02 07:50:10 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class PropertyTableModel extends AbstractTableModel { + + private String[] mColumnNames = { Language.translate("Name"), Language.translate("Value") }; + HashMap sourceMap = new HashMap(); + ArrayList sortedNameList = new ArrayList(); + boolean isEditable = false; + + public PropertyTableModel() { + super(); + } + + @Override + public int getColumnCount() + { + return mColumnNames.length; + } + @Override + public String getColumnName(int col) + { + return mColumnNames[col]; + } + @Override + public int getRowCount() + { + synchronized (sourceMap) { + return sourceMap.size(); + } + } + @Override + public Object getValueAt(int rowIndex, int colIndex) + { + synchronized (sourceMap) { + String rowName = sortedNameList.get(rowIndex); + if (colIndex == 0) + return rowName; + else + return sourceMap.get(rowName); + } + } + + @Override + public void setValueAt(Object value, int rowIndex, int colIndex) + { + synchronized (sourceMap) { + if (colIndex == 0) return; + String rowName = sortedNameList.get(rowIndex); + Class oldElement = sourceMap.get(rowName).getClass(); + if (oldElement == Float.class && value.getClass() == String.class) + try { + value = Float.valueOf((String)value); + } catch (Exception ex) { } + if (value.getClass() != oldElement) + JOptionPane.showMessageDialog(null, "This property should contain a "+oldElement.getName()+" not a "+value.getClass().getName(), "Incorrect datatype", JOptionPane.ERROR_MESSAGE); + else { + sourceMap.put(rowName, value); + fireTableCellUpdated(rowIndex, colIndex); + } + } + } + + public void setMap(HashMap props) { + synchronized (sourceMap) { + sourceMap = props; + sortedNameList = new ArrayList(props.size()); + for (String string : props.keySet()) + sortedNameList.add(string); + + Collections.sort(sortedNameList, new Comparator() { + @Override + public int compare(String o1, String o2) { + return (o1.compareToIgnoreCase(o2)); + } + }); + } + fireTableChanged(new TableModelEvent(this)); + } + + @Override + public boolean isCellEditable(int row, int col) + { + return col==1 && isEditable; + } + + /** + * @return Returns the isEditable. + */ + public boolean isEditable() { + return isEditable; + } + /** + * @param isEditable The isEditable to set. + */ + public void setEditable(boolean isEditable) { + this.isEditable = isEditable; + } + + /** + * @param text + * @param object + */ + public void addProperty(String text, Object object) { + sourceMap.put(text,object); + setMap(sourceMap); + } + + /** + * @param object + */ + public void delProperty(Object propName) { + sourceMap.remove(propName); + setMap(sourceMap); + } +} diff --git a/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java b/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java new file mode 100644 index 0000000..966f527 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/SelectedVertexPanel.java @@ -0,0 +1,27 @@ +package com.c2kernel.graph.view; + +import javax.swing.JPanel; + +import com.c2kernel.graph.model.Vertex; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2005/05/12 10:12:52 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + + +public abstract class SelectedVertexPanel extends JPanel { + + public SelectedVertexPanel() { + super(); + } + + public abstract void select(Vertex vert); + + public abstract void clear(); +} diff --git a/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java b/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java new file mode 100644 index 0000000..4e3e711 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/VertexPropertyPanel.java @@ -0,0 +1,259 @@ +package com.c2kernel.graph.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +import com.c2kernel.graph.event.EntireModelChangedEvent; +import com.c2kernel.graph.event.SelectionChangedEvent; +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphableEdge; +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.gui.tabs.EntityTabPane; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.4 $ + * $Date: 2005/09/09 12:19:28 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class VertexPropertyPanel extends JPanel implements Observer, TableModelListener, ActionListener { + + private final PropertyTableModel mPropertyModel; + private final PropertyTable mPropertyTable; + private GraphModelManager mGraphModelManager; + private boolean isEditable = false; + GridBagLayout gridbag = new GridBagLayout(); + protected JLabel selObjName; + protected JLabel selObjClass; + JButton addPropButton; + JButton delPropButton; + Box newPropBox; + private JTextField newPropName; + private JComboBox newPropType; + String[] typeOptions = { "String", "Boolean", "Integer", "Float" }; + String[] typeInitVal = { "", "false", "0", "0.0"}; + SelectedVertexPanel mSelPanel; + + public VertexPropertyPanel() { + super(); + setLayout(gridbag); + mPropertyModel = new PropertyTableModel(); + mPropertyModel.addTableModelListener(this); + mPropertyTable = new PropertyTable(mPropertyModel); + } + + /** + * + */ + + @Override + public void update(Observable o, Object arg) { + Vertex[] selectedVertices = null; + DirectedEdge selectedEdge = null; + // If the selection has changed + if (arg instanceof SelectionChangedEvent) + { + SelectionChangedEvent event = (SelectionChangedEvent) arg; + selectedVertices = event.mSelection.mVertices; + if (selectedVertices != null) + { + if (selectedVertices.length == 1) + { + setVertex(selectedVertices[0]); + return; + } + } + selectedEdge = event.mSelection.mEdge; + if (selectedEdge != null) + { + setEdge(selectedEdge); + return; + } + } + if (arg instanceof SelectionChangedEvent || arg instanceof EntireModelChangedEvent){ + clear(); + } + } + + + @Override + public void tableChanged(TableModelEvent e) { + if (mGraphModelManager!=null) + mGraphModelManager.forceNotify(); + + } + + public void setVertex(Vertex vert) { + if (vert.getName().equals("domain")) + selObjName.setText("Domain Workflow"); + else + selObjName.setText(vert.getName()); + String className = vert.getClass().getName(); + selObjClass.setText(className.substring(className.lastIndexOf('.')+1)); + if (mSelPanel != null) mSelPanel.select(vert); + if (vert instanceof GraphableVertex) { + mPropertyModel.setMap(((GraphableVertex)vert).getProperties()); + addPropButton.setEnabled(isEditable); + delPropButton.setEnabled(isEditable); + } + } + + public void setEdge(DirectedEdge edge) { + selObjName.setText(edge.getName()); + String className = edge.getClass().getName(); + selObjClass.setText(className.substring(className.lastIndexOf('.')+1)); + if (edge instanceof GraphableEdge) { + mPropertyModel.setMap(((GraphableEdge)edge).getProperties()); + addPropButton.setEnabled(isEditable); + delPropButton.setEnabled(isEditable); + } + if (mSelPanel != null) mSelPanel.clear(); + } + + public void clear() { + selObjName.setText(""); + selObjClass.setText("Nothing Selected"); + mPropertyModel.setMap(new HashMap()); + if (mSelPanel != null) mSelPanel.clear(); + addPropButton.setEnabled(false); + delPropButton.setEnabled(false); + } + + /** + * @param isEditable The isEditable to set. + */ + public void setEditable(boolean editable) { + mPropertyModel.setEditable(editable); + isEditable = editable; + newPropBox.setVisible(editable); + } + + public void setGraphModelManager(GraphModelManager manager) { + mGraphModelManager = manager; + manager.addObserver(this); + } + + public void createLayout(SelectedVertexPanel selPanel) + { + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 0; + c.anchor = GridBagConstraints.NORTHWEST; + c.ipadx = 5; + c.ipady = 5; + + selObjName = new JLabel(); + selObjName.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(selObjName, c); + add(selObjName); + + c.gridy++; + selObjClass = new JLabel(); + gridbag.setConstraints(selObjClass, c); + add(selObjClass); + + c.gridy++; + JLabel title = new JLabel("Properties"); + title.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(title, c); + add(title); + + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.weighty = 2; + JScrollPane scroll = new JScrollPane(mPropertyTable); + gridbag.setConstraints(scroll, c); + add(scroll); + + newPropBox = Box.createHorizontalBox(); + newPropBox.add(new JLabel(Language.translate("New :"))); + newPropBox.add(Box.createHorizontalGlue()); + newPropName = new JTextField(15); + newPropBox.add(newPropName); + newPropType = new JComboBox(typeOptions); + newPropBox.add(newPropType); + newPropBox.add(Box.createHorizontalStrut(1)); + addPropButton = new JButton("Add"); + addPropButton.setMargin(new Insets(0, 0, 0, 0)); + delPropButton = new JButton("Del"); + delPropButton.setMargin(new Insets(0, 0, 0, 0)); + addPropButton.addActionListener(this); + delPropButton.addActionListener(this); + newPropBox.add(addPropButton); + newPropBox.add(delPropButton); + + c.gridy++; + c.weighty=0; + c.fill= GridBagConstraints.HORIZONTAL; + gridbag.setConstraints(newPropBox, c); + add(newPropBox); + + if (selPanel != null) { + c.gridy++; + mSelPanel = selPanel; + gridbag.setConstraints(mSelPanel, c); + add(mSelPanel); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == addPropButton) { + if (newPropName.getText().length() < 1) { + JOptionPane.showMessageDialog(this, "Enter a name for the new property", "Cannot add property", JOptionPane.ERROR_MESSAGE); + return; + } + if (mPropertyModel.sourceMap.containsKey(newPropName.getText())) { + JOptionPane.showMessageDialog(this, "Property '"+newPropName.getText()+"' already exists.", "Cannot add property", JOptionPane.ERROR_MESSAGE); + return; + } + if (mPropertyTable.getCellEditor() != null) + mPropertyTable.getCellEditor().stopCellEditing(); + + try { + Class newPropClass = Class.forName("java.lang."+typeOptions[newPropType.getSelectedIndex()]); + Class[] params = {String.class}; + Constructor init = newPropClass.getConstructor(params); + Object[] initParams = { typeInitVal[newPropType.getSelectedIndex()] }; + mPropertyModel.addProperty(newPropName.getText(), init.newInstance(initParams)); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + else if (e.getSource() == delPropButton) { + int selrow = mPropertyTable.getSelectedRow(); + if (selrow == -1) { + JOptionPane.showMessageDialog(this, "Select a property to remove", "Cannot delete property", JOptionPane.ERROR_MESSAGE); + return; + } + mPropertyModel.delProperty(mPropertyModel.sortedNameList.get(selrow)); + } + } +} diff --git a/src/main/java/com/c2kernel/graph/view/VertexRenderer.java b/src/main/java/com/c2kernel/graph/view/VertexRenderer.java new file mode 100644 index 0000000..1a8d263 --- /dev/null +++ b/src/main/java/com/c2kernel/graph/view/VertexRenderer.java @@ -0,0 +1,11 @@ +package com.c2kernel.graph.view; + +import java.awt.Graphics2D; + +import com.c2kernel.graph.model.Vertex; + + +public interface VertexRenderer +{ + public void draw(Graphics2D g2d, Vertex vertex); +} diff --git a/src/main/java/com/c2kernel/gui/Console.java b/src/main/java/com/c2kernel/gui/Console.java new file mode 100644 index 0000000..3427f82 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/Console.java @@ -0,0 +1,290 @@ +package com.c2kernel.gui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.io.BufferedReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.InterruptedIOException; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.Properties; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +/************************************************************************** + * + * $Revision: 1.10 $ + * $Date: 2005/10/05 07:39:37 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class Console extends JFrame { + JTextArea output; + JScrollPane scroll; + JTextField input; + JButton sendButton; + JButton toFileButton; + FileWriter logFile; + ConsoleConnection connection; + JFileChooser scriptLoader = new JFileChooser(); + static int bufferSize = Integer.parseInt(Gateway.getProperty("Console.bufferSize", "200")); + + public Console(String host, int port) { + super("Cristal Console - "+host); + GridBagLayout gridbag = new GridBagLayout(); + getContentPane().setLayout(gridbag); + output = new JTextArea("Type 'help' for help. . .\n"); + output.setEditable(false); + input = new JTextField(); + setSize(400, 600); + sendButton = new JButton("Send"); + sendButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + submit(); + } + }); + JButton clearButton = new JButton("Clear"); + clearButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + synchronized (output) { + output.setText(""); + } + } + }); + toFileButton = new JButton("Save"); + toFileButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (logFile == null) { + int returnValue = scriptLoader.showSaveDialog(null); + switch (returnValue) + { + case JFileChooser.APPROVE_OPTION : + try { + logFile = new FileWriter(scriptLoader.getSelectedFile()); + print ("Starting writing log to "+scriptLoader.getSelectedFile().getAbsolutePath()); + } catch (Exception ex) { + print(ex.getClass().getName()+": "+ex.getMessage()); + Logger.error(ex); + } + toFileButton.setText("Stop"); + case JFileChooser.CANCEL_OPTION : + case JFileChooser.ERROR_OPTION : + default : + } + } + else { + try { + logFile.close(); + } catch (Exception ex) { + logFile = null; + print(ex.getClass().getName()+": "+ex.getMessage()); + } + logFile = null; + toFileButton.setText("Save"); + } + } + }); + + + input.addKeyListener(new EnterListener(this)); + + scroll = new JScrollPane(output); + GridBagConstraints c = new GridBagConstraints(); + c.gridx=0; c.gridy=0; + c.fill=GridBagConstraints.BOTH; + c.weightx=1.0;c.weighty=1.0; + gridbag.setConstraints(scroll, c); + getContentPane().add(scroll); + + Box inputBox = Box.createHorizontalBox(); + inputBox.add(input); + inputBox.add(Box.createHorizontalStrut(5)); + inputBox.add(sendButton); + inputBox.add(clearButton); + inputBox.add(toFileButton); + c.gridy=1; c.fill=GridBagConstraints.HORIZONTAL; + c.weighty=0; + gridbag.setConstraints(inputBox, c); + getContentPane().add(inputBox); + + try { + // TODO: merge module script utilities together and prepend with namespace + Properties utilProps = FileStringUtility.loadConfigFile( Resource.findTextResource("ScriptUtils.conf") ); + + Box utilBox = Box.createHorizontalBox(); + for (Object name2 : utilProps.keySet()) { + String name = (String) name2; + String value = utilProps.getProperty(name); + JButton newUtil = new JButton(name); + newUtil.setActionCommand(value); + newUtil.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + processUtil(e.getActionCommand()); + } + }); + utilBox.add(newUtil); + utilBox.add(Box.createHorizontalStrut(5)); + } + + c.gridy++; + gridbag.setConstraints(utilBox, c); + getContentPane().add(utilBox); + } catch (Exception ex) { // no domain utils + } + + + validate(); + connection = new ConsoleConnection(host, port, this); + new Thread(connection).start(); + addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent evt) { + if (connection!=null) connection.shutdown(); + dispose(); + } + }); + } + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) input.requestFocus(); + } + + public void processUtil(String command) { + int replace; + String text = input.getText(); + while ((replace = command.indexOf("%s")) > -1) { + command = command.substring(0, replace)+text+command.substring(replace+2); + } + connection.sendCommand(command); + } + + public void submit() { + connection.sendCommand(input.getText()); + input.setText(""); + } + + public void print(String line) { + synchronized (output) { + String currentText = output.getText()+line+"\n"; + while (output.getLineCount() > bufferSize) { + currentText = currentText.substring(currentText.indexOf("\n")+1); + output.setText(currentText); + } + output.setText(currentText); + output.setCaretPosition(output.getText().length()); + if (logFile != null) try { + logFile.write(line+"\n"); + } catch (IOException ex) { + logFile = null; + print("Error writing to file."); + } + } + } + + @Override + public void disable() { + synchronized (output) { + output.append("Lost connection"); + } + output.setEnabled(false); + input.setEnabled(false); + sendButton.setEnabled(false); + } + + private class EnterListener extends KeyAdapter + { + Console parent; + public EnterListener(Console parent) { + this.parent = parent; + } + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode()==10) { + parent.submit(); + } + } + }; + + private class ConsoleConnection implements Runnable { + String host; int port; Console parent; boolean keepConnected = true; + Socket conn; PrintWriter consoleOutput; BufferedReader consoleInput; + + + public ConsoleConnection(String host, int port, Console parent) { + Thread.currentThread().setName("Console Client to "+host+":"+port); + this.host = host; + this.port = port; + this.parent = parent; + } + + @Override + public void run() { + connect(); + while (keepConnected) { + try { + String line = consoleInput.readLine(); + if (line == null) { + parent.disable(); + keepConnected = false; + } + else + parent.print(line); + } catch (InterruptedIOException ex) { // timeout - ignore + } catch (IOException ex) { // error reading + parent.disable(); + keepConnected = false; + } + } + + try { + conn.close(); + } catch (IOException ex) { } + } + + public void sendCommand(String command) { + consoleOutput.println(command); + } + + public void shutdown() { + keepConnected = false; + } + + public void connect() { + parent.print("Connecting to "+host+":"+port); + try { + conn = new Socket(host, port); + conn.setKeepAlive(true); + conn.setSoTimeout(500); + consoleOutput = new PrintWriter(conn.getOutputStream(), true); + consoleInput = new BufferedReader(new InputStreamReader(conn.getInputStream())); + } catch (Exception ex) { + + } + } + } +} diff --git a/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java b/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java new file mode 100644 index 0000000..18847cc --- /dev/null +++ b/src/main/java/com/c2kernel/gui/DomainKeyConsumer.java @@ -0,0 +1,16 @@ +package com.c2kernel.gui; + +import com.c2kernel.lookup.DomainPath; + +/** + * Things that can be told when a barcode etc is entered + * @version $Revision: 1.2 $ $Date: 2003/03/13 16:42:38 $ + * @author $Author: abranson $ + */ + +public interface DomainKeyConsumer { + public void push(DomainPath key); + + public void push(String name); + +} diff --git a/src/main/java/com/c2kernel/gui/DomainKeyListener.java b/src/main/java/com/c2kernel/gui/DomainKeyListener.java new file mode 100644 index 0000000..df18e72 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/DomainKeyListener.java @@ -0,0 +1,27 @@ +package com.c2kernel.gui; + +import java.io.IOException; + +import javax.swing.ImageIcon; + +/** + * Interface for external key input classes (e.g. barcode scanner) + * @version $Revision: 1.5 $ $Date: 2004/10/20 14:10:21 $ + * @author $Author: abranson $ + */ + +public interface DomainKeyListener { + public void init(); + + public boolean enable() throws IOException; + + public void setConsumer(EntityFinder consumer); + + public void disable(); + + // return 25x25 icon for enable/disable button + public ImageIcon getIcon(); + + // tooltip for the button + public String getDescription(); +} diff --git a/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java b/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java new file mode 100644 index 0000000..050a76a --- /dev/null +++ b/src/main/java/com/c2kernel/gui/DynamicTreeBuilder.java @@ -0,0 +1,183 @@ +package com.c2kernel.gui; + +import javax.swing.ImageIcon; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import com.c2kernel.gui.data.Node; +import com.c2kernel.gui.data.NodeItem; +import com.c2kernel.gui.data.NodeSubscriber; +import com.c2kernel.lookup.Path; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +/** + * Installed as the user object on a single child node of a new node known to be composite. + *

Shows 'Loading . . .' when the branch is opened, but a TreeExpansionListener attempts to fire this thread off in the first child node. + *
When started, this thread will retrieve all of the real child nodes and add them to its parent while removing itself (hopefully for garbage collection) + * + * @version $Revision: 1.24 $ $Date: 2004/12/15 12:12:06 $ + * @author $Author: abranson $ + */ + +public class DynamicTreeBuilder implements NodeSubscriber { + private DefaultTreeModel treeModel; + private final DefaultMutableTreeNode parent; + public short state = IDLE; + public static final short IDLE = 0; + public static final short LOADING = 1; + public static final short PARTIAL = 2; + public static final short FINISHED = 3; + private final DefaultMutableTreeNode loading; + private static ImageIcon loadIcon = Resource.findImage("loading.gif"); + private static ImageIcon pauseIcon = Resource.findImage("reload.gif"); + + /** + * The newly created DynamicTreeBuilder records its parent node - the one for which it will build child nodes for. + * @param nodeClicked The Parent Tree Node that will be populated. + * @see NodeItem + * @see TreeDisplay*/ + public DynamicTreeBuilder(DefaultMutableTreeNode parent) { + this.parent = parent; + loading = new DefaultMutableTreeNode(this); + } + + /** + * Before the tree builder can execute, it needs to be given references to the tree and NodeFactory needed to create the new nodes. + * @param myNodeFactory The NodeFactory that can be queried for new NodeItems. + * @param parentTree The JTree in which this node is currently contained. + */ + public void buildInfo(JTree parentTree) { + this.treeModel = (DefaultTreeModel)parentTree.getModel(); + } + + public void start() { + // find the clicked tree node + Node parentNode = (Node)parent.getUserObject(); + Logger.msg(2, "DynamicTreeBuilder.start() - Filling in children of '"+parentNode.toString()+"'"); + if (state == IDLE) + parentNode.subscribeNode(this); + else + parentNode.loadMore(); + state = LOADING; + } + + /** + * Used by the JTree to find the text representation of the node. + */ + @Override + public String toString() { + switch (state) { + case IDLE: + return Language.translate("Initializing Tree Node Loader"); + case LOADING: + return Language.translate("Loading . . ."); + case PARTIAL: + return Language.translate("Double-click to load more"); + case FINISHED: + return Language.translate("Done"); + default: + return ""; + } + + } + + public ImageIcon getIcon() { + if (state == LOADING) + return loadIcon; + else + return pauseIcon; + } + + public DefaultMutableTreeNode getTreeNode() { + return loading; + } + + @Override + public void add(Node newNode) { + Logger.msg(2, "DynamicTreeBuilder.add() - Received item for tree. Name: "+newNode); + + // have we inserted the node yet? + SwingUtilities.invokeLater(new TreeAddThread(newNode)); + } + + class TreeAddThread implements Runnable { + Node newNode; + TreeAddThread(Node newNode) { + this.newNode = newNode; + } + @Override + public void run() { + boolean inserted = false; + DefaultMutableTreeNode newTreeNode = newNode.getTreeNode(); + // loop though all children unless we have done the insertion + for (int i=0; i= 0) { + // if the next string is 'greater than' ours, insert the node before + treeModel.insertNodeInto(newTreeNode, parent, i); + inserted = true; + break; + } + + } + // if we haven't inserted yet, it must go at the end. + + if (!inserted) + treeModel.insertNodeInto(newTreeNode, parent, parent.getChildCount()); + } + + } + + class TreeRemoveThread implements Runnable { + DefaultMutableTreeNode oldNode; + TreeRemoveThread(DefaultMutableTreeNode oldNode) { + this.oldNode = oldNode; + } + + @Override + public void run() { + treeModel.removeNodeFromParent(oldNode); + } + } + + @Override + public void end(boolean more) { + if (more) { + state = PARTIAL; + } + else { + state = FINISHED; + synchronized(treeModel) { + if (loading.getParent() != null) + SwingUtilities.invokeLater(new TreeRemoveThread(loading)); + } + } + } + + @Override + public void remove(Path path) { + synchronized (treeModel) { + for (int i=0; i childPanes = new HashMap(); + protected String startTab; + protected String startCommand = null; + protected boolean initialized = false; + + public EntityDetails(NodeEntity thisItem) { + super(); + startTab = MainFrame.getPref("DefaultStartTab", "Properties"); + myEntity = thisItem; + } + + @Override + public void run() { + Thread.currentThread().setName("Entity Pane Builder"); + EntityTabPane componentToAdd = null; + setLayout(new BorderLayout()); + itemTitlePanel = getItemTitlePanel(); + add(itemTitlePanel, BorderLayout.NORTH); + add(myTabbedPane); + + // decide which tabs to create + ArrayList requiredTabs = myEntity.getTabs(); + + for (Object name2 : requiredTabs) { + String tabName = (String)name2; + if (tabName != null) { + //create class instances and initialise + Class myClass = null; + //look up the required TabbedPane + try { + myClass = Class.forName(this.getClass().getPackage().getName() + ".tabs." + tabName + "Pane"); + Logger.msg(2, "ItemDetails. - Creating ItemTabPane instance: " + + this.getClass().getPackage().getName() + ".tabs." + tabName + "Pane"); + componentToAdd = (EntityTabPane)myClass.newInstance(); + } catch (ClassNotFoundException e) { + Logger.msg(2, "ItemDetails. - No specialist tab found for " + tabName + ". Using default."); + } catch (InstantiationException e) { + Logger.msg(0, "ItemDetails. - Instantiation Error! " + e); + } catch (IllegalAccessException e) { + Logger.msg(0, "ItemDetails. - Illegal Method Access Error! Class was probably not a ItemTabPane: " + e); + } + if (componentToAdd == null) componentToAdd = new EntityTabPane(tabName, null); + componentToAdd.setParent(this); + + //adds the component to the panel + childPanes.put(componentToAdd, new Boolean(false)); + + int placement = myTabbedPane.getTabCount(); + if (tabName.equals("Properties")) // must be first + placement = 0; + myTabbedPane.insertTab(componentToAdd.getTabName(), null, componentToAdd, null, placement); + } + } + initialized = true; + if (!(requiredTabs.contains(startTab))) { + startTab = "Properties"; + startCommand = null; + } + runCommand(Language.translate(startTab), startCommand); + myTabbedPane.setVisible(true); + myTabbedPane.addChangeListener(this); + validate(); + + } + + @Override + public void stateChanged(javax.swing.event.ChangeEvent p1) { + initialisePane((EntityTabPane)myTabbedPane.getSelectedComponent()); + } + + public void initialisePane(EntityTabPane pane) { + Boolean isInit = childPanes.get(pane); + if (isInit.booleanValue() == false) { + Logger.msg(4,"Initialising "+pane.getTabName()); + pane.initForEntity(myEntity); + childPanes.put(pane, new Boolean(true)); + validate(); + } + } + + public EntityTabManager getDesktopManager() { + return desktopManager; + } + + public void setDesktopManager(EntityTabManager newDesktopManager) { + desktopManager = newDesktopManager; + } + + public JPanel getItemTitlePanel() { + JPanel titlePanel = new JPanel(); + JComponent current; + // Use gridbag layout for title + GridBagLayout gridbag = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + titlePanel.setLayout(gridbag); + // Place Item Icon + c.gridx = 0; + c.gridy = 0; + c.gridheight = GridBagConstraints.REMAINDER; + c.anchor = GridBagConstraints.NORTH; + c.ipadx = 5; + c.ipady = 5; + current = new JLabel(Resource.findImage("typeicons/"+myEntity.getIconName()+"_32.png")); + gridbag.setConstraints(current, c); + titlePanel.add(current); + // Place Name/ID Label + current = new JLabel(myEntity.getName() + " (" + myEntity.getSysKey() + ")"); + c.gridx = 1; c.gridy = 0; c.gridheight = 1; + c.anchor = GridBagConstraints.NORTH; c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1.0; c.ipadx = 2; c.ipady = 2; + current.setFont(new Font("Helvetica", Font.PLAIN, 18)); + gridbag.setConstraints(current, c); + titlePanel.add(current); + // Place Type Label + current = new JLabel(myEntity.getType()); + c.gridx = 1; c.gridy = 2; c.gridheight = 1; + c.anchor = GridBagConstraints.CENTER; c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1.0; + current.setFont(new Font("Helvetica", Font.PLAIN, 12)); + gridbag.setConstraints(current, c); + titlePanel.add(current); + return titlePanel; + } + + public void discardTabs() { + myTabbedPane.removeChangeListener(this); + myTabbedPane.removeAll(); + for (Iterator iter = childPanes.keySet().iterator(); iter.hasNext();) { + EntityTabPane element = iter.next(); + element.destroy(); + iter.remove(); + } + } + + public int getSysKey() + { + return myEntity.getSysKey(); + } + + public void closeTab() { + desktopManager.remove(myEntity.getSysKey()); + Logger.msg(5,"Remove master Tab :"+myEntity.getType()+ " SysKey "+myEntity.getSysKey()); + myEntity.getEntity().dumpSubscriptions(0); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("close")) + closeTab(); + } + + public void runCommand(String tab, String command) { + if (initialized) { + int tabIndex = findTab(tab); + Logger.msg(3, "Running command "+tab+" "+command+" ("+tabIndex+")"); + if (tabIndex == -1) { + Logger.error("Tab "+tab+" not found for command "+command); + return; + } + EntityTabPane startPane = (EntityTabPane)myTabbedPane.getComponentAt(tabIndex); + myTabbedPane.setSelectedIndex(tabIndex); + initialisePane(startPane); + if (command!= null) startPane.runCommand(command); + } + else + { + Logger.msg(3, "Storing command "+tab+" "+command+" until initialised."); + startTab = tab; + startCommand = command; + } + } + + protected int findTab(String tabName) { + for (int i=0; i< myTabbedPane.getTabCount(); i++) { + EntityTabPane thisPane = (EntityTabPane)myTabbedPane.getComponentAt(i); + if (thisPane.getTabName().equals(tabName)) + return i; + } + return -1; + } + + + public void refresh() + { + } + /** + * + */ + @Override + protected void finalize() throws Throwable { + Logger.msg(7, "EntityDetails "+myEntity.getSysKey()+" reaped"); + super.finalize(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/gui/EntityFinder.java b/src/main/java/com/c2kernel/gui/EntityFinder.java new file mode 100644 index 0000000..0d53545 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/EntityFinder.java @@ -0,0 +1,217 @@ +package com.c2kernel.gui; + +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.IOException; +import java.util.Enumeration; +import java.util.StringTokenizer; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JTextField; +import javax.swing.JToggleButton; + +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.lookup.Path; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +public class EntityFinder extends Box implements Runnable { + JTextField inputField; + JButton findButton; + JButton findNextButton; + GridBagLayout gridbag = new GridBagLayout(); + LDAPLookup lookup = Gateway.getLDAPLookup(); + DomainKeyConsumer defaultConsumer = null; + DomainKeyConsumer currentConsumer = null; + Enumeration matches; + Path rootNode = MainFrame.userNode.getPath(); + + static protected ImageIcon mFindIcon = null; + static protected ImageIcon mNextIcon = null; + static { + try + { + mNextIcon =Resource.findImage("next.png"); + mFindIcon =Resource.findImage("find.png"); + } + catch (Exception e) + { + Logger.error("Couldn't load images: " + e); + } + } + + public EntityFinder() { + super(BoxLayout.X_AXIS); + initPanel(); + } + + public void pushNewKey(String key) { + inputField.setText(key); + runSearch(); + } + + public void setDefaultConsumer(DomainKeyConsumer newConsumer) { + defaultConsumer = newConsumer; + currentConsumer = newConsumer; + } + + public void setConsumer(DomainKeyConsumer newConsumer, String label) { + currentConsumer = newConsumer; + findButton.setText(label); + } + + public void clearConsumer(DomainKeyConsumer oldConsumer) { + if (currentConsumer == oldConsumer) { + currentConsumer = defaultConsumer; + findButton.setText(""); + } + } + + private void initPanel() { + + JLabel search = new JLabel(" "+Language.translate("Search")+":"); + add(search); + add(Box.createHorizontalStrut(7)); + + inputField = new JTextField(20); + add(inputField); + add(Box.createHorizontalStrut(5)); + inputField.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + pushNewKey(inputField.getText()); + } + }); + + findButton = new JButton(mFindIcon);//(Language.translate("Find")); + findButton.setMargin(new Insets(2, 5, 2, 5)); + findButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + pushNewKey(inputField.getText()); + } + }); + add(findButton); + add(Box.createHorizontalStrut(5)); + + findNextButton = new JButton(mNextIcon);//(Language.translate("Next")); + findNextButton.setMargin(new Insets(2, 5, 2, 5)); + findNextButton.addActionListener( new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + MainFrame.status.setText("Navigating to next match"); + nextMatch(); + } + }); + findNextButton.setEnabled(false); + add(findNextButton); + add(Box.createHorizontalStrut(15)); + + // create plugins + Logger.msg(6, "ItemFinder() - creating plugins"); + String requiredListeners = Gateway.getProperty("DomainKeyListeners"); + if (requiredListeners != null) { + StringTokenizer tok = new StringTokenizer(requiredListeners, ","); + while (tok.hasMoreTokens()) { + String listenerName = tok.nextToken(); + Logger.msg(6, "ItemFinder() - creating a " + listenerName); + try { + Class listenerClass = Class.forName(listenerName); + DomainKeyListener newListener = (DomainKeyListener)listenerClass.newInstance(); + newListener.init(); newListener.setConsumer(this); + JToggleButton listenerButton = new JToggleButton(newListener.getIcon(), false); + listenerButton.addItemListener(new ListenerButtonListener(newListener, listenerButton)); + listenerButton.setMargin(new Insets(0, 2, 0, 2)); + listenerButton.setToolTipText("Enable "+newListener.getDescription()); + add(listenerButton); + add(Box.createHorizontalStrut(7)); + } catch (Exception e) { + Logger.error("ItemFinder() - could not create a "+listenerName+": "+e); + } + } + add(Box.createHorizontalGlue()); + } + } + + private void runSearch() { + Thread searcher = new Thread(this); + searcher.start(); + } + + @Override + public void run() { + Thread.currentThread().setName("Entity Search"); + MainFrame.status.setText("Searching. Please Wait"); + findButton.setEnabled(false); findNextButton.setEnabled(false); + String searchTerm = inputField.getText(); + if (searchTerm.length() == 0) return; // don't allow null searches + findNextButton.setEnabled(false); + matches = lookup.search(rootNode,inputField.getText()); + if (!matches.hasMoreElements()) { + MainFrame.status.setText("No results"); + currentConsumer.push(searchTerm); // for subscribers who don't care if it exists + findButton.setEnabled(true); + return; + } + MainFrame.status.setText("Selecting first match."); + nextMatch(); + + } + + void nextMatch() { + findButton.setEnabled(false); findNextButton.setEnabled(false); + DomainPath nextMatch = (DomainPath)matches.nextElement(); + try + { + currentConsumer.push(nextMatch); + } + catch (NullPointerException e) + { + //case the item searched is not found ! + } + findButton.setEnabled(true); + findNextButton.setToolTipText("Click to show next match"); + if (matches.hasMoreElements()) findNextButton.setEnabled(true); + } + + private class ListenerButtonListener implements ItemListener { + private final DomainKeyListener listener; + private final JToggleButton listenerButton; + + public ListenerButtonListener(DomainKeyListener newListener, JToggleButton listenerButton) { + this.listener = newListener; + this.listenerButton = listenerButton; + } + + @Override + public void itemStateChanged(ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + // Switch on + try { + if (!(listener.enable())) listenerButton.doClick(); // allow plugins to disable themselves + } catch (IOException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "Error initialising "+listener.getDescription(), JOptionPane.ERROR_MESSAGE); + listenerButton.doClick(); + } + listenerButton.setToolTipText("Disable "+listener.getDescription()); + } else { + // Switch off + listener.disable(); + listenerButton.setToolTipText("Enable "+listener.getDescription()); + } + } + } + +} diff --git a/src/main/java/com/c2kernel/gui/EntityTabManager.java b/src/main/java/com/c2kernel/gui/EntityTabManager.java new file mode 100644 index 0000000..b465570 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/EntityTabManager.java @@ -0,0 +1,86 @@ +package com.c2kernel.gui; +import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; + +import com.c2kernel.gui.data.NodeEntity; +import com.c2kernel.gui.tabs.JTabbedPaneWithCloseIcons; +import com.c2kernel.utils.Logger; + +/** + * Keeps + * + * @version $Revision: 1.12 $ $Date: 2005/09/12 14:56:19 $ + * @author $Author: abranson $ + */ + +public class EntityTabManager extends JPanel +{ + private MainFrame mMainframe; + + protected HashMap openItems = new HashMap(); + protected JTabbedPaneWithCloseIcons tabbedPane = new JTabbedPaneWithCloseIcons(); + //JTabbedPane tabbedPane = new JTabbedPane(); + MenuBuilder myMenuBuilder; + + + public EntityTabManager() { + super(); + setLayout(new GridLayout(1,1)); + setBorder(BorderFactory.createLoweredBevelBorder()); + //UIDefaults ui = UIManager.getDefaults(); + //ui.put("TabbedPane.selected",Color.red); + add(tabbedPane); + } + + public EntityDetails add(NodeEntity thisEntity) { + + EntityDetails requestedDetails; + if (!openItems.containsKey(new Integer(thisEntity.getSysKey()))) { + Logger.msg(1, "ItemWindowManager.add() - Window for syskey "+thisEntity.getSysKey()+" not found. Opening new one."); + requestedDetails = new EntityDetails(thisEntity); + Thread itemLoader = new Thread(requestedDetails); + itemLoader.start(); + openItems.put(new Integer(thisEntity.getSysKey()), requestedDetails); + requestedDetails.setDesktopManager(this); + + // get currently selected item to set location + tabbedPane.addTab(thisEntity.getName(), thisEntity.getIcon(), requestedDetails, Integer.toString(thisEntity.getSysKey())); + + + } + else { //opened window but different nodeitem + requestedDetails = openItems.get(new Integer(thisEntity.getSysKey())); + } + tabbedPane.setSelectedComponent(requestedDetails); + return requestedDetails; + } + + public void setMenuBuilder(MenuBuilder myMenuBuilder) { + this.myMenuBuilder = myMenuBuilder; + } + + @Override + public void remove(int sysKey) { + Integer sysKeyObj = new Integer(sysKey); + if (!openItems.containsKey(sysKeyObj)) return; + EntityDetails tabToClose = openItems.get(sysKeyObj); + tabbedPane.remove(tabToClose); + tabToClose.discardTabs(); + openItems.remove(sysKeyObj); + } + + public void closeAll(boolean keepOpen) { + ArrayList toRemove = new ArrayList(); + for (Integer element : openItems.keySet()) { + if (keepOpen && openItems.get(element).equals(tabbedPane.getSelectedComponent())) continue; + toRemove.add(element); + } + for (Integer element : toRemove) { + remove(element.intValue()); + } + } +} diff --git a/src/main/java/com/c2kernel/gui/LoginBox.java b/src/main/java/com/c2kernel/gui/LoginBox.java new file mode 100644 index 0000000..aee469f --- /dev/null +++ b/src/main/java/com/c2kernel/gui/LoginBox.java @@ -0,0 +1,327 @@ +package com.c2kernel.gui; + +/** + *

Title:

+ *

Description:

+ *

Copyright: Copyright (c) 2003

+ *

Company:

+ * @author not attributable + * @version 1.0 + */ +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.border.EmptyBorder; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.entity.proxy.AgentProxy; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + + +//import com.borland.jbcl.layout.*; + +/** + *

Title:

+ *

Description:

+ *

Copyright: Copyright (c) 2003

+ *

Company:

+ * @author not attributable + * @version 1.0 + */ + +public class LoginBox extends JFrame { + private final int xMov; + private final int yMov; + public String errorMessage=new String(""); + private int maxNumberLogon; + public boolean action = false; + public int loginAttemptNumber= 0; + JLabel passwordLabel = new JLabel(); + JTextField username = new JTextField(); + JButton OK = new JButton(); + JLabel errorLabel = new JLabel(); + JPasswordField password = new JPasswordField(); + JButton Cancel = new JButton(); + JLabel userLabel = new JLabel(); + ImageIcon imageMainHolder = new ImageIcon(); + JLabel pictureLabel = new JLabel(); + GridBagLayout gridBagLayout1 = new GridBagLayout(); + MainFrame mainFrameFather; + public static AgentProxy userAgent; + private boolean logged; + private boolean errorSet; + + public LoginBox(int attempt,String title,String lastUser,String bottomMessage, + javax.swing.ImageIcon imageHolder,MainFrame mainFrame) { + String iconFile = Gateway.getProperty("AppIcon"); + if (iconFile != null) + this.setIconImage(Resource.findImage(iconFile).getImage()); + this.errorLabel.setText(bottomMessage); + if (errorMessage.compareTo("")!=0) this.errorLabel.setText(errorMessage); + mainFrameFather=mainFrame; + xMov=imageHolder.getIconWidth()+90; + yMov=imageHolder.getIconHeight()+40; + imageMainHolder=imageHolder; + try { + jbInit(); + } + catch(Exception e) { + e.printStackTrace(); + } + if (attempt==0) maxNumberLogon=5; + else maxNumberLogon=attempt; + if (title == null) + title = "Cristal2"; + title = Language.translate("Log in to ")+title; + setTitle(title); + username.setText(lastUser); + + } +//OK button pressed OR Enter Hit + private void loginClicked(){ + errorSet=false; + try { + if (this.getUser().length()>0 && this.getPassword().length()>0) + userAgent = Gateway.connect(this.getUser(), this.getPassword()); + logged = (userAgent != null); + Logger.msg(7, "AbstractMain::standardSetUp() - Gateway.connect() OK."); + } + catch (InvalidDataException ex) { + String message = ex.getMessage(); + int i = ex.getMessage().indexOf(' '); + if (i > -1 ) message = message.substring(i); + //Here us elanguage translate I guess :) + //if (message.length()>65 && message.substring(1,5).compareTo("User")==0) + // message = (message.substring(1,50)+ "... not found" ); + this.errorLabel.setText(message); + logged= false; + errorSet=true; + } + if (!logged) { + Logger.msg("Login attempt "+loginAttemptNumber+" of "+maxNumberLogon+" failed"); + if (loginAttemptNumber>=maxNumberLogon) Logger.die("Login failure limit reached"); + if (!errorSet) this.errorLabel.setText(Language.translate("Please enter username & password")); +// int posx=xMov+120; +// int posy=yMov; +// if (posy<135) posy=135; +// float texstSize = errorLabel.getFont().getSize2D(); +// if (posx-xMov pluginClass = Class.forName(pluginName); + Executor domainExecutor = (Executor)pluginClass.newInstance(); + plugins.addItem(domainExecutor); + } catch (Exception ex) { + Logger.error("Could not load the executor plugin "+pluginName); + } + } + } + return plugins; + } + protected JSplitPane getSplitPanel() + { + // create the split pane, and add the Tree to it. + if (splitPane == null) + { + splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, treeBrowser, myDesktopManager); + splitPane.setDividerSize(5); + splitPanePos = Integer.parseInt(getPref("SplitPanePosition", "200")); + getSplitPanel().setDividerLocation(splitPanePos); + } + return splitPane; + } + +} diff --git a/src/main/java/com/c2kernel/gui/MenuBuilder.java b/src/main/java/com/c2kernel/gui/MenuBuilder.java new file mode 100644 index 0000000..255e7c1 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/MenuBuilder.java @@ -0,0 +1,281 @@ +package com.c2kernel.gui; +import java.awt.Dimension; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import java.util.Enumeration; +import java.util.HashMap; + +import javax.swing.Box; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JDialog; +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.html.HTMLEditorKit; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +/** + * @version $Revision: 1.47 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ +public class MenuBuilder extends JMenuBar implements ActionListener, ItemListener, HyperlinkListener +{ + + protected UIManager.LookAndFeelInfo[] availableViews = UIManager.getInstalledLookAndFeels(); + protected MainFrame myParentFrame; + protected JMenu fileMenu; + protected JMenu consoleMenu; + protected JMenu styleMenu; + protected JMenu prefMenu; + protected JMenu helpMenu; + protected HashMap availableMenus = new HashMap(); + + public MenuBuilder() + {} + + /** Creates new DynamicMenuBuilder */ + public MenuBuilder(MainFrame parentFrame) + { + myParentFrame = parentFrame; + fileMenu = new JMenu(Language.translate("File")); + consoleMenu = new JMenu(Language.translate("Console")); + styleMenu = new JMenu(Language.translate("Style")); + prefMenu = new JMenu("Preferences"); + helpMenu = new JMenu(Language.translate("Help")); + availableMenus.put("file", fileMenu); + availableMenus.put("console", consoleMenu); + availableMenus.put("preferences", prefMenu); + availableMenus.put("style", styleMenu); + availableMenus.put("help", helpMenu); + + addMenuItem(Language.translate("Close All"), "file", null, 0); + addMenuItem(Language.translate("Close Others"), "file", null, 0); + fileMenu.insertSeparator(2); + addMenuItem(Language.translate("Exit"), "file", null, 0); + + addMenuItem(Language.translate("Local console"), "console", null, 0); + consoleMenu.insertSeparator(5); + addServerConsoles(); + + ButtonGroup styleButtonGroup = new ButtonGroup(); + for (LookAndFeelInfo availableView : availableViews) + addMenuItem(availableView.getName(), "style", styleButtonGroup, 0); + + addMenuItem(Language.translate("Tree Browser"), "preferences", null, MainFrame.getPref("ShowTree", "true").equals("true")?2:1); + addMenuItem(Language.translate("Outcome Field Help"), "preferences", null, MainFrame.getPref("ShowHelp", "true").equals("true")?2:1); + addMenuItem(Language.translate("Graph Properties"), "preferences", null, MainFrame.getPref("ShowProps", "true").equals("true")?2:1); + addMenuItem(Language.translate("About"), "help", null, 0); + + add(fileMenu); + add(consoleMenu); + add(styleMenu); + add(prefMenu); + add(helpMenu); + } + /** + * + */ + private void addServerConsoles() { + Enumeration servers = Gateway.getLDAPLookup().searchEntities(new DomainPath("/servers")); + while(servers.hasMoreElements()) { + Path thisServerPath = (Path)servers.nextElement(); + try { + int syskey = thisServerPath.getSysKey(); + String serverName = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/Name", null)).getValue(); + String portStr = ((Property)Gateway.getStorage().get(syskey, ClusterStorage.PROPERTY+"/ConsolePort", null)).getValue(); + addMenuItem(serverName+":"+portStr, "console", null, 0); + } catch (Exception ex) { + Logger.error("Exception retrieving proxy server connection data for "+thisServerPath); + Logger.error(ex); + } + } + + } + + /** + * Adds a menu item to a menu. Adds an action listener to the menu item. + */ + public void addMenuItem(String itemName, String menuName, ButtonGroup bg, int checkBox) + { + //checks to see if the menu to add the item to exists + if (availableMenus.containsKey(menuName)) + { + JMenuItem myItem = new JMenuItem(itemName); + if (bg != null) + { + //if the menu item equals the current style, set it selected + myItem = new JRadioButtonMenuItem(itemName, UIManager.getLookAndFeel().getName().equals(itemName)); + bg.add(myItem); + } + if (checkBox != 0) + { + myItem = new JCheckBoxMenuItem(itemName, checkBox == 2); + } + myItem.addActionListener(this); + JMenu myMenu = availableMenus.get(menuName); + myMenu.add(myItem); + } + } + //checks to see if the event dispatched is one of the + //styles that belong to the UIManager + public int isStyleChange(String style) + { + for (int i = 0; i < availableViews.length; i++) + { + if (style.equals(availableViews[i].getName())) + return i; + } + return -1; + } + //listens for events performed on the menu items + @Override + public void actionPerformed(java.awt.event.ActionEvent e) + { + String s = e.getActionCommand(); + int i = isStyleChange(s); + if (s.equals("Close All") || s.equals("Close Others")) { + MainFrame.myDesktopManager.closeAll(s.equals("Close Others")); + } + else if (s.equals(Language.translate("Exit"))) + myParentFrame.exitForm(); + else if (s.equals(Language.translate("About"))) + showAboutWindow(); + else if (i >= 0) + { + try + { + UIManager.setLookAndFeel(availableViews[i].getClassName()); + SwingUtilities.updateComponentTreeUI(myParentFrame); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + else if (s.equals(Language.translate("Tree Browser"))) + { + myParentFrame.toggleTree(); + } + else if (s.indexOf(":")>0) { // server console + try + { + String[] serverDetails = s.split(":"); + new Console(serverDetails[0], Integer.parseInt(serverDetails[1])).setVisible(true); + } + catch (Exception ex) + { + Logger.error(ex); + } + } + else if (s.equals(Language.translate("Local console"))) { + try + { + new Console("localhost", Logger.getConsolePort()).setVisible(true); + } + catch (Exception ex) + { + Logger.error(ex); + } + } + else if (s.equals(Language.translate("Outcome Field Help"))) { + MainFrame.setPref("ShowHelp", String.valueOf(!MainFrame.getPref("ShowHelp", "true").equals("true"))); + } + else if (s.equals(Language.translate("Graph Properties"))) { + MainFrame.setPref("ShowProps", String.valueOf(!MainFrame.getPref("ShowProps", "true").equals("true"))); + } + else + Logger.msg(1, "MenuBuilder.actionPerformed() - No action associated with the event received"); + } + //constructs an about dialog + public void showAboutWindow() + { + JOptionPane myPane = new JOptionPane(); + Box about = Box.createVerticalBox(); + + String aboutInfo; + try + { + aboutInfo = FileStringUtility.file2String(Gateway.getProperty("about")); + } + catch (Exception e) + { + aboutInfo = Language.translate("Cristal 2 Itembrowser"); + } + JLabel title = new JLabel(aboutInfo); + about.add(title); + + about.add(new JLabel("Kernel version: "+Resource.getKernelVersion())); + about.add(new JLabel("Modules loaded: "+Gateway.getModuleManager().getModuleVersions())); + // get license info + + StringBuffer lictxt = new StringBuffer(); + try { + lictxt.append(Resource.getTextResource(null, "textFiles/license.html")); + } catch (ObjectNotFoundException e) { } // no kernel license found + for (String ns : Resource.getModuleBaseURLs().keySet()) { + String domlictxt; + try { + domlictxt = Resource.getTextResource(ns, "license.html"); + lictxt.append(domlictxt).append("\n"); + } catch (ObjectNotFoundException e) { } + + } + + + JEditorPane license = new JEditorPane(); + license.setEditable(false); + license.setEditorKit(new HTMLEditorKit()); + license.setContentType("text/html"); + license.addHyperlinkListener(this); + license.setText(lictxt.toString()); + JScrollPane scroll = new JScrollPane(license); + scroll.setPreferredSize(new Dimension(300,200)); + license.setCaretPosition(0); + + about.add(scroll); + myPane.setMessage(about); + myPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + JDialog dialog = myPane.createDialog(null, Language.translate("About")); + dialog.setResizable(false); + Icon icon = Resource.findImage(Gateway.getProperty("banner")); + myPane.setIcon(icon); + dialog.pack(); + dialog.setVisible(true); + } + + @Override +public void hyperlinkUpdate(HyperlinkEvent e) { + try { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) + Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler "+e.getURL().toString()); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + + @Override + public void itemStateChanged(java.awt.event.ItemEvent e) + { + } +} diff --git a/src/main/java/com/c2kernel/gui/TreeBrowser.java b/src/main/java/com/c2kernel/gui/TreeBrowser.java new file mode 100644 index 0000000..72cf738 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/TreeBrowser.java @@ -0,0 +1,213 @@ +package com.c2kernel.gui; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.ImageIcon; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.ToolTipManager; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +import com.c2kernel.gui.data.Node; +import com.c2kernel.gui.data.NodeEntity; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.utils.Logger; + +/** + * Container for the tree browser + * @version $Revision: 1.31 $ $Date: 2006/01/17 07:49:44 $ + * @author $Author: abranson $ + */ + + // must put in top level list of loaded items, so we don't have duplicates +public class TreeBrowser extends JPanel implements DomainKeyConsumer +{ + private EntityTabManager desktop; + protected JTree tree; + private Node userRoot; + + public TreeBrowser(EntityTabManager target, Node userRoot) { + setLayout(new java.awt.BorderLayout()); + //record the desktop and node factory for our item frames + this.desktop = target; + this.userRoot = userRoot; + this.setPreferredSize(new Dimension(300, 500)); + tree = new JTree(new DefaultTreeModel(userRoot.getTreeNode())); + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + tree.setToggleClickCount(3); // need three clicks to expand a branch + tree.addTreeExpansionListener( + new TreeExpansionListener() { + @Override + public void treeCollapsed(TreeExpansionEvent e) { + //REVISIT: possible reaping here if things are getting heavy + } + @Override + public void treeExpanded(TreeExpansionEvent e) { + TreePath p = e.getPath(); + // find the clicked tree node + DefaultMutableTreeNode nodeClicked = (DefaultMutableTreeNode)p.getLastPathComponent(); + // run the tree builder if it is there. + DefaultMutableTreeNode loadNode = (DefaultMutableTreeNode)nodeClicked.getFirstChild(); + if (loadNode.getUserObject() instanceof DynamicTreeBuilder) { + DynamicTreeBuilder loading = (DynamicTreeBuilder)loadNode.getUserObject(); + if (loading.state == DynamicTreeBuilder.IDLE) { + loading.buildInfo(tree); + loading.start(); + } + } + } + } + ); + + //Enable tool tips. + ToolTipManager.sharedInstance().registerComponent(tree); + tree.setCellRenderer(new ItemRenderer()); + tree.addMouseListener(new TreeMouseListener()); + JScrollPane myScrollPane = new JScrollPane(tree); + this.add(myScrollPane); + DefaultMutableTreeNode loadNode = (DefaultMutableTreeNode)userRoot.getTreeNode().getFirstChild(); + DynamicTreeBuilder loading = (DynamicTreeBuilder)loadNode.getUserObject(); + loading.buildInfo(tree); + loading.start(); + } + + @Override + public void push(DomainPath target) { + Logger.debug("Opening tree node "+target); + String[] components = target.getPath(); + Node currentNode = userRoot; + Object[] treePath = new Object[components.length+1]; + treePath[0] = currentNode.getTreeNode(); + for (int i=0; i childNodes = new HashMap(); + protected ArrayList subscribers = new ArrayList(); + protected DynamicTreeBuilder loader = null; + private boolean loaded = false; + private String iconName; + protected EntityTabManager desktop; + static ImageIcon folder = Resource.findImage("folder.png"); + static ImageIcon emptyLeaf = Resource.findImage("leaf.png"); + + public Node() { + } + + protected void createTreeNode() { + this.treeNode = new DefaultMutableTreeNode(this); + } + + public Node(Path path, EntityTabManager desktop) { + this.binding = path; + this.desktop = desktop; + this.sysKey = path.getSysKey(); + // get the name of this node (last path element) + String[] pathComponents = path.getPath(); + if (pathComponents.length > 0) + this.name = pathComponents[pathComponents.length-1]; + else + this.name = Gateway.getProperty("Name"); + } + + public EntityTabManager getDesktop() { + return desktop; + } + + public Node newNode(Path path) + { + try { + if (path.getEntity() instanceof AgentPath) + return new NodeAgent(path, desktop); + else + return new NodeItem(path, desktop); + } catch (ObjectNotFoundException ex) { + return new NodeContext(path, desktop); + } + + } + + /** Inserts a tree builder as the first child of the node, so it can be opened in the tree + */ + public void makeExpandable() { + if (isExpandable) return; + loader = new DynamicTreeBuilder(this.treeNode); + this.treeNode.insert(loader.getTreeNode(),0); + isExpandable = true; + } + + + public DefaultMutableTreeNode getTreeNode() { + return treeNode; + } + + public void setTreeNode(DefaultMutableTreeNode treeNode) { + this.treeNode = treeNode; + treeNode.setUserObject(this); + } + + /** Subscription for loading node children. + * Note this is separate from the itemproxy subscription as it included query of the naming service + * and eventually should not require access to the item at all for higher performance */ + public void subscribeNode(NodeSubscriber target) { + subscribers.add(target); + if (loaded == false) { + loaded = true; + loadMore(); + } + else { + synchronized (childNodes) { + Node newNode; + for (Iterator nodes = childNodes.values().iterator(); nodes.hasNext();) { + newNode = nodes.next(); + Logger.msg("subscribeNode target.add("+newNode.name+")"); + target.add(newNode); + } + } + } + } + + public void loadMore() { + Thread loading = new Thread(this); + loading.start(); + } + + public void unsubscribeNode(NodeSubscriber target) { + subscribers.remove(target); + } + + public void add(Node newNode) { + synchronized(childNodes) { + childNodes.put(newNode.getPath(), newNode); + for (NodeSubscriber thisSub : subscribers) { + thisSub.add(newNode); + } + } + } + + public void remove(Path oldPath) { + synchronized(childNodes) { + childNodes.remove(oldPath); + for (NodeSubscriber thisSub : subscribers) { + thisSub.remove(oldPath); + } + } + } + + public void removeAllChildren() { + synchronized(childNodes) { + while (childNodes.keySet().iterator().hasNext()) { + remove(childNodes.keySet().iterator().next()); + } + } + } + + public Node getChildNode(Path itsPath) { + for (Iterator i = childNodes.keySet().iterator(); i.hasNext();) { + Object next = i.next(); + if ( next.equals(itsPath) ) return childNodes.get(next); + } + return null; + } + + // end of current batch + public void end(boolean more) { + for (NodeSubscriber thisSub : subscribers) { + thisSub.end(more); + } + } + + + @Override + public void run() { + Thread.currentThread().setName("Node Loader: "+name); + loadChildren(); + } + + public abstract void loadChildren(); + + public void refresh() { + removeAllChildren(); + loadChildren(); + } + + // Getters and Setters + + public int getSysKey() { return sysKey; } +// public void setSysKey( int sysKey ) { this.sysKey = sysKey; } + + public String getName() { return name; } +// public void setName( String name ) { this.name = name; } + + public String getType() { return type; } +// public void setType( String type ) { this.type = type; } + + public Path getPath() { return binding; } + + public DynamicTreeBuilder getTreeBuilder() { return loader; } + + @Override + public String toString() { + if (this.name.length() > 0) { + return this.name; + } + else { return "Cristal"; } + } + + public Icon getIcon() { + if (icon != null) return icon; + return(isExpandable?folder:emptyLeaf); + } + + public String getIconName() { + return iconName; + } + + public void setIcon(String icon) { + iconName = icon; + this.icon = Resource.findImage("typeicons/"+icon+"_16.png"); + } + + public JPopupMenu getPopupMenu() { + JPopupMenu popup = new JPopupMenu(); + JMenuItem menuItem = new JMenuItem(Language.translate("Refresh")); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (isExpandable) refresh(); + } + }); + popup.add(menuItem); + return popup; + } +} diff --git a/src/main/java/com/c2kernel/gui/data/NodeAgent.java b/src/main/java/com/c2kernel/gui/data/NodeAgent.java new file mode 100644 index 0000000..9f6cdad --- /dev/null +++ b/src/main/java/com/c2kernel/gui/data/NodeAgent.java @@ -0,0 +1,33 @@ + +package com.c2kernel.gui.data; + + +import java.util.ArrayList; + +import com.c2kernel.gui.EntityTabManager; +import com.c2kernel.lookup.Path; + +/** + * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory. + * @author $Author: abranson $ + * @version $Version$ + */ +public class NodeAgent extends NodeEntity { + + public NodeAgent(Path path, EntityTabManager desktop) { + super(path, desktop); + } + + @Override + public void loadChildren() { + } + + @Override + public ArrayList getTabs() { + + ArrayList requiredTabs = super.getTabs(); + requiredTabs.add("AgentProperties"); + requiredTabs.add("JobList"); + return requiredTabs; + } +} diff --git a/src/main/java/com/c2kernel/gui/data/NodeCollection.java b/src/main/java/com/c2kernel/gui/data/NodeCollection.java new file mode 100644 index 0000000..ceee16f --- /dev/null +++ b/src/main/java/com/c2kernel/gui/data/NodeCollection.java @@ -0,0 +1,68 @@ +package com.c2kernel.gui.data; + +import java.util.ArrayList; + +import javax.swing.tree.DefaultMutableTreeNode; + +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.collection.Parent2ChildCollection; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.gui.EntityTabManager; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.utils.Logger; + +public class NodeCollection extends Node { + + ItemProxy parent; + Parent2ChildCollection thisCollection; + String path; + + public NodeCollection(ItemProxy parent, String name, EntityTabManager desktop) { + this.desktop = desktop; + this.parent = parent; + this.name = name; + this.path = parent.getSystemKey()+"/Collection/"+name; + createTreeNode(); + this.makeExpandable(); + } + + @Override + public void loadChildren() { + Logger.msg(8, "NodeCollection::loadChildren()"); + try { + thisCollection = (Parent2ChildCollection)parent.getObject("Collection/"+name); + } catch (ObjectNotFoundException ex) { + end(false); + return; + } + + this.type = thisCollection.getClass().getName(); + int lastDot = this.type.lastIndexOf('.'); + if (lastDot > -1) this.type = this.type.substring(lastDot+1); + ArrayList collectionMembers = thisCollection.getMembers().list; + for (int i=0; i children; + + public NodeContext(Path path, EntityTabManager desktop) { + super(path, desktop); + this.sysKey=Path.INVALID; + createTreeNode(); + this.makeExpandable(); + this.type = "Cristal Context"; + } + + + @Override + public void loadChildren() { + if (children == null) { + Gateway.getProxyManager().subscribeTree(this, (DomainPath)binding); + children = binding.getChildren(); + } + + int batch = 75; + while (children.hasMoreElements() && batch > 0) { + Path newPath = children.nextElement(); + if (newPath == null) break; + Logger.msg(2, "Subscription.run() - new node: " + newPath ); + add( newNode(newPath)); + batch--; + } + end(children.hasMoreElements()); + } + + @Override + public void pathAdded(DomainPath path) { + add(newNode(path)); + } + + @Override + public void refresh() { + children = null; + super.refresh(); + } + @Override + public void pathRemoved(DomainPath path) { + remove(path); + } + +} + + + + + + + diff --git a/src/main/java/com/c2kernel/gui/data/NodeEntity.java b/src/main/java/com/c2kernel/gui/data/NodeEntity.java new file mode 100644 index 0000000..cce4f68 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/data/NodeEntity.java @@ -0,0 +1,82 @@ +package com.c2kernel.gui.data; + + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import com.c2kernel.entity.proxy.EntityProxy; +import com.c2kernel.gui.EntityTabManager; +import com.c2kernel.lookup.Path; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/** + * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory. + * @author $Author: abranson $ + * @version $Version$ + */ +public abstract class NodeEntity extends Node { + + protected EntityProxy myEntity = null; + + public NodeEntity(Path path, EntityTabManager desktop) { + super(path, desktop); + Logger.msg(2,"NodeEntity. - Creating item for '"+path.toString()+"'."); + + try { + // if an item - resolve the item and get its properties + myEntity = Gateway.getProxyManager().getProxy(path); + this.sysKey = path.getSysKey(); + Logger.msg(2,"NodeEntity. - System key is "+this.sysKey); + + // Name should be the alias if present + String alias = myEntity.getName(); + if (alias != null) this.name = alias; + + this.type = myEntity.getProperty("Type"); + String iconString = this.type; + if (type.equals("ActivityDesc")) iconString = myEntity.getProperty("Complexity")+iconString; + iconString = iconString.toLowerCase(); + this.setIcon(iconString); + createTreeNode(); + } catch (Exception e) { + Logger.msg(2, "NodeEntity. - "+sysKey+" failed to resolve:"); + Logger.error(e); + } + } + + public EntityProxy getEntity() { + return myEntity; + } + /** + * + */ + @Override + public JPopupMenu getPopupMenu() { + JPopupMenu popup = super.getPopupMenu(); + JMenuItem openItem = new JMenuItem(Language.translate("Open")); + openItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + openItem(); + } + }); + popup.addSeparator(); + popup.add(openItem); + return popup; + } + + public void openItem() { + desktop.add(this); + } + + public ArrayList getTabs() { + ArrayList requiredTabs = new ArrayList(); + return requiredTabs; + } +} diff --git a/src/main/java/com/c2kernel/gui/data/NodeItem.java b/src/main/java/com/c2kernel/gui/data/NodeItem.java new file mode 100644 index 0000000..30f7ce3 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/data/NodeItem.java @@ -0,0 +1,112 @@ +package com.c2kernel.gui.data; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.gui.EntityDetails; +import com.c2kernel.gui.EntityTabManager; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Logger; + +/** + * Structure for Item presence on the tree and ItemDetails boxes. Created by NodeFactory. + * @author $Author: abranson $ + * @version $Version$ + */ +public class NodeItem extends NodeEntity { + + public NodeItem(Path path, EntityTabManager desktop) { + super(path, desktop); + try { + makeExpandable(); + } catch (Exception e) { + Logger.error(e); + } + } + + @Override + public void loadChildren() { + try { + String collections = myEntity.queryData("Collection/all"); + StringTokenizer tok = new StringTokenizer(collections, ","); + while (tok.hasMoreTokens()) { + NodeCollection newCollection = new NodeCollection((ItemProxy)myEntity, tok.nextToken(), desktop); + add(newCollection); + } + end(false); + } catch (Exception e) { + Logger.error(e); + } + } + + @Override + public JPopupMenu getPopupMenu() { + JPopupMenu popup = super.getPopupMenu(); + popup.addSeparator(); + try { + ArrayList jobList = ((ItemProxy)myEntity).getJobList(MainFrame.userAgent); + ArrayList already = new ArrayList(); + if (jobList.size() > 0) { + for (Job thisJob : jobList) { + String stepName = thisJob.getStepName(); + if (already.contains(stepName)) + continue; + already.add(stepName); + JMenuItem menuItem = new JMenuItem(stepName); + menuItem.setActionCommand(stepName); + menuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + execute(e.getActionCommand()); + } + }); + popup.add(menuItem); + + } + } + else { + JMenuItem noAct = new JMenuItem("No activities"); + noAct.setEnabled(false); + popup.add(noAct); + } + } catch (Exception ex) { + JMenuItem error = new JMenuItem("Error querying jobs"); + error.setEnabled(false); + popup.add(error); + } + + return popup; + } + + public void execute(String stepName) { + EntityDetails thisDetail = desktop.add(this); + thisDetail.runCommand("Execution", stepName); + } + + @Override + public ArrayList getTabs() { + + ArrayList requiredTabs = super.getTabs(); + requiredTabs.add("Properties"); + try { + String collNames = myEntity.queryData(ClusterStorage.COLLECTION+"/all"); + if (collNames.length() > 0) + requiredTabs.add("Collection"); + } catch (Exception e) { } + requiredTabs.add("Execution"); + requiredTabs.add("History"); + requiredTabs.add("Viewpoint"); + requiredTabs.add("Workflow"); + return requiredTabs; + + } +} diff --git a/src/main/java/com/c2kernel/gui/data/NodeSubscriber.java b/src/main/java/com/c2kernel/gui/data/NodeSubscriber.java new file mode 100644 index 0000000..70af660 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/data/NodeSubscriber.java @@ -0,0 +1,13 @@ +package com.c2kernel.gui.data; + +import com.c2kernel.lookup.Path; + + +public interface NodeSubscriber { + + public void add(Node newNode); + + public void remove(Path path); + + public void end(boolean more); +} diff --git a/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java b/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java new file mode 100644 index 0000000..f0ae533 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/AgentPropertiesPane.java @@ -0,0 +1,51 @@ +package com.c2kernel.gui.tabs; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextField; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2005/07/05 11:34:17 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + +public class AgentPropertiesPane extends EntityTabPane { + + JTable roleTable; + JTextField newPassword; + JTextField newPasswordConfirm; + JButton changePassword; + + public AgentPropertiesPane() { + super("Properties", "Agent Details"); + initPanel(); + getGridBagConstraints(); + c.gridy++; + JLabel roleHeader = new JLabel("Roles held"); + roleHeader.setFont(titleFont); + roleHeader.setForeground(headingColor); + gridbag.setConstraints(roleHeader, c); + add(roleHeader); + roleTable = new JTable(1,1); + JScrollPane roleScroll = new JScrollPane(roleTable); + c.gridy++; + gridbag.setConstraints(roleScroll, c); + add(roleScroll); + + //JLabel passHeader = new JLabel("Change password"); + //TODO: Finish agent admin page + } + + @Override + public void run() { + + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java b/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java new file mode 100644 index 0000000..a117df4 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/CloseTabIcon.java @@ -0,0 +1,70 @@ +package com.c2kernel.gui.tabs; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.Icon; + +/** + * @author Developpement + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +/** * The class which generates the 'X' icon for the tabs. The constructor * accepts an icon which is extra to the 'X' icon, so you can have tabs * like in JBuilder. This value is null if no extra icon is required. */ +class CloseTabIcon implements Icon +{ + private int x_pos; + private int y_pos; + private int width; + private int height; + private Icon fileIcon; + public CloseTabIcon(Icon fileIcon) + { + this.fileIcon = fileIcon; + width = 16; + height = 16; + } + @Override + public void paintIcon(Component c, Graphics g, int x, int y) + { + this.x_pos = x; + this.y_pos = y; + Color col = g.getColor(); + g.setColor(Color.black); + int y_p = y + 2; + g.drawLine(x + 1, y_p, x + 12, y_p); + g.drawLine(x + 1, y_p + 13, x + 12, y_p + 13); + g.drawLine(x, y_p + 1, x, y_p + 12); + g.drawLine(x + 13, y_p + 1, x + 13, y_p + 12); + g.drawLine(x + 3, y_p + 3, x + 10, y_p + 10); + g.drawLine(x + 3, y_p + 4, x + 9, y_p + 10); + g.drawLine(x + 4, y_p + 3, x + 10, y_p + 9); + g.drawLine(x + 10, y_p + 3, x + 3, y_p + 10); + g.drawLine(x + 10, y_p + 4, x + 4, y_p + 10); + g.drawLine(x + 9, y_p + 3, x + 3, y_p + 9); + g.setColor(col); + if (fileIcon != null) + { + fileIcon.paintIcon(c, g, x + width, y_p); + } + } + @Override + public int getIconWidth() + { + return width + (fileIcon != null ? fileIcon.getIconWidth() : 0); + } + @Override + public int getIconHeight() + { + return height; + } + public Rectangle getBounds() + { + return new Rectangle(x_pos, y_pos, width, height); + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java b/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java new file mode 100644 index 0000000..4d9092e --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/CollectionPane.java @@ -0,0 +1,109 @@ +package com.c2kernel.gui.tabs; +import java.awt.GridBagConstraints; + +import javax.swing.JTabbedPane; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.collection.Dependency; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.gui.tabs.collection.AggregationView; +import com.c2kernel.gui.tabs.collection.CollectionView; +import com.c2kernel.gui.tabs.collection.DependencyView; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.36 $ $Date: 2005/10/06 06:51:15 $ + * @author $Author: abranson $ + */ +public class CollectionPane extends EntityTabPane implements EntityProxyObserver> +{ + JTabbedPane collTabs; + + public CollectionPane() + { + super("Collection", "Item Collection"); + createLayout(); + } + + @Override + public void add(Collection contents) + { + Logger.msg(5, "Got "+contents.getName()+": "+contents.getClass().getName()); + Logger.msg(7, "Looking for existing "+contents.getName()); + CollectionView thisCollView = findTabForCollName(contents.getName()); + if (thisCollView == null){ + if (contents instanceof Aggregation) { + AggregationView thisAggView = new AggregationView(); + thisAggView.setCollection((Aggregation)contents); + thisCollView = thisAggView; + } + else if (contents instanceof Dependency) { + DependencyView thisDepView = new DependencyView(); + thisDepView.setCollection((Dependency)contents); + thisCollView = thisDepView; + } + else { + Logger.error("Collection type "+contents.getClass().getName()+" not known"); + return; + } + Logger.msg(3, "Adding new "+thisCollView.getClass().getName()); + thisCollView.setItem((ItemProxy)sourceEntity.getEntity()); + collTabs.add(contents.getName(), thisCollView); + } + } + + @Override + public void remove(String id) + { + + } + + private CollectionView findTabForCollName(String collName) { + CollectionView thisCollView = null; + for (int i = 0; i < collTabs.getTabCount(); i++) { + String tabName = collTabs.getTitleAt(i); + if (tabName.equals(collName)) { + thisCollView = (CollectionView)collTabs.getComponentAt(i); + } + } + return thisCollView; + } + + protected void createLayout() + { + initPanel(); + // Add the collection tab pane + getGridBagConstraints(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.BOTH; + c.weighty = 2.0; + collTabs = new JTabbedPane(); + gridbag.setConstraints(collTabs, c); + add(collTabs); + } + + @Override + public void run() + { + Thread.currentThread().setName("Collection Loader"); + sourceEntity.getEntity().subscribe(new MemberSubscription>(this, ClusterStorage.COLLECTION, true)); + } + + @Override + public void reload() + { + Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.COLLECTION); + collTabs.removeAll(); + initForEntity(sourceEntity); + } + + @Override + public void control(String control, String msg) { + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java b/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java new file mode 100644 index 0000000..408a32c --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/DomainPathAdmin.java @@ -0,0 +1,174 @@ +package com.c2kernel.gui.tabs; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Enumeration; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2004/10/21 08:02:21 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class DomainPathAdmin extends Box implements ActionListener { + + ItemProxy entity; + JTable table; + DomainPathTableModel model; + JButton addButton; + JButton removeButton; + + public DomainPathAdmin() { + super(BoxLayout.Y_AXIS); + + model = new DomainPathTableModel(this); + table = new JTable(model); + add(new JScrollPane(table)); + + add(Box.createVerticalGlue()); + Box buttonBox = Box.createHorizontalBox(); + addButton = new JButton("Add"); + buttonBox.add(addButton); + buttonBox.add(Box.createHorizontalGlue()); + removeButton = new JButton("Remove"); + buttonBox.add(removeButton); + buttonBox.add(Box.createHorizontalGlue()); + add(buttonBox); + + addButton.setActionCommand("add"); + addButton.addActionListener(this); + removeButton.setActionCommand("remove"); + removeButton.addActionListener(this); + } + + public void setEntity(ItemProxy entity) { + this.entity = entity; + model.loadPaths(); + } + + @Override +public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("add")) { + String newPath = JOptionPane.showInputDialog(this, "Enter new path,", "Add Domain Path", JOptionPane.PLAIN_MESSAGE); + addDomainPath(new DomainPath(newPath)); + model.loadPaths(); + } + else if (e.getActionCommand().equals("remove")) { + if (table.getSelectedRow() > -1) { + DomainPath oldPath = model.getPath(table.getSelectedRow()); + removeDomainPath(oldPath); + model.loadPaths(); + } + } + } + + public boolean removeDomainPath(DomainPath oldPath) { + return alterDomainPath(oldPath, "Remove"); + } + + public boolean addDomainPath(DomainPath newPath) { + return alterDomainPath(newPath, "Add"); + } + + public boolean alterDomainPath(DomainPath path, String action) { + + if (JOptionPane.showConfirmDialog(this, + action+" "+path+"?", + action+" Domain Path", + JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return false; + + String[] params = new String[1]; + params[0] = path.toString(); + try { + MainFrame.userAgent.execute(entity, action+"DomainPath", params); + } catch (Exception e) { + Logger.exceptionDialog(e); + return false; + } + return true; + } + + private class DomainPathTableModel extends AbstractTableModel { + ArrayList domPaths; + DomainPathAdmin parent; + public DomainPathTableModel(DomainPathAdmin parent) { + this.parent = parent; + domPaths = new ArrayList(); + } + + public void loadPaths() { + domPaths.clear(); + for (Enumeration currentPaths = Gateway.getLDAPLookup().search(new DomainPath(), entity.getName()); currentPaths.hasMoreElements();) { + DomainPath thisPath = (DomainPath)currentPaths.nextElement(); + if (thisPath.getSysKey() == entity.getSystemKey()) + domPaths.add(thisPath); + } + fireTableDataChanged(); + } + + public DomainPath getPath(int rowIndex) { + return domPaths.get(rowIndex); + } + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + DomainPath oldPath = domPaths.get(rowIndex); + DomainPath newPath = new DomainPath((String)aValue); + boolean success = parent.addDomainPath(newPath); + if (success) + success = parent.removeDomainPath(oldPath); + if (success) { + oldPath.setPath(newPath); + fireTableDataChanged(); + } + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public String getColumnName(int column) { + return "Path"; + } + + @Override + public int getRowCount() { + return domPaths.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return domPaths.get(rowIndex).toString(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return true; + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java b/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java new file mode 100644 index 0000000..0a8a0cd --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/EntityTabPane.java @@ -0,0 +1,197 @@ +/* + * TabbedPane.java + * + * Created on March 22, 2001, 11:39 AM + */ +package com.c2kernel.gui.tabs; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.SwingConstants; + +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.gui.EntityDetails; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.data.NodeEntity; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.gui.tabs.outcome.form.OutcomePanel; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +/** + * Generic item details tabbed pane. + * + * @version $Revision: 1.31 $ $Date: 2005/06/08 16:47:44 $ + * @author $Author: abranson $ + */ +public class EntityTabPane extends JPanel implements Runnable { + + protected NodeEntity sourceEntity; + protected String titleText = null; + protected ImageIcon titleIcon = null; + private final String tabName; + protected GridBagLayout gridbag = new GridBagLayout(); + protected GridBagConstraints c = null; + public static Font titleFont = null; + public static Color headingColor = new Color(0, 0, 185); + protected EntityDetails parent; + protected static ImageIcon mReloadIcon = null; + protected Box titleBox; + static { + try { + mReloadIcon = Resource.findImage("reload.gif"); + } catch (Exception e) { + Logger.warning("Couldn't load images: " + e); + } + } + + public void focusLost(FocusEvent e) + { + } + + public EntityTabPane(String tabName, String titleText) { + this.tabName = Language.translate(tabName); + this.titleText = + titleText == null ? null : Language.translate(titleText); + if (titleFont == null) + titleFont = + new Font("SansSerif", Font.BOLD, this.getFont().getSize() + 5); + Logger.msg(2, "ItemTabPane. - viewing " + tabName); + setLayout(gridbag); + } + public void setParent(EntityDetails parent) { + this.parent = parent; + } + public String getTabName() { + return tabName; + } + protected GridBagConstraints getGridBagConstraints() { + if (c == null) + c = new GridBagConstraints(); + return c; + } + protected void initPanel() { + getGridBagConstraints().gridx = 0; + getGridBagConstraints().gridy = 0; + getGridBagConstraints().anchor = GridBagConstraints.NORTHWEST; + getGridBagConstraints().fill = GridBagConstraints.HORIZONTAL; + getGridBagConstraints().ipadx = 5; + getGridBagConstraints().weightx = 1.0; + getGridBagConstraints().ipady = 5; + // Help panel + if (titleText == null) + titleText = tabName; + if (titleIcon == null) + titleIcon = Resource.findImage("info.png"); + JLabel title = new JLabel(titleText, titleIcon, SwingConstants.LEFT); + title.setFont(titleFont); + title.setForeground(headingColor); + JButton refreshButton = new JButton(mReloadIcon); + refreshButton.setToolTipText(Language.translate("Refresh")); + refreshButton.setMargin(new Insets(0, 0, 0, 0)); + refreshButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + setCursor(new Cursor(Cursor.WAIT_CURSOR)); + reload(); + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + }); + String defaultStartTab = MainFrame.getPref("DefaultStartTab", "Properties"); + JToggleButton defaultStart = + new JToggleButton(Resource.findImage("graph/start.png")); + defaultStart.setMargin(new Insets(0, 0, 0, 0)); + defaultStart.setToolTipText( + Language.translate("Select this tab to be the default one opened when you double click an item")); + defaultStart.setSelected(tabName.equals(defaultStartTab)); + defaultStart.setActionCommand(tabName); + defaultStart.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (((JToggleButton)e.getSource()).isSelected()) + MainFrame.setPref("DefaultStartTab", e.getActionCommand()); + } + }); + titleBox = Box.createHorizontalBox(); + titleBox.add(title); + titleBox.add(Box.createHorizontalGlue()); + titleBox.add(defaultStart); + titleBox.add(refreshButton); + gridbag.setConstraints(titleBox, c); + this.add(titleBox); + } + public void initForEntity(NodeEntity sourceEntity) { + this.sourceEntity = sourceEntity; + Thread loader = new Thread(this); + loader.start(); + } + @Override + public void run() { + Thread.currentThread().setName("Default Entity Pane Builder"); + getGridBagConstraints(); + c.gridx = 0; + c.gridy = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.HORIZONTAL; + c.ipadx = 5; + c.weightx = 1.0; + c.weighty = 1.0; + c.ipady = 5; + JLabel error = new JLabel("In Development"); + gridbag.setConstraints(error, c); + this.add(error); + } + public void reload() { + } + public void runCommand(String command) { + } + + public void destroy() { + if (sourceEntity != null && this instanceof EntityProxyObserver) { + sourceEntity.getEntity().unsubscribe((EntityProxyObserver)this); + } + parent = null; + } + + @Override + protected void finalize() throws Throwable { + Logger.msg(7, "Reaping "+getClass().getName()); + } + + static public OutcomeHandler getOutcomeHandler(String schema, int version) { + String ohClassName = Gateway.getProperty("OutcomeHandler."+schema+"."+version); + try { + if (ohClassName != null && ohClassName.length() > 0) { + Class ohClass = Class.forName(ohClassName); + return (OutcomeHandler) ohClass.newInstance(); + } + } catch (Exception ex) { + Logger.error("Error creating handler "+ohClassName+". using default outcome editor"); + } + ohClassName = Gateway.getProperty("OutcomeHandler.*"); + try { + if (ohClassName != null && ohClassName.length() > 0) { + Class ohClass = Class.forName(ohClassName); + return (OutcomeHandler) ohClass.newInstance(); + } + } catch (Exception ex) { + Logger.error("Error creating handler "+ohClassName+". using default outcome editor"); + Logger.error(ex); + } + return new OutcomePanel(); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java b/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java new file mode 100644 index 0000000..a853695 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/ExecutionPane.java @@ -0,0 +1,208 @@ +package com.c2kernel.gui.tabs; + +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.execution.ActivityItem; +import com.c2kernel.gui.tabs.execution.ActivityViewer; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +public class ExecutionPane extends EntityTabPane implements EntityProxyObserver { + + ArrayList jobList = null; + Object jobLock = new Object(); + ActivityItem emptyAct = new ActivityItem(); + JLabel noActs = new JLabel(Language.translate("There are currently no activities that you can execute in this item.")); + JPanel view = new JPanel(new GridLayout(1, 1)); + ActivityViewer currentActView; + JComboBox activitySelector = new JComboBox(); + Box activityBox = Box.createHorizontalBox(); + String selAct = null; + ArrayList activities; + String autoRun = null; + boolean init = false; + boolean formIsActive = false; + public ExecutionPane() { + super("Execution", "Activity Execution"); + super.initPanel(); + // add view panel + c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 1; c.weightx = 1.0; c.weighty = 2.0; + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + gridbag.setConstraints(view, c); + + add(view); + // create activity selection box + activityBox.add(new JLabel(Language.translate("Select Activity") + ": ")); + activityBox.add(Box.createHorizontalStrut(5)); + activitySelector.setEditable(false); + activityBox.add(activitySelector); + activitySelector.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent selection) { + if (selection.getStateChange() == ItemEvent.SELECTED) { + selectActivity(selection.getItem()); + } + } + }); + } + @Override + public void run() { + Thread.currentThread().setName("Execution Pane Builder"); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.LIFECYCLE, false)); + loadJobList(); + init = true; + if (autoRun != null) { + runCommand(autoRun); + autoRun = null; + } + } + private void loadJobList() { + synchronized (jobLock) { + activitySelector.removeAllItems(); + view.removeAll(); + activities = new ArrayList(); + try { + jobList = ((ItemProxy)sourceEntity.getEntity()).getJobList(MainFrame.userAgent); + activitySelector.addItem(emptyAct); + for (Job thisJob : jobList) { + Logger.msg(7, "ExecutionPane - loadJobList " + thisJob.isOutcomeUsed() + "|" + thisJob.getSchemaType() + "|" + thisJob.getSchemaVersion() + "|"); + ActivityItem newAct = new ActivityItem(thisJob); + if (activities.contains(newAct)) { + int actIndex = activities.indexOf(newAct); + activities.get(actIndex).addJob(thisJob); + } else { + Logger.msg(2, "ExecutionPane - Adding activity " + thisJob.getStepPath()); + addActivity(newAct); + } + } + } catch (Exception e) { + Logger.debug("Error fetching joblist"); + Logger.error(e); + } + + switch (activities.size()) { + case 0 : + view.add(noActs); + break; + case 1 : + currentActView = new ActivityViewer(activities.get(0), (ItemProxy)sourceEntity.getEntity(), this); + c.fill = GridBagConstraints.BOTH; + gridbag.setConstraints(view, c); + view.add(currentActView); + currentActView.init(); + break; + default : + c.fill = GridBagConstraints.HORIZONTAL; + gridbag.setConstraints(view, c); + view.add(activityBox); + } + } + revalidate(); + updateUI(); + } + @Override + public void reload() { + loadJobList(); + } + private void addActivity(ActivityItem newAct) { + if (activities.contains(newAct)) { + Logger.msg(6, "ExecutionPane.addActivity(): Already in " + newAct.getStepPath()); + int actIndex = activities.indexOf(newAct); + activitySelector.removeItemAt(actIndex); + activitySelector.insertItemAt(newAct, actIndex); + activities.set(actIndex, newAct); + } else { + Logger.msg(6, "ExecutionPane.addActivity(): New " + newAct.getStepPath()); + activities.add(newAct); + activitySelector.addItem(newAct); + } + } + private void selectActivity(Object selObj) { + if (selObj.equals(emptyAct)) + return; + view.removeAll(); + c.fill = GridBagConstraints.BOTH; + gridbag.setConstraints(view, c); + currentActView = new ActivityViewer((ActivityItem)selObj, (ItemProxy)sourceEntity.getEntity(), this); + view.add(currentActView); + revalidate(); + updateUI(); + currentActView.init(); + } + @Override + public void runCommand(String command) { + if (init) { + for (ActivityItem act : activities) { + if (act.name.equals(command)) { + selectActivity(act); + } + } + } else + autoRun = command; + } + /** + * when the workflow changes, reload this pane. + */ + @Override + public void add(Workflow contents) { + if (!formIsActive) + reload(); + else { // look to see if this form is now invalid + // get the new joblist + try { + jobList = ((ItemProxy)sourceEntity.getEntity()).getJobList(MainFrame.userAgent); + } catch (Exception ex) { + return; + } + // compare to currently editing jobs + ArrayList currentActJobs = currentActView.getActivity().getJobs(); + boolean allValid = true; + for (Iterator iter = currentActJobs.iterator(); iter.hasNext() && allValid;) { + Job thisJob = (Job)iter.next(); + boolean stillValid = false; + for (Job newJob : jobList) { + if (thisJob.equals(newJob)) { + stillValid = true; + break; + } + } + allValid &= stillValid; + } + if (!allValid) { // not all transitions are now valid + reload(); // refresh the execution pane + } + } + } + /** + * Not pertinent for this one + */ + @Override + public void remove(String id) { + } + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java b/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java new file mode 100644 index 0000000..5b3d536 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/HistoryPane.java @@ -0,0 +1,270 @@ +/* + * StatusPane.java + * + * Created on March 20, 2001, 3:30 PM + */ + +package com.c2kernel.gui.tabs; + +/** + * @author abranson + * @version + */ +import java.awt.GridBagConstraints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.events.Event; +import com.c2kernel.events.History; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/** + * Pane to display all work orders that this agent can execute, and activate + * them on request from the user. Subscribes to NodeItem for WorkOrder objects. + * @version $Revision: 1.22 $ $Date: 2005/04/26 06:48:13 $ + * @author $Author: abranson $ + */ +public class HistoryPane extends EntityTabPane implements ActionListener, EntityProxyObserver { + + History history; + HistoryTableModel model; + JTable eventTable; + JButton startButton = new JButton("<<"); + JButton prevButton = new JButton("<"); + JButton nextButton = new JButton(">"); + JButton endButton = new JButton(">>"); + public static final int SIZE = 30; + int currentSize = SIZE; + + public HistoryPane() { + super("History", "Event History"); + initPanel(); + + // add buttons + Box navBox = Box.createHorizontalBox(); + navBox.add(startButton); navBox.add(prevButton); + navBox.add(nextButton); navBox.add(endButton); + + // setup buttons + //startButton.setEnabled(false); nextButton.setEnabled(false); + //prevButton.setEnabled(false); endButton.setEnabled(false); + startButton.setActionCommand("start"); + startButton.addActionListener(this); + prevButton.setActionCommand("prev"); + prevButton.addActionListener(this); + nextButton.setActionCommand("next"); + nextButton.addActionListener(this); + endButton.setActionCommand("end"); + endButton.addActionListener(this); + getGridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill=GridBagConstraints.NONE; + c.weightx=0; c.weighty=0; + gridbag.setConstraints(navBox, c); + add(navBox); + + + // Create table + eventTable = new JTable(); + JScrollPane eventScroll= new JScrollPane(eventTable); + c.weightx = 1.0; c.weighty = 1.0; + c.fill = GridBagConstraints.BOTH; c.gridy++; + gridbag.setConstraints(eventScroll, c); + add(eventScroll); + + } + + @Override + public void reload() { + history.clear(); + jumpToEnd(); + } + + @Override + public void run() { + Thread.currentThread().setName("History Pane Builder"); + try { + history = (History)sourceEntity.getEntity().getObject(ClusterStorage.HISTORY); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.HISTORY, false)); + } catch (ObjectNotFoundException e) { + Logger.error(e); + } + model = new HistoryTableModel(); + eventTable.setModel(model); + jumpToEnd(); + } + + public void jumpToEnd() { + int lastEvent = history.getLastId(); + int firstEvent = 0; currentSize = SIZE; + if (lastEvent > currentSize) firstEvent = lastEvent - currentSize + 1; + if (lastEvent < currentSize) currentSize = lastEvent + 1; + Logger.msg(5, "HistoryPane.run() - init table start "+firstEvent+" for "+currentSize); + model.setView(firstEvent, currentSize); + } + + @Override + public void add(Event contents) { + jumpToEnd(); + } + + @Override + public void remove(String id) { + // don't have to deal with this normally + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("end")) { + jumpToEnd(); + return; + } + + int lastEvent = history.getLastId(); + int startEvent = model.getStartId(); + if (e.getActionCommand().equals("start")) { + currentSize = SIZE; + startEvent = 0; + } + + else if (e.getActionCommand().equals("prev")) { + currentSize = SIZE; + startEvent-=currentSize; + if (startEvent<0) startEvent = 0; + } + else if (e.getActionCommand().equals("next")) { + currentSize = SIZE; + startEvent+=currentSize; + if (startEvent > lastEvent) + startEvent = lastEvent - currentSize +1; + } + else { // unknown action + return; + } + + model.setView(startEvent, currentSize); + } + + private class HistoryTableModel extends AbstractTableModel { + Event[] event; + Integer[] ids; + int loaded = 0; + int startId = 0; + + public HistoryTableModel() { + event = new Event[0]; + ids = new Integer[0]; + } + + public int getStartId() { + return startId; + } + + public void setView(int startId, int size) { + event = new Event[size]; + ids = new Integer[size]; + this.startId = startId; + for (int i=0; i getColumnClass(int columnIndex) { + switch(columnIndex) { + case 0: + return Integer.class; + default: + return String.class; + } + } + + /** + * @see javax.swing.table.TableModel#getColumnCount() + */ + @Override + public int getColumnCount() { + return 6; + } + + /** + * @see javax.swing.table.TableModel#getColumnName(int) + */ + @Override + public String getColumnName(int columnIndex) { + switch(columnIndex) { + case 0: return Language.translate("ID"); + case 1: return Language.translate("Activity"); + case 2: return Language.translate("Transition"); + case 3: return Language.translate("Date"); + case 4: return Language.translate("Agent Name"); + case 5: return Language.translate("Agent Role"); + default: return ""; + } + } + + /** + * @see javax.swing.table.TableModel#getRowCount() + */ + @Override + public int getRowCount() { + return loaded; + } + + /** + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (event.length <= rowIndex || event[rowIndex] == null) + return ""; + try { + switch (columnIndex) { + case 0: return ids[rowIndex]; + case 1: return event[rowIndex].getStepName(); + case 2: return Transitions.getTransitionName(event[rowIndex].getTransition()); + case 3: return event[rowIndex].getTimeString(); + case 4: return event[rowIndex].getAgentName(); + case 5: return event[rowIndex].getAgentRole(); + default: return ""; + } + } catch (Exception e) { + return null; + } + } + + /** + * @see javax.swing.table.TableModel#isCellEditable(int, int) + */ + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + } + + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java b/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java new file mode 100644 index 0000000..8f047ca --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/JTabbedPaneWithCloseIcons.java @@ -0,0 +1,96 @@ +package com.c2kernel.gui.tabs; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.Icon; +import javax.swing.JTabbedPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import com.c2kernel.gui.EntityDetails; + +/** + * @author Developpement + * + * Allows a close icone in JTabbePane + */ +public class JTabbedPaneWithCloseIcons extends JTabbedPane implements MouseListener, ChangeListener +{ + /** + * + */ + public JTabbedPaneWithCloseIcons() + { + super(); + addMouseListener(this); + addChangeListener(this); + } + /** + * @see javax.swing.JTabbedPane#addTab(String, Icon, Component, String) + */ + @Override + public void addTab(String title, Icon arg2, Component component, String arg3) + { + super.addTab(title, new CloseTabIcon(arg2), component, arg3); + } + /** + * @see java.awt.event.MouseListener#mouseClicked(MouseEvent) + */ + @Override + public void mouseClicked(MouseEvent e) + { + int tabNumber = getUI().tabForCoordinate(this, e.getX(), e.getY()); + Component cp = null; + if (tabNumber < 0) + return; + Rectangle rect = ((CloseTabIcon) getIconAt(tabNumber)).getBounds(); + if (rect.contains(e.getX(), e.getY())||(e.getModifiers()& InputEvent.CTRL_MASK) != 0) + { //the tab is being closed + cp = this.getComponent(tabNumber); + //if (getComponentCount() != 1) + if (cp instanceof EntityDetails) + { + ((EntityDetails) cp).closeTab(); + remove(cp); + } + } + stateChanged(new ChangeEvent(this)); + } + /** + * @see java.awt.event.MouseListener#mouseEntered(MouseEvent) + */ + @Override + public void mouseEntered(MouseEvent e) + { + } + /** + * @see java.awt.event.MouseListener#mouseExited(MouseEvent) + */ + @Override + public void mouseExited(MouseEvent e) + { + } + /** + * @see java.awt.event.MouseListener#mousePressed(MouseEvent) + */ + @Override + public void mousePressed(MouseEvent e) + { + } + /** + * @see java.awt.event.MouseListener#mouseReleased(MouseEvent) + */ + @Override + public void mouseReleased(MouseEvent e) + { + } + @Override + public void stateChanged(ChangeEvent e) + { + if (getSelectedComponent()!= null) + ((EntityDetails) getSelectedComponent()).refresh(); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/JobListPane.java b/src/main/java/com/c2kernel/gui/tabs/JobListPane.java new file mode 100644 index 0000000..619a589 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/JobListPane.java @@ -0,0 +1,312 @@ +/* + * StatusPane.java + * + * Created on March 20, 2001, 3:30 PM + */ + +package com.c2kernel.gui.tabs; + +/** + * @author abranson + * @version + */ +import java.awt.GridBagConstraints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.Iterator; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JOptionPane; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.agent.JobList; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/** + * Pane to display all work orders that this agent can execute, and activate + * them on request from the user. Subscribes to NodeItem for WorkOrder objects. + * @version $Revision: 1.4 $ $Date: 2004/10/21 08:02:21 $ + * @author $Author: abranson $ + */ +public class JobListPane extends EntityTabPane implements ActionListener, EntityProxyObserver { + + JobList joblist; + JoblistTableModel model; + JTable eventTable; + JButton startButton = new JButton("<<"); + JButton prevButton = new JButton("<"); + JButton nextButton = new JButton(">"); + JButton endButton = new JButton(">>"); + public static final int SIZE = 30; + int currentSize = SIZE; + + public JobListPane() { + super("Job List", "Agent Job List"); + initPanel(); + + // add buttons + Box navBox = Box.createHorizontalBox(); + navBox.add(startButton); navBox.add(prevButton); + navBox.add(nextButton); navBox.add(endButton); + + // setup buttons + //startButton.setEnabled(false); nextButton.setEnabled(false); + //prevButton.setEnabled(false); endButton.setEnabled(false); + startButton.setActionCommand("start"); + startButton.addActionListener(this); + prevButton.setActionCommand("prev"); + prevButton.addActionListener(this); + nextButton.setActionCommand("next"); + nextButton.addActionListener(this); + endButton.setActionCommand("end"); + endButton.addActionListener(this); + getGridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill=GridBagConstraints.NONE; + c.weightx=0; c.weighty=0; + gridbag.setConstraints(navBox, c); + add(navBox); + + + // Create table + eventTable = new JTable(); + JScrollPane eventScroll= new JScrollPane(eventTable); + c.weightx = 1.0; c.weighty = 1.0; + c.fill = GridBagConstraints.BOTH; c.gridy++; + gridbag.setConstraints(eventScroll, c); + add(eventScroll); + + // detect double clicked jobs + eventTable.addMouseListener(new JobListMouseListener()); + } + + @Override + public void reload() { + joblist.clear(); + jumpToEnd(); + } + + @Override + public void run() { + Thread.currentThread().setName("Joblist Pane Builder"); + try { + joblist = (JobList)sourceEntity.getEntity().getObject(ClusterStorage.JOB); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.JOB, false)); + } catch (ObjectNotFoundException e) { + Logger.error(e); + } + model = new JoblistTableModel(joblist); + eventTable.setModel(model); + jumpToEnd(); + } + + + public void jumpToEnd() { + int lastEvent = joblist.getLastId(); + int firstEvent = 0; currentSize = SIZE; + if (lastEvent > currentSize) firstEvent = lastEvent - currentSize + 1; + if (lastEvent < currentSize) currentSize = lastEvent + 1; + Logger.msg(5, "JobListPane.run() - init table start "+firstEvent+" for "+currentSize); + model.setView(firstEvent, currentSize); + } + + @Override + public void add(Job contents) { + reload(); + } + + @Override + public void remove(String id) { + reload(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("end")) { + jumpToEnd(); + return; + } + + int lastEvent = joblist.getLastId(); + int startEvent = model.getStartId(); + if (e.getActionCommand().equals("start")) { + currentSize = SIZE; + startEvent = 0; + } + + else if (e.getActionCommand().equals("prev")) { + currentSize = SIZE; + startEvent-=currentSize; + if (startEvent<0) startEvent = 0; + } + else if (e.getActionCommand().equals("next")) { + currentSize = SIZE; + startEvent+=currentSize; + if (startEvent > lastEvent) + startEvent = lastEvent - currentSize +1; + } + else { // unknown action + return; + } + + model.setView(startEvent, currentSize); + } + + private class JoblistTableModel extends AbstractTableModel { + Job[] job; + Integer[] ids; + String[] itemNames; + int loaded = 0; + int startId = 0; + + public JoblistTableModel(JobList joblist) { + job = new Job[0]; + ids = new Integer[0]; + } + + public int getStartId() { + return startId; + } + + public void setView(int startId, int size) { + job = new Job[size]; + ids = new Integer[size]; + itemNames = new String[size]; + this.startId = startId; + int count = 0; + for (Iterator i = joblist.keySet().iterator(); i.hasNext();) { + Integer thisJobId = new Integer((String)i.next()); + if (count >= startId) { + int idx = count-startId; + ids[idx] = thisJobId; + job[idx] = joblist.getJob(thisJobId.intValue()); + itemNames[idx] = "Item Not Found"; + try { + itemNames[idx] = ((Property)Gateway.getStorage().get(job[count-startId].getItemSysKey(), ClusterStorage.PROPERTY+"/Name", null)).getValue(); + } catch (Exception ex) { + Logger.error(ex); + } + + } + count++; + loaded = count-startId; + if (count > (startId + size)) break; + } + fireTableStructureChanged(); + } + /** + * @see javax.swing.table.TableModel#getColumnClass(int) + */ + @Override + public Class getColumnClass(int columnIndex) { + switch(columnIndex) { + case 0: + return Integer.class; + default: + return String.class; + } + } + + /** + * @see javax.swing.table.TableModel#getColumnCount() + */ + @Override + public int getColumnCount() { + return 4; + } + + /** + * @see javax.swing.table.TableModel#getColumnName(int) + */ + @Override + public String getColumnName(int columnIndex) { + switch(columnIndex) { + case 0: return Language.translate("ID"); + case 1: return Language.translate("Subject"); + case 2: return Language.translate("Activity"); + case 3: return Language.translate("Transition"); + default: return ""; + } + } + + /** + * @see javax.swing.table.TableModel#getRowCount() + */ + @Override + public int getRowCount() { + return loaded; + } + + /** + * @see javax.swing.table.TableModel#getValueAt(int, int) + */ + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (job.length <= rowIndex || job[rowIndex] == null) + return ""; + try { + switch (columnIndex) { + case 0: return ids[rowIndex]; + case 1: return itemNames[rowIndex]; + case 2: return job[rowIndex].getStepName(); + case 3: return Transitions.getTransitionName(job[rowIndex].getPossibleTransition()); + default: return ""; + } + } catch (Exception e) { + return null; + } + } + + /** + * @see javax.swing.table.TableModel#isCellEditable(int, int) + */ + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + public Job getJobAtRow(int rowIndex) { + return job[rowIndex]; + } + + } + + private class JobListMouseListener extends MouseAdapter { + + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + if (e.getClickCount() == 2) { + Job selectedJob = model.getJobAtRow(eventTable.getSelectedRow()); + try { + MainFrame.itemFinder.pushNewKey(selectedJob.getItemProxy().getName()); + } catch (Exception ex) { + Logger.error(ex); + JOptionPane.showMessageDialog(null, "No Item Found", "Job references an unknown item", JOptionPane.ERROR_MESSAGE); + } + } + } + } + + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java b/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java new file mode 100644 index 0000000..2411296 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/PropertiesPane.java @@ -0,0 +1,200 @@ +/* + * StatusPane.java + * + * Created on March 20, 2001, 3:30 PM + */ + +package com.c2kernel.gui.tabs; + +/** + * @author abranson + * @version + */ +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.data.NodeAgent; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +/** + * Pane to display all work orders that this agent can execute, and activate + * them on request from the user. Subscribes to NodeItem for Property objects. + * @version $Revision: 1.44 $ $Date: 2005/08/31 07:21:20 $ + * @author $Author: abranson $ + */ +public class PropertiesPane extends EntityTabPane implements EntityProxyObserver, ActionListener { + + Box propertyBox; + boolean subbed = false; + HashMap loadedProps = new HashMap(); + JLabel domTitle; + DomainPathAdmin domAdmin; + + public PropertiesPane() { + super("Properties", "Properties"); + initPanel(); + + // Create box container for properties + getGridBagConstraints(); + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.NONE; + c.weightx = 1.0; c.weighty = 2.0; + propertyBox = Box.createVerticalBox(); + gridbag.setConstraints(propertyBox, c); + add(propertyBox); + if (MainFrame.isAdmin) { // edit dompath + c.gridy++; + c.fill = GridBagConstraints.NONE; + c.weighty=0.0; + domTitle = new JLabel("Domain Paths", titleIcon, SwingConstants.LEFT); + domTitle.setFont(titleFont); + domTitle.setForeground(headingColor); + gridbag.setConstraints(domTitle, c); + add(domTitle); + + c.gridy++; + c.fill = GridBagConstraints.BOTH; + c.weighty=1.0; + domAdmin = new DomainPathAdmin(); + gridbag.setConstraints(domAdmin, c); + add(domAdmin); + + + if ("true".equals(Gateway.getProperty("EnableItemErase"))) { + c.gridy++; + c.fill = GridBagConstraints.NONE; + JButton eraseButton = new JButton(Language.translate("Erase!")); + eraseButton.addActionListener(this); + eraseButton.setActionCommand("Erase Item"); + gridbag.setConstraints(eraseButton, c); + add(eraseButton); + } + } + } + + @Override + public void reload() { + Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.PROPERTY); + loadedProps = new HashMap(); + initForEntity(sourceEntity); + } + + @Override + public void run() { + Thread.currentThread().setName("Property Pane Builder"); + if (sourceEntity instanceof NodeAgent) { + remove(domAdmin); + remove(domTitle); + } + else if (domAdmin != null) + domAdmin.setEntity((ItemProxy)sourceEntity.getEntity()); + propertyBox.removeAll(); + propertyBox.add(Box.createGlue()); + revalidate(); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.PROPERTY, true)); + + } + /** + * + */ + @Override + public void add(Property newProp) { + JLabel propLabel = loadedProps.get(newProp.getName()); + if (propLabel == null) { // new prop + JPanel summaryPanel = new JPanel(new GridLayout(0,2)); + summaryPanel.add(new JLabel(Language.translate(newProp.getName()) + ":")); + Box valueBox = Box.createHorizontalBox(); + propLabel = new JLabel(newProp.getValue()); + loadedProps.put(newProp.getName(), propLabel); + valueBox.add(propLabel); + if (MainFrame.isAdmin) { + JButton editButton = new JButton("..."); + editButton.setMargin(new Insets(0,0,0,0)); + editButton.setActionCommand(newProp.getName()); + editButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e){ + String oldVal = loadedProps.get(e.getActionCommand()).getText(); + String newVal = (String)JOptionPane.showInputDialog(null, "Enter new value for "+e.getActionCommand(), "Edit Property", + JOptionPane.QUESTION_MESSAGE, null, null, oldVal); + if (newVal!=null && !(newVal.equals(oldVal))) { + try { + ((ItemProxy)sourceEntity.getEntity()).setProperty(MainFrame.userAgent, e.getActionCommand(), newVal); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + } + }); + valueBox.add(Box.createVerticalStrut(7)); + valueBox.add(editButton); + + } + summaryPanel.add(valueBox); + propertyBox.add(Box.createVerticalStrut(7)); + propertyBox.add(summaryPanel); + } + propLabel.setText(newProp.getValue()); + revalidate(); + } + + @Override + public void remove(String id) { + String propName = id.substring(id.lastIndexOf("/")+1); + JLabel propbox = loadedProps.get(propName); + if (propbox!= null) propbox.setText("DELETED"); + revalidate(); + } + + @Override + public void actionPerformed(ActionEvent e) { + String[] params; + String predefStep; + + if (JOptionPane.showConfirmDialog(this, + "Are you sure?", + e.getActionCommand(), + JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return; + + if (e.getActionCommand().equals("Erase Item")) { + params = new String[0]; + predefStep = "Erase"; + } + else + return; + + try { + MainFrame.userAgent.execute((ItemProxy)sourceEntity.getEntity(), predefStep, params); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java b/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java new file mode 100644 index 0000000..52c9cb3 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/ViewpointPane.java @@ -0,0 +1,515 @@ + +package com.c2kernel.gui.tabs; +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.events.Event; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +public class ViewpointPane extends EntityTabPane implements ItemListener, ActionListener, EntityProxyObserver { + + JComboBox schemas; + JComboBox views; + JComboBox events; + JLabel eventDetails; + JButton exportButton; + JButton viewButton; + + ArrayList schemaList; + ArrayList viewpointList; + ArrayList eventList; + String currentSchema = null; + Outcome currentOutcome = null; + OutcomeHandler thisOutcome; + boolean suspendSelection = false; + + JPanel dataView = new JPanel(new GridLayout(1,1)); + + public ViewpointPane() { + + super("Data Viewer", "Outcome Browser"); + initialize(); + } + + public void initialize() { + initPanel(); + + getGridBagConstraints(); + + c.gridx = 0; c.gridy = 1; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.HORIZONTAL; + c.ipadx = 5; c.weightx = 1.0; + c.ipady = 5; + + // Set up view box + + Box viewBox = Box.createHorizontalBox(); + + JLabel label = new JLabel(Language.translate("Outcome Type")+":", SwingConstants.LEFT); + viewBox.add(label); + viewBox.add(Box.createHorizontalStrut(7)); + + schemas = new JComboBox(); + viewBox.add(schemas); + viewBox.add(Box.createHorizontalGlue()); + schemas.addItemListener(this); + + label = new JLabel(Language.translate("View")+":", SwingConstants.LEFT); + viewBox.add(label); + viewBox.add(Box.createHorizontalStrut(7)); + + views = new JComboBox(); + viewBox.add(views); + viewBox.add(Box.createHorizontalGlue()); + views.addItemListener(this); + + gridbag.setConstraints(viewBox, c); + this.add(viewBox); + + // Set up event details box + c.gridy++; + Box eventBox = Box.createHorizontalBox(); + + label = new JLabel(Language.translate("Event")+":", SwingConstants.LEFT); + eventBox.add(label); + eventBox.add(Box.createHorizontalStrut(7)); + + events = new JComboBox(); + eventBox.add(events); + eventBox.add(Box.createHorizontalStrut(7)); + events.addItemListener(this); + + eventDetails = new JLabel(); + eventBox.add(eventDetails); + eventBox.add(Box.createHorizontalGlue()); + + if (MainFrame.isAdmin) { + viewButton = new JButton(Language.translate("Write View")); + viewButton.setMargin(new Insets(0, 0, 0, 0)); + viewButton.setActionCommand("setview"); + eventBox.add(viewButton); + eventBox.add(Box.createHorizontalStrut(14)); + viewButton.addActionListener(this); + } + + exportButton = new JButton(Language.translate("Export")); + exportButton.setMargin(new Insets(0, 0, 0, 0)); + exportButton.setActionCommand("export"); + exportButton.addActionListener(this); + eventBox.add(exportButton); + + gridbag.setConstraints(eventBox, c); + this.add(eventBox); + + // data pane + c.gridx = 0; c.gridy = 3; + c.anchor = GridBagConstraints.NORTHWEST; c.fill = GridBagConstraints.BOTH; + c.weighty = 1.0; c.weightx = 1.0; + gridbag.setConstraints(dataView, c); + this.add(dataView); + } + + @Override + public void reload() { + // reset boxes + schemas.removeAllItems(); + views.removeAllItems(); + events.removeAllItems(); + eventDetails.setText(""); + + clearView(); + + // reload + initForEntity(sourceEntity); + } + + @Override + public void run() { + Thread.currentThread().setName("Viewpoint Pane Builder"); + //Local object subscriptions + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.VIEWPOINT, false)); + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.OUTCOME, false)); + clearView(); + schemas.addItem("--"); + currentSchema = null; + schemaList = new ArrayList(); + try { + String outcomeTypes = sourceEntity.getEntity().queryData(ClusterStorage.VIEWPOINT+"/all"); + StringTokenizer tok = new StringTokenizer(outcomeTypes, ","); + while (tok.hasMoreTokens()) { + String thisType = tok.nextToken(); + schemas.addItem(thisType); + schemaList.add(thisType); + } + } catch (Exception e) { + Logger.msg(2, "No viewpoints found"); + } + } + + @Override + public void itemStateChanged(ItemEvent e) { + + Object selectedItem = e.getItem(); + if (e.getStateChange() == ItemEvent.DESELECTED) return; + if (suspendSelection) return; + if (e.getItem().equals("--")) return; + + if (e.getItemSelectable() == schemas) + switchSchema((String)selectedItem); + else if (e.getItemSelectable() == views) + switchView((Viewpoint)selectedItem); + else if (e.getItemSelectable() == events) + showEvent((EventItem)selectedItem); + } + + public void switchSchema(String schemaName) { + clearView(); + suspendSelection = true; + views.removeAllItems(); + events.removeAllItems(); + viewpointList = new ArrayList(); + eventList = new ArrayList(); + + currentSchema = schemaName; + + try { + // populate views + String viewNames = sourceEntity.getEntity().queryData(ClusterStorage.VIEWPOINT+"/"+schemaName+"/all"); + StringTokenizer tok = new StringTokenizer(viewNames, ","); + Viewpoint lastView = null; + while(tok.hasMoreTokens()) { + String viewName = tok.nextToken(); + Viewpoint thisView = (Viewpoint)sourceEntity.getEntity().getObject(ClusterStorage.VIEWPOINT+"/"+schemaName+"/"+viewName); + views.addItem(thisView); + if (lastView == null) lastView = thisView; + if (thisView.getName().equals("last")) //select + lastView = thisView; + viewpointList.add(thisView); + } + + String ocVersions = sourceEntity.getEntity().queryData(ClusterStorage.OUTCOME+"/"+schemaName+"/all"); + tok = new StringTokenizer(ocVersions, ","); + while(tok.hasMoreTokens()) { + int schemaVersion = Integer.parseInt(tok.nextToken()); + String ocEvents = sourceEntity.getEntity().queryData(ClusterStorage.OUTCOME+"/"+schemaName+"/"+schemaVersion+"/all"); + StringTokenizer tok2 = new StringTokenizer(ocEvents, ","); + while(tok2.hasMoreTokens()) { + int eventId = Integer.parseInt(tok2.nextToken()); + EventItem newEvent = new EventItem(eventId, schemaVersion); + for (Viewpoint thisView : viewpointList) { + if (thisView.getEventId() == eventId) + newEvent.addView(thisView.getName()); + } + eventList.add(newEvent); + } + Collections.sort(eventList, new Comparator() { + @Override + public int compare(EventItem o1, EventItem o2) { + return o1.compareTo(o2); + } + }); + for (EventItem eventItem : eventList) + events.addItem(eventItem); + } + + if (lastView != null) { + suspendSelection = false; + views.setSelectedItem(lastView); + switchView(lastView); + } + + } catch (Exception e) { + Logger.error(e); + JOptionPane.showMessageDialog(this, + "The data structures of this item are incorrect.\nPlease contact your administrator.", + "Viewpoint Error" , JOptionPane.ERROR_MESSAGE); + } + suspendSelection = false; + } + + public void switchView(Viewpoint newView) { + for (EventItem thisEvent : eventList) { + if (thisEvent.eventId == newView.getEventId()) { + suspendSelection = true; + events.setSelectedItem(thisEvent); + showEvent(thisEvent); + suspendSelection = false; + break; + } + } + } + + public void showEvent(EventItem thisEvent) { + eventDetails.setText(thisEvent.getEventDesc()); + try { + setView((Outcome)sourceEntity.getEntity().getObject( + ClusterStorage.OUTCOME+"/"+currentSchema+"/"+thisEvent.schemaVersion+"/"+thisEvent.eventId)); + } catch (Exception ex) { + Logger.error(ex); + JOptionPane.showMessageDialog(this, + "Could not retrieve requested outcome.\nPlease contact your administrator.", + "Viewpoint Error" , JOptionPane.ERROR_MESSAGE); + } + } + + public void setView(Outcome data) { + Logger.msg(6, "ViewpointPane: got outcome type: "+data.getSchemaType()+" version: "+data.getSchemaVersion()); + String schema; + currentOutcome = data; + dataView.removeAll(); + String error = null; + try { + schema = LocalObjectLoader.getSchema(data.getSchemaType(), data.getSchemaVersion()).schema; + thisOutcome = EntityTabPane.getOutcomeHandler(data.getSchemaType(), data.getSchemaVersion()); + thisOutcome.setDescription(schema); + thisOutcome.setOutcome(data.getData()); + thisOutcome.setReadOnly(true); + Thread builder = new Thread(thisOutcome); + builder.start(); + dataView.add(thisOutcome.getPanel()); + exportButton.setEnabled(true); + if (viewButton!=null) viewButton.setEnabled(true); + return; + } catch (ObjectNotFoundException ex) { + error = "Schema not found"; + } catch (OutcomeException ex) { + error = "Outcome was not valid. See log for details: "+ex.getMessage(); + Logger.error(ex); + } + + dataView.add(new JLabel(error)); + } + + public void clearView() { + dataView.removeAll(); + exportButton.setEnabled(false); + if (viewButton!=null) viewButton.setEnabled(false); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("export") && currentOutcome != null) + saveOutcomeToFile(); + if (e.getActionCommand().equals("setview") && currentOutcome != null) + overrideView(); + } + + private void saveOutcomeToFile() { + + MainFrame.xmlChooser.setSelectedFile(new File(currentOutcome.getSchemaType()+".xml")); + int returnVal = MainFrame.xmlChooser.showSaveDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File targetFile = MainFrame.xmlChooser.getSelectedFile(); + if (!(targetFile.getAbsolutePath().endsWith(".xml"))) + targetFile = new File(targetFile.getAbsolutePath()+".xml"); + + Logger.msg(2, "ViewpointPane.actionPerformed() - Exporting outcome to file " + targetFile.getName()); + try { + thisOutcome.export(targetFile); + } + catch (Exception ex) { + Logger.error(ex); + Logger.exceptionDialog(ex); + } + } + + } + + private void overrideView() { + + Viewpoint oldView = (Viewpoint)views.getSelectedItem(); + EventItem newEvent = (EventItem)events.getSelectedItem(); + + if (oldView.getEventId() == newEvent.eventId) { + JOptionPane.showMessageDialog(this, + "View '"+oldView.getName()+"' is already set to event "+newEvent.eventId, + "Viewpoint Already Set" , JOptionPane.ERROR_MESSAGE); + return; + } + + if (JOptionPane.showConfirmDialog(this, + "Are you sure you want to set the '"+oldView.getName()+ + "' view to event " + newEvent.eventId+ "?", + "Overwrite view", + JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) + return; + + oldView.setEventId(newEvent.eventId); + try { + String[] predefParams = new String[1]; + predefParams[0] = CastorXMLUtility.marshall(oldView); + MainFrame.userAgent.execute((ItemProxy)sourceEntity.getEntity(), "AddC2KObject", predefParams); + } catch (Exception e) { + Logger.error(e); + Logger.exceptionDialog(e); + } + } + + @Override + public void add(C2KLocalObject contents) { + if (contents instanceof Viewpoint) + addViewpoint((Viewpoint)contents); + else if (contents instanceof Outcome) + addOutcome((Outcome)contents); + + } + + public void addViewpoint(Viewpoint newView) { + String schemaName = newView.getSchemaName(); + Logger.msg(3, "Viewpoint "+newView.getName()+" now points to "+newView.getEventId()); + if (!(schemaList.contains(schemaName))) { + schemaList.add(schemaName); + schemas.addItem(schemaName); + return; + } + + + if (!(schemaName.equals(schemas.getSelectedItem()))) + return; + + for (EventItem thisEvent : eventList) { + if (thisEvent.eventId == newView.getEventId()) + thisEvent.addView(newView.getName()); + else + thisEvent.removeView(newView.getName()); + } + + boolean isSelected = false; + for (Viewpoint thisView : viewpointList) { + if (thisView.getName().equals(newView.getName())) { + isSelected = thisView.equals(views.getSelectedItem()); + views.removeItem(thisView); + viewpointList.remove(thisView); + break; + } + } + + views.addItem(newView); + viewpointList.add(newView); + if (isSelected) { + views.setSelectedItem(newView); + } + + } + + public void addOutcome(Outcome contents) { + if (!(contents.getSchemaType().equals(currentSchema))) // not interested + return; + Logger.msg(3, "Adding event "+contents.getID()); + EventItem newEvent = new EventItem(contents.getID(), contents.getSchemaVersion()); + eventList.add(newEvent); + events.addItem(newEvent); + } + + @Override + public void remove(String id) { + // we don't really remove viewpoints + } + + class EventItem implements Comparable { + public int eventId; + public int schemaVersion; + public ArrayList viewNames = new ArrayList(); + public String viewList = ""; + + public EventItem(int eventId, int schemaVersion) { + this.eventId = eventId; + this.schemaVersion = schemaVersion; + } + + public void addView(String viewName) { + if (!(viewNames.contains(viewName))) { + viewNames.add(viewName); + buildViewLabel(); + } + } + + public void removeView(String viewName) { + viewNames.remove(viewName); + buildViewLabel(); + } + + private void buildViewLabel() { + if (viewNames.size() == 0) { + viewList = ""; + return; + } + + StringBuffer newLabel = new StringBuffer(" ("); + for (Iterator iter = viewNames.iterator(); iter.hasNext();) { + String viewName = iter.next(); + newLabel.append(viewName); + if (iter.hasNext()) + newLabel.append(", "); + } + + viewList = newLabel.append(")").toString(); + } + + @Override + public String toString() { + return eventId+viewList; + + } + + public String getEventDesc() { + try { + Event myEvent = (Event)sourceEntity.getEntity().getObject(ClusterStorage.HISTORY+"/"+eventId); + return (Language.translate("Recorded on")+" "+myEvent.getTimeString()+" "+ + Language.translate("by")+" "+myEvent.getAgentName()+" "+ + Language.translate("using schema v")+schemaVersion); + } catch (Exception ex) { + Logger.error(ex); + return ("Error retrieving event details"); + } + } + + @Override + public int compareTo(EventItem other) { + if (other.eventId < eventId) return 1; + if (other.eventId > eventId) return -1; + return 0; + } + } + + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java b/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java new file mode 100644 index 0000000..e4acd8d --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/WorkflowPane.java @@ -0,0 +1,286 @@ +package com.c2kernel.gui.tabs; +import java.awt.Cursor; +import java.awt.GridBagConstraints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JSplitPane; + +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.graph.layout.DefaultGraphLayoutGenerator; +import com.c2kernel.graph.model.EdgeFactory; +import com.c2kernel.graph.model.Selection; +import com.c2kernel.graph.model.VertexFactory; +import com.c2kernel.graph.view.EditorPanel; +import com.c2kernel.graph.view.VertexPropertyPanel; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lifecycle.instance.gui.model.WfEdgeFactory; +import com.c2kernel.lifecycle.instance.gui.model.WfGraphPanel; +import com.c2kernel.lifecycle.instance.gui.model.WfVertexFactory; +import com.c2kernel.lifecycle.instance.gui.model.WfVertexOutlineCreator; +import com.c2kernel.lifecycle.instance.gui.view.TransitionPanel; +import com.c2kernel.lifecycle.instance.gui.view.WfDirectedEdgeRenderer; +import com.c2kernel.lifecycle.instance.gui.view.WfVertexRenderer; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +public class WorkflowPane extends EntityTabPane implements EntityProxyObserver +{ + // Only for the purpose of loading and saving + protected Workflow mWorkflow = null; + boolean init = false; + TransitionPanel transPanel; + protected JButton mLoadButton = new JButton(Resource.findImage("graph/load.png")); + protected JButton mSaveButton = new JButton(Resource.findImage("graph/save.png")); + protected JButton mLayoutButton = new JButton(Resource.findImage("graph/autolayout.png")); + protected JButton mZoomOutButton = new JButton(Resource.findImage("graph/zoomout.png")); + protected JButton[] mOtherToolBarButtons; + // Workflow factories + protected EdgeFactory mWfEdgeFactory; + protected VertexFactory mWfVertexFactory; + // Graph editor panel + protected EditorPanel mEditorPanel; + // Objects to view/modify the properties of the selected activity + protected VertexPropertyPanel mPropertyPanel; + protected JSplitPane mSplitPane; + + // Graph editor panel + // Objects to view/modify the properties of the selected activity + public WorkflowPane() + { + super("Workflow", "Workflow Viewer"); + // Workflow factories + mWfEdgeFactory = new WfEdgeFactory(); + mWfVertexFactory = new WfVertexFactory(); + mZoomOutButton.setToolTipText(Language.translate("Zoom Out")); + mLayoutButton.setToolTipText(Language.translate("Auto Layout")); + mLoadButton.setToolTipText(Language.translate("Load")); + mSaveButton.setToolTipText(Language.translate("Save")); + mOtherToolBarButtons = new JButton[] { mZoomOutButton, mLayoutButton, mLoadButton, mSaveButton }; + + } + + protected void createListeners() + { + /** + * + */ + mLoadButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + loadWorkflow(); + } + }); + /** + * + */ + mSaveButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + setCursor(new Cursor(Cursor.WAIT_CURSOR)); + saveWorkflow(); + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + }); + /** + * + */ + mLayoutButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + DefaultGraphLayoutGenerator.layoutGraph(mEditorPanel.mGraphModelManager.getModel()); + } + }); + /** + * + */ + mZoomOutButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + mEditorPanel.mGraphModelManager.zoomOut(); + } + }); + } + /** + * Return a single ref on mEditorPanel + * + * @return EditorPanel + */ + public EditorPanel getEditorPanel() + { + if (mEditorPanel == null) + mEditorPanel = + new EditorPanel( + mWfEdgeFactory, + mWfVertexFactory, + new WfVertexOutlineCreator(), + true, + mOtherToolBarButtons, + new WfGraphPanel(new WfDirectedEdgeRenderer(), new WfVertexRenderer())); + return mEditorPanel; + } + public JSplitPane getJSplitPane() + { + if (mSplitPane == null) + { + mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, getEditorPanel(), getPropertyPanel()); + mSplitPane.setDividerSize(5); + mSplitPane.setDividerLocation(800); + } + return mSplitPane; + } + @Override + public void add(Workflow contents) + { + mWorkflow = contents; + addActivity((CompositeActivity) mWorkflow.search("workflow/domain")); + } + @Override + public void remove(String id) + { + } + protected void addActivity(CompositeActivity cAct) + { + // Resolve any undefined references in the workflow + mEditorPanel.mGraphModelManager.replace(cAct.getChildrenGraphModel()); + // Give the editor panel the edge and vertex types + mEditorPanel.updateVertexTypes(cAct.getWf().getVertexTypeNameAndConstructionInfo()); + mEditorPanel.updateEdgeTypes(cAct.getWf().getEdgeTypeNameAndConstructionInfo()); + mEditorPanel.enterSelectMode(); + mWfVertexFactory.setCreationContext(cAct); + } + @Override + public void run() + { + Thread.currentThread().setName("Workflow Pane Builder"); + if (!init) + { + getEditorPanel(); + createLayout(); + createListeners(); + mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager); + mEditorPanel.setEditable(MainFrame.isAdmin); + init = true; + } + sourceEntity.getEntity().subscribe(new MemberSubscription(this, ClusterStorage.LIFECYCLE, true)); + transPanel.setItem((ItemProxy) sourceEntity.getEntity()); + } + @Override + public void reload() + { + Gateway.getStorage().clearCache(sourceEntity.getSysKey(), ClusterStorage.LIFECYCLE); + initForEntity(sourceEntity); + } + protected void createLayout() + { + initPanel(); + // Add the editor pane + getGridBagConstraints().gridx = 0; + getGridBagConstraints().gridy = 1; + getGridBagConstraints().fill = GridBagConstraints.BOTH; + getGridBagConstraints().weighty = 2.0; + gridbag.setConstraints(getJSplitPane(), getGridBagConstraints()); + add(getJSplitPane()); + validate(); + } + protected void loadWorkflow() + { + File selectedFile = null; + int returnValue = MainFrame.xmlChooser.showOpenDialog(null); + switch (returnValue) + { + case JFileChooser.APPROVE_OPTION : + selectedFile = MainFrame.xmlChooser.getSelectedFile(); + try + { + String newWf = FileStringUtility.file2String(selectedFile); + add((Workflow) CastorXMLUtility.unmarshall(newWf)); + } + catch (Exception e) + { + e.printStackTrace(); + } + case JFileChooser.CANCEL_OPTION : + case JFileChooser.ERROR_OPTION : + default : + } + } + protected String marshall() throws Exception + { + return com.c2kernel.utils.CastorXMLUtility.marshall(mWorkflow.getWf()); + } + protected void saveWorkflow() + { + try + { + CompositeActivity cact = (CompositeActivity)mWorkflow.getWf().search("workflow/domain"); + MainFrame.userAgent.execute( + (ItemProxy)sourceEntity.getEntity(), + "ReplaceDomainWorkflow", + new String[] { com.c2kernel.utils.CastorXMLUtility.marshall(cact)}); + cact.getChildrenGraphModel().setSelection(new Selection(null,null,0,0,0,0)); + } + catch (Exception e) + { + Logger.error(e); + } + } + + public VertexPropertyPanel getPropertyPanel() + { + if (mPropertyPanel == null) { + setNewPropertyPanel(); + transPanel = new TransitionPanel(); + mPropertyPanel.createLayout(transPanel); + mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager); + mPropertyPanel.setEditable(MainFrame.isAdmin); + } + return mPropertyPanel; + } + + public void setNewPropertyPanel() + { + String wfPanelClass = Gateway.getProperty("WfPropertyPanel"); + if (wfPanelClass != null) + { + try + { + Class panelClass = Class.forName(wfPanelClass); + mPropertyPanel = (VertexPropertyPanel) panelClass.newInstance(); + return; + } + catch (Exception ex) + { + Logger.error("Could not load wf props panel:" + wfPanelClass); + Logger.error(ex); + } + } + mPropertyPanel = new VertexPropertyPanel(); + } + + @Override + public void control(String control, String msg) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java b/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java new file mode 100644 index 0000000..b6578bb --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/collection/AggregationView.java @@ -0,0 +1,90 @@ +package com.c2kernel.gui.tabs.collection; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JSplitPane; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.AggregationMember; +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.gui.model.AggregationVertexFactory; +import com.c2kernel.collection.gui.model.AggregationVertexOutlineCreator; +import com.c2kernel.collection.gui.view.AggregationMemberRenderer; +import com.c2kernel.collection.gui.view.PropertyPanel; +import com.c2kernel.collection.gui.view.SelectedMemberPanel; +import com.c2kernel.graph.view.EditorPanel; +import com.c2kernel.graph.view.GraphPanel; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Resource; +/** + * @version $Revision: 1.5 $ $Date: 2006/09/15 15:02:24 $ + * @author $Author: abranson $ + */ +public class AggregationView extends CollectionView +{ + protected JButton mSaveButton = new JButton(Resource.findImage("graph/save.png")); + protected JButton mHistoryButton = new JButton(Resource.findImage("graph/history.png")); + protected JButton[] mOtherToolBarButtons = { mSaveButton, mHistoryButton }; + // Graph editor panel + protected EditorPanel mEditorPanel; + // Objects to view/modify the properties of the selected activity + protected PropertyPanel mPropertyPanel; + protected JSplitPane mSplitPane; + private final AggregationVertexFactory mAggregationVertexFactory = new AggregationVertexFactory(); + private final AggregationMemberRenderer mAggregationMemberRenderer = new AggregationMemberRenderer(); + public AggregationView() + { + super(); + setLayout(new GridLayout(1,1)); + mPropertyPanel = new PropertyPanel(); + mEditorPanel = new EditorPanel(null, mAggregationVertexFactory, new AggregationVertexOutlineCreator(), false, mOtherToolBarButtons, new GraphPanel(null, mAggregationMemberRenderer)); + createLayout(); + createListeners(); + mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager); + mPropertyPanel.createLayout(new SelectedMemberPanel()); + mEditorPanel.setEditable(MainFrame.isAdmin); + } + + @Override + public void setCollection(Collection contents) + { + thisColl = contents; + Aggregation agg = (Aggregation)thisColl; + mPropertyPanel.setCollection(agg); + mAggregationMemberRenderer.setAggregation(agg); + mEditorPanel.mGraphModelManager.setModel(agg.getLayout()); + mEditorPanel.updateVertexTypes(agg.getVertexTypeNameAndConstructionInfo()); + mEditorPanel.enterSelectMode(); + mAggregationVertexFactory.setCreationContext(agg); + } + public void createLayout() + { + mSaveButton.setToolTipText(Language.translate("Save Layout Changes")); + mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mEditorPanel, mPropertyPanel); + mSplitPane.setDividerSize(5); + add(mSplitPane); + } + + protected void createListeners() + { + mSaveButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + saveCollection(); + } + }); + mHistoryButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent ae) + { + new CollectionHistoryWindow(item, (Aggregation)thisColl); + } + }); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java new file mode 100644 index 0000000..673f3ac --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionHistoryWindow.java @@ -0,0 +1,192 @@ +package com.c2kernel.gui.tabs.collection; + +import java.awt.HeadlessException; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +import com.c2kernel.collection.Aggregation; +import com.c2kernel.collection.Collection; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.EntityProxy; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.events.Event; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStep; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +public class CollectionHistoryWindow extends JFrame { + + JTable historyTable; + HistoryTableModel historyModel; + + public CollectionHistoryWindow(ItemProxy item, Aggregation coll) throws HeadlessException { + super("Collection History"); + historyModel = new HistoryTableModel(item, coll); + historyTable = new JTable(historyModel); + this.getContentPane().add(new JScrollPane(historyTable)); + historyTable.addMouseListener(new HistoryTableListener(item)); + this.pack(); + super.toFront(); + this.validate(); + this.setVisible(true); + } + + private class HistoryTableModel extends AbstractTableModel implements EntityProxyObserver { + + ItemProxy item; + ArrayList collEvents; + ArrayList collEventData; + Aggregation coll; + public HistoryTableModel(ItemProxy item, Aggregation coll) { + this.item = item; + this.coll = coll; + collEvents = new ArrayList(); + collEventData = new ArrayList(); + item.subscribe(new MemberSubscription(this, ClusterStorage.HISTORY, true)); + } + @Override + public int getColumnCount() { + return 4; + } + + @Override + public String getColumnName(int columnIndex) { + switch(columnIndex) { + case 0: return Language.translate("Date"); + case 1: return Language.translate("Operation"); + case 2: return Language.translate("Slot"); + case 3: return Language.translate("Child"); + default: return ""; + } + } + @Override + public int getRowCount() { + return collEvents.size(); + } + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Event ev = collEvents.get(rowIndex); + switch (columnIndex) { + case 0: + return ev.getTimeString(); + case 1: + if (ev.getStepName().equals("AssignItemToSlot")) + return "Item Assigned"; + else + return "Collection replaced"; + case 2: + if (ev.getStepName().equals("AssignItemToSlot")) + return ((String[])collEventData.get(rowIndex))[1]; + return ""; + case 3: + if (ev.getStepName().equals("AddC2KObject")) + return "Click to view"; + String name; + try { + EntityProxy childItem = Gateway.getProxyManager().getProxy(new EntityPath(Integer.parseInt(((String[])collEventData.get(rowIndex))[2]))); + name = childItem.getName(); + } catch (NumberFormatException e) { + name = "Invalid entity key: "+((String[])collEventData.get(rowIndex))[2]; + } catch (ObjectNotFoundException e) { + name = "Item deleted: "+((String[])collEventData.get(rowIndex))[2]; + } catch (InvalidEntityPathException e) { + name = "Invalid entity key: "+((String[])collEventData.get(rowIndex))[2]; + } + return name; + default: + return ""; + } + } + public Object getEventData(int row) { + return collEventData.get(row); + } + @Override + public void add(Event thisEv) { + if (thisEv.getStepName().equals("AssignItemToSlot") || thisEv.getStepName().equals("AddC2KObject")) { + String[] params; + try { + Outcome oc = (Outcome)item.getObject(ClusterStorage.OUTCOME+"/PredefinedStepOutcome/0/"+thisEv.getID()); + params = PredefinedStep.getDataList(oc.getData()); + } catch (ObjectNotFoundException ex) { return; } + if (thisEv.getStepName().equals("AssignItemToSlot")) { + if (params[0].equals(coll.getName())) + collEventData.add(params); + else return; + } + else { + Object obj; + try { + obj = CastorXMLUtility.unmarshall(params[0]); + } catch (Exception e) { + Logger.error(e); + return; + } + if (obj instanceof Collection) + collEventData.add(obj); + else return; + + } + } + else return; + collEvents.add(thisEv); + fireTableRowsInserted(collEvents.size()-1, collEvents.size()-1); + } + @Override + public void remove(String id) { } + @Override + public void control(String control, String msg) { + } + } + + private class HistoryTableListener extends MouseAdapter { + + ItemProxy item; + public HistoryTableListener(ItemProxy item) { + this.item = item; + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount()==2) { + int row = historyTable.getSelectedRow(); + Object data = historyModel.getEventData(row); + if (data instanceof Aggregation) { + showColl((Aggregation)data); + } + else { + String[] params = (String[])data; + try { + EntityProxy childItem = Gateway.getProxyManager().getProxy(new EntityPath(Integer.parseInt(params[2]))); + MainFrame.itemFinder.pushNewKey(childItem.getName()); + } catch (Exception ex) { } + } + } + } + public void showColl(Aggregation coll) { + JFrame newFrame = new JFrame(); + AggregationView newView = new AggregationView(); + newView.setCollection(coll); + newView.setItem(item); + newFrame.getContentPane().add(newView); + newFrame.pack(); + newFrame.toFront(); + newFrame.validate(); + newFrame.setVisible(true); + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java new file mode 100644 index 0000000..c698430 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/collection/CollectionView.java @@ -0,0 +1,49 @@ +package com.c2kernel.gui.tabs.collection; + +import javax.swing.JPanel; + +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2004/08/10 07:56:08 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + +public abstract class CollectionView extends JPanel { + + protected Collection thisColl; + protected ItemProxy item; + + public CollectionView() { + super(); + } + + public void setItem(ItemProxy entity) { + this.item = entity; + } + + public abstract void setCollection(Collection coll); + + protected void saveCollection() + { + try + { + String[] params = new String[1]; + params[0] = com.c2kernel.utils.CastorXMLUtility.marshall(thisColl); + MainFrame.userAgent.execute(item, "AddC2KObject", params); + } + catch (Exception e) + { + Logger.error(e); + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java b/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java new file mode 100644 index 0000000..e068bdc --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/collection/DependencyView.java @@ -0,0 +1,34 @@ +package com.c2kernel.gui.tabs.collection; +import java.awt.GridLayout; + +import javax.swing.JLabel; + +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.DependencyMember; +/** + * @version $Revision: 1.2 $ $Date: 2005/06/02 12:17:22 $ + * @author $Author: abranson $ + */ +public class DependencyView extends CollectionView +{ + // Objects to view/modify the properties of the selected activity + + public DependencyView() + { + super(); + setLayout(new GridLayout(1,1)); + createLayout(); + } + + @Override + public void setCollection(Collection contents) + { + thisColl = contents; + } + public void createLayout() + { + // TODO: design a nice dependency view, with property viewing and modification + add(new JLabel("Dependency view not yet implemented. Please browse the tree instead.")); + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java new file mode 100644 index 0000000..6a8f2f7 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityItem.java @@ -0,0 +1,55 @@ +package com.c2kernel.gui.tabs.execution; +import java.util.ArrayList; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.lifecycle.instance.stateMachine.States; + +public class ActivityItem { + public String stepPath; + public int state; + public String name; + ArrayList jobs = new ArrayList(); + + public ActivityItem() { + stepPath = ""; + state = -1; + name = "--"; + } + + public ActivityItem(Job thisJob) { + stepPath = thisJob.getStepPath(); + state = thisJob.getCurrentState(); + name = thisJob.getStepName(); + jobs.add(thisJob); + } + + public void addJob(Job newJob) { + jobs.add(newJob); + } + + public ArrayList getJobs() { + return jobs; + } + + public String getStepPath() { + return stepPath; + } + + @Override + public String toString() { + return name+(state>-1?" ("+States.getStateName(state)+")":""); + } + + @Override + public boolean equals(Object other) { + if (other instanceof ActivityItem) + return hashCode() == ((ActivityItem)other).hashCode(); + return false; + } + + @Override + public int hashCode() { + return stepPath.hashCode(); + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java new file mode 100644 index 0000000..707f311 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/execution/ActivityViewer.java @@ -0,0 +1,296 @@ +package com.c2kernel.gui.tabs.execution; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.ArrayList; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.EntityTabPane; +import com.c2kernel.gui.tabs.ExecutionPane; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +public class ActivityViewer extends JPanel implements Runnable { + + ItemProxy item; + Box outcomeButtons = Box.createHorizontalBox(); + OutcomeHandler outcomePanel; + JPanel outcomeView = new JPanel(new GridLayout(1,1)); + ActivityItem thisAct; + ArrayList requestButtons = new ArrayList(); + JLabel noOutcome = new JLabel(Language.translate("No outcome data is required for this activity")); + ExecutionPane parent; + JLabel status; + JComboBox executors; + JButton saveButton = new JButton("Save"); + JButton loadButton = new JButton("Load"); + GridBagLayout gridbag = new GridBagLayout(); + Job executingJob = null; + static JFileChooser chooser = new JFileChooser(); + static { + chooser.addChoosableFileFilter( + new javax.swing.filechooser.FileFilter() { + @Override + public String getDescription() { + return "XML Files"; + } + @Override + public boolean accept(File f) { + if (f.isDirectory() || (f.isFile() && f.getName().endsWith(".xml"))) { + return true; + } + return false; + } + }); + } + + public ActivityViewer (ActivityItem newAct, ItemProxy item, ExecutionPane parent){ + thisAct = newAct; + this.item = item; + this.parent = parent; + setLayout(gridbag); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx=0; c.gridy=1; c.weightx=1.0; c.weighty=0.0; + c.insets = new Insets(5,5,5,5); + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.HORIZONTAL; + +// activity title + JLabel actTitle = new JLabel(Language.translate("Activity")+": "+newAct.name); + actTitle.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(actTitle, c); + add(actTitle); + + Job firstJob = (thisAct.getJobs().get(0)); +// desc + String desc = firstJob.getDescription(); + if (desc != null && desc.length() > 0) { + Box descBox = Box.createHorizontalBox(); + + String chopDesc = null; + if(desc.length() >= 40) chopDesc = desc.substring(0,40); + else chopDesc = desc; + + descBox.add(new JLabel("Description: "+chopDesc)); + if (desc.length()>chopDesc.length()) { + descBox.add(new JLabel(" ...")); + descBox.add(Box.createHorizontalStrut(7)); + JButton descButton = new JButton("View"); + descButton.setMargin(new Insets(0,0,0,0)); + descButton.setActionCommand(desc); + descButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JTextArea descArea = new JTextArea(e.getActionCommand()); + descArea.setLineWrap(true); + descArea.setWrapStyleWord(true); + JScrollPane descScroll = new JScrollPane(descArea); + descScroll.setPreferredSize(new Dimension(400,150)); + JOptionPane.showMessageDialog(null, descScroll, "Activity Description", JOptionPane.PLAIN_MESSAGE); + } + }); + descBox.add(descButton); + } + + c.gridy++; + gridbag.setConstraints(descBox, c); + add(descBox); + } + + +// agentid + String roleName = firstJob.getAgentRole(); + if (roleName!= null && roleName.length()>0) { + c.gridy++; + JLabel role = new JLabel(Language.translate("Agent Role")+": "+roleName); + gridbag.setConstraints(role, c); + add(role); + } + + c.gridy++; + c.anchor = GridBagConstraints.EAST; + gridbag.setConstraints(outcomeButtons, c); + add(outcomeButtons); + + executors = MainFrame.getExecutionPlugins(); + if (executors.getItemCount() > 1) { + c.gridx++; + gridbag.setConstraints(executors, c); + add(executors); + c.gridx--; + } + + c.gridy++; + + status = new JLabel(Language.translate("Waiting for request")); + status.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(status, c); + add(status); + + c.gridx++; + Box fileBox = Box.createHorizontalBox(); + fileBox.add(saveButton); fileBox.add(Box.createHorizontalGlue()); fileBox.add(loadButton); + gridbag.setConstraints(fileBox, c); + add(fileBox); + saveButton.setEnabled(false); + loadButton.setEnabled(false); + c.gridx--; + c.gridwidth = 2; + boolean outcomeEmpty = true; + for (Object name2 : thisAct.getJobs()) { + Job thisJob = (Job)name2; + RequestButton newButton = new RequestButton(thisJob, this); + requestButtons.add(newButton); + outcomeButtons.add(newButton); + outcomeButtons.add(Box.createHorizontalStrut(5)); + + if (thisJob.isOutcomeUsed()) { + String schema; + if (outcomeEmpty) { + try { + schema = LocalObjectLoader.getSchema(thisJob.getSchemaType(), thisJob.getSchemaVersion()).schema; + outcomePanel = EntityTabPane.getOutcomeHandler(thisJob.getSchemaType(), thisJob.getSchemaVersion()); + outcomePanel.setReadOnly(false); + outcomePanel.setDescription(schema); + String outcomeString = thisJob.getOutcomeString(); + if ( outcomeString!= null && outcomeString.length() > 0) + outcomePanel.setOutcome(outcomeString); + outcomeView = outcomePanel.getPanel(); + } catch (ObjectNotFoundException ex) { + outcomeView.add(new JLabel(Language.translate("Schema not found:")+" "+thisJob.getSchemaType()+" v"+thisJob.getSchemaVersion())); + outcomePanel = null; + } catch (Exception ex) { + outcomeView.add(new JLabel(Language.translate("ERROR loading outcome editor: ") + +ex.getClass().getName()+" ("+ex.getMessage()+")")); + Logger.error(ex); + outcomePanel = null; + } + } + outcomeEmpty = false; + if (outcomePanel == null) newButton.setEnabled(false); + else { + saveButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + String output; + try { + output = outcomePanel.getOutcome(); + int returnVal = chooser.showSaveDialog(null); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File targetFile = chooser.getSelectedFile(); + if (!(targetFile.getAbsolutePath().endsWith(".xml"))) + targetFile = new File(targetFile.getAbsolutePath()+".xml"); + + Logger.msg(2, "ExecutionPane - Exporting outcome to file " + targetFile.getName()); + FileStringUtility.string2File(targetFile, output); + } + } catch (Exception ex) { + Logger.error(ex); + Logger.exceptionDialog(ex); + } + } + }); + saveButton.setEnabled(true); + + loadButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + try { + int returnVal = chooser.showOpenDialog(null); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File targetFile = chooser.getSelectedFile(); + + Logger.msg(2, "ViewpointPane.actionPerformed() - Reading outcome from file " + targetFile.getName()); + String outcome = FileStringUtility.file2String(targetFile); + outcomePanel.setOutcome(outcome); + new Thread(outcomePanel).start(); + } + } catch (Exception ex) { + Logger.error(ex); + Logger.exceptionDialog(ex); + } + } + }); + loadButton.setEnabled(true); + } + } + } + if (outcomeEmpty) + outcomeView.add(noOutcome); + c.gridy++; c.weighty=1.0; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.BOTH; + gridbag.setConstraints(outcomeView, c); + add(outcomeView); + + } + + public void init() { + if (outcomePanel != null) + new Thread(outcomePanel).start(); + } + + public void execute(Job thisJob) { + try{ + if (thisJob.isOutcomeUsed() && thisJob.getSchemaType().length() > 0) + thisJob.setOutcome(outcomePanel.getOutcome()); + executingJob = thisJob; + new Thread(this).start(); + } catch (OutcomeException ex) { + Logger.exceptionDialog(ex); + } + + } + + /** + * Submits the job to the database + */ + @Override + public void run() { + Thread.currentThread().setName("Activity Execution"); + enableAllButtons(false); + try { + Executor selectedExecutor = (Executor)executors.getSelectedItem(); + selectedExecutor.execute(executingJob, status); + } catch (Exception e) { + Logger.error(e); + status.setText(Language.translate("Error during execution")); + Logger.exceptionDialog(e); + } + enableAllButtons(true); + } + + private void enableAllButtons(boolean enabled) { + + for (RequestButton thisButton : requestButtons) { + thisButton.setEnabled(enabled); + } + } + + public ActivityItem getActivity() { + return thisAct; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java b/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java new file mode 100644 index 0000000..378cc2e --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/execution/DefaultExecutor.java @@ -0,0 +1,35 @@ +package com.c2kernel.gui.tabs.execution; + +import javax.swing.JLabel; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.utils.Language; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2003/11/04 14:31:30 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class DefaultExecutor implements Executor { + + public DefaultExecutor() { + super(); + } + + @Override + public void execute(Job job, JLabel status) throws Exception { + status.setText(Language.translate("Requesting, please wait.")); + MainFrame.userAgent.execute(job); + status.setText(Language.translate("Execution complete. Waiting for joblist update.")); + } + + @Override + public String toString() { + return "Normal"; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java b/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java new file mode 100644 index 0000000..6fbde17 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/execution/Executor.java @@ -0,0 +1,22 @@ +package com.c2kernel.gui.tabs.execution; + +import javax.swing.JLabel; + +import com.c2kernel.entity.agent.Job; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2003/09/25 10:28:02 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public interface Executor { + + @Override + public String toString(); + + public void execute(Job job, JLabel status) throws Exception; +} diff --git a/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java b/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java new file mode 100644 index 0000000..e1372a2 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/execution/RequestButton.java @@ -0,0 +1,34 @@ +package com.c2kernel.gui.tabs.execution; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +/** + * Each job gets a RequestButton + */ + + public class RequestButton extends JButton implements ActionListener { + + Job myJob; + ActivityViewer parent; + + public RequestButton(Job myJob, ActivityViewer parent) { + super(); + this.myJob = myJob; + this.parent = parent; + String label = Transitions.getTransitionName(myJob.getPossibleTransition()); + label = Character.toUpperCase(label.charAt(0))+label.substring(1); + if (myJob.isOutcomeUsed()) setBackground(Color.white); + super.setText(label); + addActionListener(this); + } + + @Override + public void actionPerformed(ActionEvent event) { + parent.execute(myJob); + } + } diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java b/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java new file mode 100644 index 0000000..5ab5245 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/BasicOutcomeEditor.java @@ -0,0 +1,112 @@ +package com.c2kernel.gui.tabs.outcome; + +import java.awt.Font; +import java.awt.GridLayout; +import java.io.File; + +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.text.PlainDocument; + +import com.c2kernel.utils.FileStringUtility; + +/************************************************************************** + * + * $Revision: 1.4 $ + * $Date: 2005/09/07 13:46:31 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + + +public class BasicOutcomeEditor extends JPanel implements OutcomeHandler { + + PlainDocument doc; + JTextArea textarea; + boolean unsaved; + + public BasicOutcomeEditor() { + super(); + this.setLayout(new GridLayout(1,1)); + doc = new PlainDocument(); + textarea = new JTextArea(doc); + textarea.setTabSize(2); + textarea.setFont(Font.decode("monospaced")); + add(new JScrollPane(textarea)); + doc.addDocumentListener(new DocumentListener() { + @Override + public void changedUpdate(DocumentEvent e) { unsaved = true; } + @Override + public void insertUpdate(DocumentEvent e) { unsaved = true; } + @Override + public void removeUpdate(DocumentEvent e) { unsaved = true; } + + }); + } + + @Override + public void setOutcome(String outcome) throws InvalidOutcomeException { + try { + doc.insertString(0, outcome, null); + unsaved = false; + } catch (Exception ex) { + throw new InvalidOutcomeException(ex.getMessage()); + } + } + + @Override + public void setDescription(String description) throws InvalidSchemaException { } + + @Override + public void setReadOnly(boolean readOnly) { + textarea.setEditable(!readOnly); + } + + + @Override + public JPanel getPanel() throws OutcomeNotInitialisedException { + return this; + } + + /** + * + */ + + @Override + public String getOutcome() throws OutcomeException { + try { + return doc.getText(0, doc.getLength()); + } catch (Exception ex) { + throw new OutcomeException(ex.getMessage()); + } + } + + /** + * + */ + + @Override + public void run() { + } + + + @Override + public boolean isUnsaved() { + return unsaved; + } + + @Override + public void saved() { + unsaved = false; + } + + @Override + public void export(File targetFile) throws Exception { + FileStringUtility.string2File(targetFile, getOutcome()); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java new file mode 100644 index 0000000..bab9050 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidOutcomeException.java @@ -0,0 +1,11 @@ +package com.c2kernel.gui.tabs.outcome; + +public class InvalidOutcomeException extends OutcomeException { + + public InvalidOutcomeException() { + super(); + } + public InvalidOutcomeException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java new file mode 100644 index 0000000..5edbcbf --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/InvalidSchemaException.java @@ -0,0 +1,11 @@ +package com.c2kernel.gui.tabs.outcome; + +public class InvalidSchemaException extends OutcomeException { + + public InvalidSchemaException() { + super(); + } + public InvalidSchemaException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java new file mode 100644 index 0000000..fd608d0 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeException.java @@ -0,0 +1,11 @@ +package com.c2kernel.gui.tabs.outcome; + +public class OutcomeException extends Exception { + + public OutcomeException() { + super(); + } + public OutcomeException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java new file mode 100644 index 0000000..0d6dc74 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeHandler.java @@ -0,0 +1,16 @@ +package com.c2kernel.gui.tabs.outcome; +import java.io.File; + +import javax.swing.JPanel; + +public interface OutcomeHandler extends Runnable { + + public void setOutcome(String outcome) throws InvalidOutcomeException; + public void setDescription(String description) throws InvalidSchemaException; + public void setReadOnly(boolean readOnly); + public JPanel getPanel() throws OutcomeNotInitialisedException; + public boolean isUnsaved(); + public void saved(); + public String getOutcome() throws OutcomeException; + public void export(File targetFile) throws Exception; +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java new file mode 100644 index 0000000..7b54f33 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/OutcomeNotInitialisedException.java @@ -0,0 +1,11 @@ +package com.c2kernel.gui.tabs.outcome; + +public class OutcomeNotInitialisedException extends OutcomeException { + + public OutcomeNotInitialisedException() { + super(); + } + public OutcomeNotInitialisedException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java new file mode 100644 index 0000000..7d15452 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/AttributeList.java @@ -0,0 +1,160 @@ +package com.c2kernel.gui.tabs.outcome.form; + +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; + +import org.exolab.castor.xml.schema.AttributeDecl; +import org.exolab.castor.xml.schema.ComplexType; +import org.exolab.castor.xml.schema.ElementDecl; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + +import com.c2kernel.gui.tabs.outcome.form.field.StringEditField; +import com.c2kernel.utils.Logger; + +public class AttributeList extends JPanel { + + ArrayList attrSet = new ArrayList(); + ElementDecl model; + Element myElement; + boolean readOnly; + static Font labelFont; + + public AttributeList(ElementDecl model, boolean readOnly, HelpPane helpPane) { + super(); + AttributeDecl thisDecl; + this.model = model; + this.readOnly = readOnly; + + // set up panel + GridBagLayout gridbag = new java.awt.GridBagLayout(); + setLayout(gridbag); + if (labelFont == null) + labelFont = this.getFont().deriveFont((float)(this.getFont().getSize()-3.0)); + // retrieve attributes + if (!model.getType().isComplexType()) { + // simple types have no attributes + return; + } + + ComplexType content = (ComplexType)model.getType(); + + // place on panel + + GridBagConstraints c = new GridBagConstraints(); + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1.0; c.weighty = 1.0; c.gridx = 0; + c.ipadx = 5; c.ipady = 0; + + for (Enumeration fields = content.getAttributeDecls(); fields.hasMoreElements();) { + c.gridy = 0; + thisDecl = (AttributeDecl)fields.nextElement(); + Logger.msg(8, "Includes Attribute "+thisDecl.getName()); + + // Add Label + JLabel heading = new JLabel(thisDecl.getName()); + heading.setFont(labelFont); + heading.setVerticalAlignment(SwingConstants.BOTTOM); + gridbag.setConstraints(heading, c); + this.add(heading); + + // read help + String helpText; + String doc = OutcomeStructure.extractHelp(thisDecl); + if (doc.length() > 0) + helpText = doc.toString(); + else + helpText = "No help is available for this attribute"; + + + c.gridy++; + + // Add entry + try { + StringEditField entry = StringEditField.getEditField(thisDecl); + entry.setHelp(helpPane, helpText); + attrSet.add(entry); + if (readOnly) entry.setEditable(false); + gridbag.setConstraints(entry.getControl(), c); + this.add(entry.getControl()); + } catch (StructuralException e) { + JLabel entry = new JLabel("Error"); + entry.setToolTipText(e.getMessage()); + gridbag.setConstraints(entry, c); + this.add(entry); + } + + + c.gridx++; + } + } + + public void setInstance(Element data) throws StructuralException { + this.myElement = data; + for (StringEditField thisField : attrSet) { + Logger.msg(8, "Populating Attribute "+thisField.getName()); + Attr thisAttr = myElement.getAttributeNode(thisField.getName()); + if (thisAttr == null) + thisAttr = newAttribute(myElement, (AttributeDecl)thisField.getModel()); + thisField.setData(thisAttr); + } + } + + public Attr newAttribute(Element parent, AttributeDecl attr) { + + parent.setAttribute(attr.getName(), attr.getFixedValue()!=null?attr.getFixedValue():attr.getDefaultValue()); + return parent.getAttributeNode(attr.getName()); + } + + public String validateAttributes() { + if (model.getType().isComplexType()) { + ComplexType content = (ComplexType)model.getType(); + for (Enumeration fields = content.getAttributeDecls(); fields.hasMoreElements();) { + AttributeDecl thisDecl = (AttributeDecl)fields.nextElement(); + String attrVal = myElement.getAttribute(thisDecl.getName()); + if (attrVal.length() == 0 && thisDecl.isOptional()) { + myElement.removeAttribute(thisDecl.getName()); + } + } + } + return null; + } + + public void initNew(Element parent) { + AttributeDecl thisDecl; + StringEditField thisField; + Attr thisAttr; + this.myElement = parent; + + if (model.getType().isSimpleType()) return; // no attributes in simple types + + ComplexType content = (ComplexType)model.getType(); + + for (Iterator e = attrSet.iterator(); e.hasNext();) { + thisField = e.next(); + + thisDecl = content.getAttributeDecl(thisField.getName()); + // HACK: if we don't resolve the reference, the type will be null + if (thisDecl.isReference()) thisDecl = thisDecl.getReference(); + thisAttr = newAttribute(myElement, thisDecl); + // add into parent - fill in field + try { + thisField.setData(thisAttr); + } catch (Exception ex) { } // impossible name mismatch + } + } + @Override + public void grabFocus() { + if (attrSet.size() > 0) + attrSet.get(0).grabFocus(); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java new file mode 100644 index 0000000..bb6d039 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/CardinalException.java @@ -0,0 +1,14 @@ +package com.c2kernel.gui.tabs.outcome.form; + +import com.c2kernel.gui.tabs.outcome.OutcomeException; + +public class CardinalException extends OutcomeException { + + public CardinalException() { + super(); + } + + public CardinalException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java new file mode 100644 index 0000000..3bfe3fd --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DataRecord.java @@ -0,0 +1,252 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; + +import javax.swing.JLabel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.exolab.castor.xml.schema.ComplexType; +import org.exolab.castor.xml.schema.ElementDecl; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.utils.Logger; + +public class DataRecord extends OutcomeStructure implements ChangeListener { + + AttributeList myAttributes; + JTabbedPane DRPanel = null; + boolean deferred; + Document parentDoc; + GridBagConstraints position; + GridBagLayout gridbag; + + public DataRecord(ElementDecl model, boolean readOnly, HelpPane help, boolean deferred) throws OutcomeException { + super(model, readOnly, help); + this.deferred = deferred; + if (!deferred) setupPanel(); + } + + public synchronized void activate() { + deferred = false; + try { + setupPanel(); + if (myElement!=null) populateInstance(); + } catch (OutcomeException ex) { + removeAll(); + setLayout(new FlowLayout()); + add(new JLabel("Error displaying outcome segment: "+ex.getMessage())); + } + validate(); + } + + private void setupPanel() throws OutcomeException { + // set up panel + gridbag = new java.awt.GridBagLayout(); + setLayout(gridbag); + position = new GridBagConstraints(); + position.anchor = GridBagConstraints.NORTHWEST; + position.fill = GridBagConstraints.NONE; + position.weightx = 1.0; position.weighty = 1.0; + position.gridx = 0; position.gridy = 0; + position.ipadx = 5; position.ipady = 5; + position.insets = new Insets(5,5,0,0); + + // attributes at the top + myAttributes = new AttributeList(model, readOnly, helpPane); + position.gridwidth=3; + gridbag.setConstraints(myAttributes, position); + add(myAttributes); + + ComplexType elementType; + try { + elementType = (ComplexType)model.getType(); + } + catch (ClassCastException e) { + throw new StructuralException("DataRecord created with non-ComplexType"); + } + + //loop through all schema sub-elements + try { + enumerateElements(elementType); + } catch (OutcomeException e) { + throw new OutcomeException("Element "+model.getName()+" could not be created: "+e.getMessage()); + } + } + + @Override + public void addStructure(OutcomeStructure newElement) throws OutcomeException { + super.addStructure(newElement); + if (newElement == null) return; + if (newElement instanceof DataRecord) { + DataRecord newRecord = (DataRecord)newElement; + // set up enclosing tabbed pane for child drs + if (DRPanel == null) { + DRPanel = new JTabbedPane(); + position.gridy++; + position.weightx=1.0; + position.fill=GridBagConstraints.HORIZONTAL; + position.gridwidth=3; + gridbag.setConstraints(DRPanel, position); + add(DRPanel); + // defer further tabs in this pane + deferChild = true; + } + DRPanel.addTab(newRecord.getName(), newRecord); + DRPanel.addChangeListener(newRecord); + } + else { + DRPanel = null;// have to make a new tabbed pane now + deferChild = false; + if (newElement instanceof Field) { + Field newField = (Field)newElement; + // make some nice columns + position.gridwidth=1; + position.gridy++; + position.gridx=0; + position.weightx=2; + position.weighty=0; + position.fill=GridBagConstraints.NONE; + gridbag.setConstraints(newField.getLabel(), position); + this.add(newField.getLabel()); + position.gridy++; + position.weighty=1; + position.fill = GridBagConstraints.HORIZONTAL; + gridbag.setConstraints(newField.getCData(), position); + this.add(newField.getCData()); + position.gridx++; + position.gridy--; + position.gridheight=2; + position.weightx=0; + position.fill=GridBagConstraints.NONE; + gridbag.setConstraints(newField.getAttributes(), position); + this.add(newField.getAttributes()); + position.gridx=0; + position.gridheight=1; + position.gridy++; + } + else { + position.fill=GridBagConstraints.HORIZONTAL; + position.gridwidth=3; + position.weightx=1.0; + position.gridy++; + position.weighty=1.0; + gridbag.setConstraints(newElement, position); + add(newElement); + } + } + } + + @Override + public void addInstance(Element myElement, Document parentDoc) throws OutcomeException { + Logger.msg(8, "Accepting DR "+myElement.getTagName()); + + if (this.myElement != null) throw new CardinalException("DataRecord "+this.getName()+" cannot repeat."); + this.myElement = myElement; + this.parentDoc = parentDoc; + + if (!deferred) + populateInstance(); + } + + public void populateInstance() throws OutcomeException { + myAttributes.setInstance(myElement); + + NodeList childElements = myElement.getChildNodes(); + + for (int i=0; i 0) + myAttributes.grabFocus(); + else if (order.size()> 0) + subStructure.get(order.get(0)).grabFocus(); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java new file mode 100644 index 0000000..c91c5df --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/Dimension.java @@ -0,0 +1,395 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.border.EtchedBorder; +import javax.swing.table.JTableHeader; + +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Particle; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.c2kernel.gui.DomainKeyConsumer; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.utils.Logger; + +public class Dimension extends OutcomeStructure implements ActionListener { + + DimensionTableModel tableModel; + Element parent; + GridBagConstraints position; + GridBagLayout gridbag; + JTabbedPane tabs; + JLabel msg; + DomKeyPushTable table; + Box tableBox; + ArrayList instances = new ArrayList(); // stores DimensionInstances if tabs + ArrayList elements = new ArrayList(); // stores current children + + JButton addButton; + JButton delButton; + + short mode; + protected static final short TABLE = 1; + protected static final short TABS = 2; + + + public Dimension(ElementDecl model, boolean readOnly, HelpPane help) { + super(model, readOnly, help); + // set up panel + gridbag = new java.awt.GridBagLayout(); + setLayout(gridbag); + position = new GridBagConstraints(); + position.anchor = GridBagConstraints.NORTHWEST; + position.fill = GridBagConstraints.HORIZONTAL; + position.weightx = 1.0; position.weighty = 0.0; + position.gridx = 0; position.gridy = 0; + position.ipadx = 0; position.ipady = 0; + position.insets = new Insets(0,0,0,0); + + // TODO: an element or attribute of the dimension can be flagged as an index, so it can be used as a title for a tab + + // set up the border + setBorder(BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), model.getName())); + + msg = new JLabel("No elements"); + msg.setFont(new Font("SansSerif", Font.ITALIC, msg.getFont().getSize())); + gridbag.setConstraints(msg, position); + add(msg); + position.gridy++; + + // decide whether a table or tabs + try { + tableModel = new DimensionTableModel(model, readOnly); + Logger.msg(8, "DIM "+model.getName()+" - Will be a table"); + mode = TABLE; + tableBox = Box.createVerticalBox(); + table = new DomKeyPushTable(tableModel, this); + new MultiLinePasteAdapter(table, this); + if (readOnly) table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + table.setColumnSelectionAllowed(readOnly); + JTableHeader tableHeader = table.getTableHeader(); + tableHeader.setReorderingAllowed(false); + tableBox.add(tableHeader); + tableBox.add(table); + gridbag.setConstraints(tableBox, position); + add(tableBox); + tableBox.setVisible(false); + + } catch (StructuralException e) { + // use tabs + Logger.msg(8, "DIM "+model.getName()+" - Will be tabs: "+e.getMessage()); + mode = TABS; + tabs = new JTabbedPane(); + gridbag.setConstraints(tabs, position); + add(tabs); + tabs.setVisible(false); + } + if (!readOnly) { + JPanel rowAdjust = new JPanel(new FlowLayout()); + addButton = new JButton("+"); + addButton.setActionCommand("add"); + addButton.addActionListener(this); + rowAdjust.add(addButton); + + delButton = new JButton("-"); + delButton.setActionCommand("del"); + delButton.addActionListener(this); + delButton.setEnabled(false); + rowAdjust.add(delButton); + + + position.gridy++; position.weighty=0; position.weightx=0; + gridbag.setConstraints(rowAdjust, position); + this.add(rowAdjust); + } + + } + + public void setParentElement(Element parent) { + this.parent = parent; + } + + @Override + public void addInstance(Element myElement, Document parentDoc) throws OutcomeException { + if (Logger.doLog(6)) + Logger.msg(6, "DIM - adding instance "+ (elements.size()+1) +" for "+myElement.getTagName()); + if (parent == null) setParentElement((Element)myElement.getParentNode()); + // if table, pass to table model + if (mode == TABLE) { + tableModel.addInstance(myElement, -1); + elements.add(myElement); + } + else { + DimensionInstance target; + elements.add(myElement); + if (instances.size() < elements.size()) + target = newInstance(); + else + target = instances.get(elements.size()-1); + target.addInstance(myElement, parentDoc); + } + checkButtons(); + } + + public int getChildCount() { + return elements.size(); + } + + public DimensionInstance newInstance() { + DimensionInstance newInstance = null; + try { + newInstance = new DimensionInstance(model, readOnly, helpPane, deferChild); + instances.add(newInstance); + newInstance.setTabNumber(instances.size()); + newInstance.setParent(this); + deferChild = true; + tabs.addTab(newInstance.getName(), newInstance); + tabs.addChangeListener(newInstance); + } catch (OutcomeException e) { + // shouldn't happen, we've already done it once + Logger.error(e); + } + return newInstance; + } + + @Override + public String validateStructure() { + if (mode == TABLE) + return table.validateStructure(); + else { + StringBuffer errors = new StringBuffer(); + for (Iterator iter = instances.iterator(); iter.hasNext();) { + OutcomeStructure element = iter.next(); + errors.append(element.validateStructure()); + } + return errors.toString(); + } + } + + public void checkButtons() { + // check if data visible + boolean dataVisible = elements.size() > 0; + if (mode == TABS) tabs.setVisible(dataVisible); + else tableBox.setVisible(dataVisible); + msg.setVisible(!dataVisible); + + if (readOnly) return; + + if (elements.size() <= model.getMinOccurs() || elements.size() == 0) { + delButton.setEnabled(false); + delButton.setToolTipText("Minimum row count of "+model.getMinOccurs()+" reached."); + } else { + delButton.setEnabled(true); + delButton.setToolTipText(null); + } + + if (elements.size() < model.getMaxOccurs() || model.getMaxOccurs() == Particle.UNBOUNDED) { + addButton.setEnabled(true); + addButton.setToolTipText(null); + } else { + addButton.setEnabled(false); + addButton.setToolTipText("Maximum row count of "+model.getMaxOccurs()+" reached."); + } + } + + @Override + public Element initNew(Document parent) { + Element newElement; + + if (mode == TABLE) { + newElement = tableModel.initNew(parent, -1); + elements.add(newElement); + checkButtons(); + return newElement; + } + else { + DimensionInstance newTab = null; + if (instances.size() < elements.size()+1) + newTab = newInstance(); + else + newTab = instances.get(elements.size()-1); + newElement = newTab.initNew(parent); + elements.add(newElement); + checkButtons(); + return newElement; + } + } + + @Override + public void actionPerformed(ActionEvent e) { + int index; + if (mode == TABS) index = tabs.getSelectedIndex(); + else { + index = table.getSelectedRow(); + if (index == -1) index = tableModel.getRowCount(); + } + try { + if (table == null || table.getCellEditor() == null || table.getCellEditor().stopCellEditing()) { + if (e.getActionCommand().equals("add")) + addRow(index); + else if (e.getActionCommand().equals("del")) + removeRow(index); + } + } catch (CardinalException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "Table error", JOptionPane.ERROR_MESSAGE); + } + } + + public void addRow(int index) throws CardinalException { + if (elements.size() == model.getMaxOccurs()) + throw new CardinalException("Maximum size of table reached"); + + if (mode == TABLE) { + Element newRow = tableModel.initNew(parent.getOwnerDocument(), index); + elements.add(index, newRow); + try { + Element following = elements.get(index+1); + parent.insertBefore(newRow, following); + } catch (IndexOutOfBoundsException ex) { + parent.appendChild(newRow); + } + table.clearSelection(); + table.setRowSelectionInterval(index, index); + } + else { + Element newTab = initNew(parent.getOwnerDocument()); + parent.appendChild(newTab); + } + checkButtons(); + + } + + public void removeRow(int index) throws CardinalException { + if (elements.size() <= model.getMinOccurs()) + throw new CardinalException("Minimum size of table reached"); + if (mode == TABLE) { + parent.removeChild(tableModel.removeRow(index)); + int selectRow = index; + if (index >= tableModel.getRowCount()) selectRow--; + if (tableModel.getRowCount() > 0) { + table.clearSelection(); + table.setRowSelectionInterval(selectRow, selectRow); + } + } + else { + Element elementToGo = elements.get(index); + parent.removeChild(elementToGo); + instances.remove(index); + tabs.remove(index); + for (int i = index; i -1 && row > -1) { + if (dataModel.getValueAt(row, col).toString().length()==0) + dataModel.setValueAt(name, row, col); + else { + if (row+1 == getRowCount()) { + try { + dim.addRow(row+1); + dataModel.setValueAt(name, row+1, col); + } catch (CardinalException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage(), "Table error", JOptionPane.ERROR_MESSAGE); + } + } + } + if (row+1 < getRowCount()) { + Logger.msg(8, "Shifting selection to row "+(row+1)); + changeSelection(row+1, col, false, false); + } + } + } + + @Override + public void focusGained(FocusEvent e) { + if (!readOnly) + MainFrame.itemFinder.setConsumer(this, "Insert"); + } + + @Override + public void focusLost(FocusEvent e) { + // release the itemFinder + if (!readOnly) + MainFrame.itemFinder.clearConsumer(this); + } + + public String validateStructure() { + if (cellEditor != null) + cellEditor.stopCellEditing(); + return null; + } + + @Override + public void changeSelection( int rowIndex, int columnIndex, boolean toggle, boolean extend) { + super.changeSelection(rowIndex, columnIndex, toggle, extend); + DimensionTableModel dimModel = (DimensionTableModel)dataModel; + helpPane.setHelp(dimModel.getColumnName(columnIndex), dimModel.getHelp(columnIndex)); + } + + } + + @Override + public void grabFocus() { + if (mode == TABLE) { + if (table.getSelectedRow() == -1 && table.getRowCount() > 0) { + table.changeSelection(0, 0, false, false); + table.editCellAt(0,0); + } + table.requestFocus(); + } + else if (instances.size()> 0) + instances.get(0).grabFocus(); + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java new file mode 100644 index 0000000..649886b --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionInstance.java @@ -0,0 +1,33 @@ +package com.c2kernel.gui.tabs.outcome.form; +import org.exolab.castor.xml.schema.ElementDecl; + +import com.c2kernel.gui.tabs.outcome.OutcomeException; + +public class DimensionInstance extends DataRecord { + + //probably will be needed to synch edits later + Dimension parentDimension; + int tabNumber; + String tabName = null; + + public DimensionInstance(ElementDecl model, boolean readOnly , HelpPane help, boolean deferred) throws OutcomeException { + super(model, readOnly, help, deferred); + } + + public void setTabNumber(int tabNumber) { + this.tabNumber=tabNumber; + } + + public void setParent(Dimension parent) { + this.parentDimension = parent; + } + + @Override + public String getName() { + //TODO appinfo for picking out attributes or child elements for tab name + if (tabName == null) + return Integer.toString(tabNumber); + else + return tabName; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java new file mode 100644 index 0000000..ac6a9f2 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/DimensionTableModel.java @@ -0,0 +1,332 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.util.ArrayList; +import java.util.Enumeration; + +import javax.swing.table.AbstractTableModel; + +import org.exolab.castor.xml.schema.Annotated; +import org.exolab.castor.xml.schema.AttributeDecl; +import org.exolab.castor.xml.schema.ComplexType; +import org.exolab.castor.xml.schema.ContentModelGroup; +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Group; +import org.exolab.castor.xml.schema.Order; +import org.exolab.castor.xml.schema.Particle; +import org.exolab.castor.xml.schema.SimpleType; +import org.exolab.castor.xml.schema.SimpleTypesFactory; +import org.exolab.castor.xml.schema.XMLType; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +public class DimensionTableModel extends AbstractTableModel { + + ElementDecl model; + ArrayList columnHeadings = new ArrayList(); + ArrayList> columnClasses = new ArrayList>(); + ArrayList columnDecls = new ArrayList(); + ArrayList colReadOnly = new ArrayList(); + ArrayList colHelp = new ArrayList(); + ArrayList rows = new ArrayList(); + ArrayList elements = new ArrayList(); + boolean readOnly; + + public DimensionTableModel(ElementDecl model, boolean readOnly) throws StructuralException { + XMLType modelContent = model.getType(); + this.model = model; + this.readOnly = readOnly; + // use text node for simple types + if (modelContent.isSimpleType()) { + SimpleType elementType = (SimpleType)modelContent; + SimpleType baseType = elementType.getBuiltInBaseType(); + addColumn(model.getName(), baseType, baseType.getTypeCode(), new Boolean(model.getFixedValue() != null)); + } + else if (modelContent.isComplexType()) { // if complex type, process child elements + ComplexType elementType = (ComplexType)modelContent; + + // find out if a CDATA type is used for this complex type + XMLType baseType = elementType.getBaseType(); + while (!(baseType instanceof SimpleType) && baseType != null) { + baseType = baseType.getBaseType(); + } + if (baseType != null) { + int typeCode = ((SimpleType)baseType).getTypeCode(); + addColumn(model.getName(), baseType, typeCode, new Boolean(model.getFixedValue() != null)); + } + // process attributes + for (Enumeration e = elementType.getAttributeDecls(); e.hasMoreElements();) { + AttributeDecl thisAttr = (AttributeDecl)e.nextElement(); + // HACK: if we don't resolve the reference, the type will be null + if (thisAttr.isReference()) thisAttr = thisAttr.getReference(); + if (thisAttr.getSimpleType() == null) + throw new StructuralException("Attribute "+thisAttr.getName()+" in "+model.getName()+" has no type"); + addColumn(thisAttr.getName(), thisAttr, thisAttr.getSimpleType().getTypeCode(), new Boolean(thisAttr.isFixed())); + } + + // enumerate child elements + enumerateElements(elementType); + } + } + + public synchronized void addColumn(String heading, Annotated decl, int typeCode, Boolean readOnly) { + Logger.msg(8, "Column "+heading+" contains "+decl.getClass().getName()+" readOnly="+readOnly.toString()); + columnHeadings.add(heading); + columnDecls.add(decl); + columnClasses.add(OutcomeStructure.getJavaClass(typeCode)); + colReadOnly.add(readOnly); + + // read help + String helpText; + if (decl instanceof SimpleType) + helpText = OutcomeStructure.extractHelp(model); + else + helpText = OutcomeStructure.extractHelp(decl); + + if (helpText.length() == 0) + helpText = ""+Language.translate("No help is available for this cell")+""; + + colHelp.add(helpText); + + } + + + public void enumerateElements(ContentModelGroup group) throws StructuralException { + for (Enumeration childElements = group.enumerate(); childElements.hasMoreElements(); ) { + Particle thisParticle = (Particle)childElements.nextElement(); + String extraHeader = ""; + if (thisParticle instanceof Group) { + Group thisGroup = (Group)thisParticle; + Order order = thisGroup.getOrder(); + if (order == Order.sequence || order == Order.all) + enumerateElements(thisGroup); + else // we only support sequences in data structures such as these + throw new StructuralException("Element "+thisGroup.getName()+". Expecting sequence or all. Got "+thisGroup.getOrder()); + } + else if (thisParticle instanceof ElementDecl) { + ElementDecl thisElement = (ElementDecl)thisParticle; + int typeCode = SimpleTypesFactory.INVALID_TYPE; + //make sure not too complex + if (thisElement.getType() != null) { + if (thisElement.getType().isComplexType()) { + ComplexType elementType = (ComplexType)thisElement.getType(); + if (elementType.getParticleCount() > 0 || + thisElement.getMaxOccurs() > 1) + throw new StructuralException("Too deep for a table"); + for (Enumeration attrs = elementType.getAttributeDecls(); attrs.hasMoreElements();) { + AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement(); + if (!thisAttr.isFixed()) + throw new StructuralException("Non-fixed attributes of child elements not supported in tables."); + else + extraHeader=extraHeader+" ("+thisAttr.getName()+":"+(thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue())+")"; + } + // find type + XMLType parentType = thisElement.getType(); + while (!(parentType instanceof SimpleType) && parentType != null) { + parentType = parentType.getBaseType(); + if (parentType != null) typeCode = ((SimpleType)parentType).getTypeCode(); + } + } + else + typeCode = ((SimpleType)thisElement.getType()).getTypeCode(); + } + + //add to list + addColumn(thisElement.getName()+extraHeader, thisElement, typeCode, new Boolean(thisElement.getFixedValue() != null)); + } + else throw new StructuralException("Particle "+thisParticle.getClass()+" not implemented"); + } + } + + public void addInstance(Element myElement, int index) throws OutcomeException { + if (index == -1) index = elements.size(); + Object[] newRow = new Object[columnHeadings.size()]; + for (int i=0; i getColumnClass(int columnIndex) { + return columnClasses.get(columnIndex); + } + + @Override + public String getColumnName(int columnIndex) { + return columnHeadings.get(columnIndex); + } + + @Override + public int getRowCount() { + return rows.size(); + } + + @Override + public int getColumnCount() { + return columnHeadings.size(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + boolean isReadOnly = readOnly || colReadOnly.get(columnIndex).booleanValue(); + return !isReadOnly; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + Object[] thisRow = rows.get(rowIndex); + thisRow[columnIndex]=aValue; + Element myElement = elements.get(rowIndex); + // update node + if (columnDecls.get(columnIndex) instanceof ElementDecl) { // sub element + ElementDecl thisDecl = (ElementDecl)columnDecls.get(columnIndex); + NodeList childElements = myElement.getElementsByTagName(thisDecl.getName()); + // depend on one element with a Text child - this should have been enforced on init. + Text childNode = (Text)(childElements.item(0).getFirstChild()); + childNode.setData(aValue.toString()); + } + else if (columnDecls.get(columnIndex) instanceof AttributeDecl) { //attribute + AttributeDecl thisDecl = (AttributeDecl) columnDecls.get(columnIndex); + myElement.setAttribute(thisDecl.getName(), aValue.toString()); + } + else { // first child node + Text textNode = (Text)myElement.getFirstChild(); + textNode.setData(aValue.toString()); + } + fireTableCellUpdated(rowIndex, columnIndex); + } + + public Element removeRow(int rowIndex) { + Element elementToGo = elements.get(rowIndex); + elements.remove(rowIndex); + rows.remove(rowIndex); + fireTableRowsDeleted(rowIndex,rowIndex); + return elementToGo; + } + + public Object setupDefaultElement(ElementDecl thisDecl, Element parent, Class type) { + Object newValue; + String defaultValue = thisDecl.getFixedValue(); + if (defaultValue == null) + defaultValue = thisDecl.getDefaultValue(); + if (readOnly) + newValue = ""; + else + newValue = OutcomeStructure.getTypedValue(defaultValue, type); + + Text newNode = parent.getOwnerDocument().createTextNode(newValue.toString()); + parent.appendChild(newNode); + // fixed attributes + try { + ComplexType content = (ComplexType)thisDecl.getType(); + for (Enumeration attrs = content.getAttributeDecls(); attrs.hasMoreElements();) { + AttributeDecl thisAttr = (AttributeDecl)attrs.nextElement(); + parent.setAttribute(thisAttr.getName(), thisAttr.getFixedValue()!=null?thisAttr.getFixedValue():thisAttr.getDefaultValue()); + } + } catch (ClassCastException ex) { } // only complex types have attributes + return newValue; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + Object[] thisRow = rows.get(rowIndex); + if (!(getColumnClass(columnIndex).equals(thisRow[columnIndex].getClass()))) + Logger.warning(thisRow[columnIndex]+" should be "+getColumnClass(columnIndex)+" is a "+thisRow[columnIndex].getClass().getName()); + return thisRow[columnIndex]; + } + + public String validateStructure() { // remove empty rows + for (int j=0; j < rows.size(); j++) { + Object[] elems = rows.get(j); + boolean empty = true; + for (int i = 0; i < elems.length && empty; i++) + empty &= OutcomeStructure.isEmpty(elems[i]); + if (empty) + if (model.getMinOccurs() < rows.size()) + removeRow(j); + else + return "Too many empty rows in table "+model.getName(); + } + return null; + } + + public Element initNew(Document parent, int index) { + if (index == -1) index = elements.size(); + Object[] newRow = new Object[columnHeadings.size()]; + Element myElement = parent.createElement(model.getName()); + for (int i=0; i"+Language.translate("Help")+""; + + public HelpPane() { + super(); + setEditable(false); + setEditorKit(new HTMLEditorKit()); + setContentType("text/html"); + setPreferredSize(new java.awt.Dimension(200,400)); + } + + public void setHelp(String title, String helpText) { + setText(header+"

"+title+"


"+toHTML(helpText)); + } + + + /** + * Unfortunately JEditorPane will only display HTML3.2, whereas to embed HTML in an xsd we must + * use XHTML so it will be valid XML. This method does a quick and dirty removal of stuff that + * the JEditorPane cannot display + * + * @param xhtml + * @return + */ + public static String toHTML(String xhtml) { + int startPos, endPos; + //remove xml header + while((startPos = xhtml.indexOf("")) != -1) { + xhtml = xhtml.substring(0,startPos)+xhtml.substring(endPos+2); + } + // remove slash in + while ((startPos = xhtml.indexOf("/>")) != -1) { + xhtml = xhtml.substring(0, startPos)+xhtml.substring(startPos+1); + } + return xhtml; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java new file mode 100644 index 0000000..3c5da27 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/MultiLinePasteAdapter.java @@ -0,0 +1,141 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.util.StringTokenizer; + +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import javax.swing.JTable; +import javax.swing.KeyStroke; + +import com.c2kernel.utils.Logger; +/** +* ExcelAdapter enables Copy-Paste Clipboard functionality on JTables. +* The clipboard data format used by the adapter is compatible with +* the clipboard format used by Excel. This provides for clipboard +* interoperability between enabled JTables and Excel. +*/ +public class MultiLinePasteAdapter implements ActionListener { + private String rowstring, value; + private Clipboard system; + private StringSelection stsel; + private JTable jTable1; + private Dimension parent; + /** + * The Excel Adapter is constructed with a + * JTable on which it enables Copy-Paste and acts + * as a Clipboard listener. + */ + public MultiLinePasteAdapter(JTable myJTable, Dimension parent) { + jTable1 = myJTable; + this.parent = parent; + KeyStroke copy = + KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK, false); + // Identifying the copy KeyStroke user can modify this + // to copy on some other Key combination. + KeyStroke paste = + KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.CTRL_MASK, false); + // Identifying the Paste KeyStroke user can modify this + //to copy on some other Key combination. + jTable1.registerKeyboardAction( + this, + "Copy", + copy, + JComponent.WHEN_FOCUSED); + jTable1.registerKeyboardAction( + this, + "Paste", + paste, + JComponent.WHEN_FOCUSED); + system = Toolkit.getDefaultToolkit().getSystemClipboard(); + } + /** + * Public Accessor methods for the Table on which this adapter acts. + */ + public JTable getJTable() { + return jTable1; + } + public void setJTable(JTable jTable1) { + this.jTable1 = jTable1; + } + /** + * This method is activated on the Keystrokes we are listening to + * in this implementation. Here it listens for Copy and Paste ActionCommands. + * Selections comprising non-adjacent cells result in invalid selection and + * then copy action cannot be performed. + * Paste is done by aligning the upper left corner of the selection with the + * 1st element in the current selection of the JTable. + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().compareTo("Copy") == 0) { + StringBuffer sbf = new StringBuffer(); + // Check to ensure we have selected only a contiguous block of + // cells + int numcols = jTable1.getSelectedColumnCount(); + int numrows = jTable1.getSelectedRowCount(); + int[] rowsselected = jTable1.getSelectedRows(); + int[] colsselected = jTable1.getSelectedColumns(); + if (!((numrows - 1 + == rowsselected[rowsselected.length - 1] - rowsselected[0] + && numrows == rowsselected.length) + && (numcols - 1 + == colsselected[colsselected.length - 1] - colsselected[0] + && numcols == colsselected.length))) { + JOptionPane.showMessageDialog( + null, + "Invalid Copy Selection", + "Invalid Copy Selection", + JOptionPane.ERROR_MESSAGE); + return; + } + for (int i = 0; i < numrows; i++) { + for (int j = 0; j < numcols; j++) { + sbf.append( + jTable1.getValueAt(rowsselected[i], colsselected[j])); + if (j < numcols - 1) + sbf.append("\t"); + } + sbf.append("\n"); + } + stsel = new StringSelection(sbf.toString()); + system = Toolkit.getDefaultToolkit().getSystemClipboard(); + system.setContents(stsel, stsel); + } + if (e.getActionCommand().compareTo("Paste") == 0) { + Logger.msg(5, "Trying to Paste"); + int startRow = (jTable1.getSelectedRows())[0]; + int startCol = (jTable1.getSelectedColumns())[0]; + try { + String trstring = + (String) (system.getContents(this).getTransferData(DataFlavor.stringFlavor)); + Logger.msg(8, "String is:" + trstring); + StringTokenizer st1 = new StringTokenizer(trstring, "\n\r"); + for (int i = 0; st1.hasMoreTokens(); i++) { + rowstring = st1.nextToken(); + StringTokenizer st2 = new StringTokenizer(rowstring, "\t"); + for (int j = 0; st2.hasMoreTokens(); j++) { + value = st2.nextToken(); + if (startRow + i == jTable1.getRowCount()) + parent.addRow(startRow+i); + if (startRow + i < jTable1.getRowCount() + && startCol + j < jTable1.getColumnCount()) + jTable1.setValueAt( + value, + startRow + i, + startCol + j); + Logger.msg(5, "Putting "+value+" at row="+(startRow+i)+" column="+(startCol+j)); + } + } + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java new file mode 100644 index 0000000..566d7c5 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeEditor.java @@ -0,0 +1,218 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + +import com.c2kernel.persistency.outcome.OutcomeValidator; +import com.c2kernel.persistency.outcome.Schema; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + + +class OutcomeEditor extends JFrame implements ActionListener { + + boolean readOnly = false; + File schemaFile = null; + File instanceFile = null; + JFileChooser chooser; + OutcomePanel outcome; + OutcomeValidator thisValid; + + public OutcomeEditor(File schema, File instance, boolean readOnly) { + URL schemaURL = null; + URL instanceURL = null; + schemaFile = schema; + instanceFile = instance; + this.readOnly = readOnly; + + try { + chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(new File(".").getCanonicalPath())); + } catch (IOException e) { + System.out.println("Could not initialise file dialog"); + System.exit(0); + } + + + this.setTitle("Outcome Editor"); + GridBagLayout gridbag = new GridBagLayout(); + getContentPane().setLayout(gridbag); + + addWindowListener( + new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent evt) { + System.exit(0); + } + } + ); + // select files if url is empty + + if (schemaFile == null) { // prompt for schema + schemaFile = getFile("Choose Schema File", "xsd"); + if (schemaFile == null) { + System.out.println("Cannot function without a schema"); + System.exit(1); + } + } + + try { + schemaURL = schemaFile.toURI().toURL(); + } catch (Exception e) { + System.out.println("Invalid schema URL"); + System.exit(1); + } + + if (instanceFile == null) { // prompt for schema + instanceFile = getFile("Choose Instance File", "xml"); + } + + try { + instanceURL = instanceFile.toURI().toURL(); + } catch (Exception e) { } + + try { + if (instanceFile != null && instanceFile.exists()) + outcome = new OutcomePanel(schemaURL, instanceURL, readOnly); + else + outcome = new OutcomePanel(schemaURL, readOnly); + + Schema thisSchema = new Schema(); + thisSchema.docType = schemaURL.getFile(); + thisSchema.docVersion = -1; + thisSchema.schema = FileStringUtility.url2String(schemaURL); + thisValid = OutcomeValidator.getValidator(thisSchema); + + } catch (Exception e) { e.printStackTrace(); System.exit(0);} + + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; c.weighty = 1.0; + c.gridwidth = 2; c.ipadx = 5; c.ipady = 5; + gridbag.setConstraints(outcome, c); + this.getContentPane().add(outcome); + + JButton saveButton = new JButton("Save"); + saveButton.setActionCommand("save"); + saveButton.addActionListener(this); + c.gridy++; c.weighty = 0; c.gridwidth = 1; + gridbag.setConstraints(saveButton, c); + this.getContentPane().add(saveButton); + if (readOnly) saveButton.setEnabled(false); + + JButton saveAsButton = new JButton("Save As"); + saveAsButton.setActionCommand("saveas"); + saveAsButton.addActionListener(this); + c.gridx++; c.weighty = 0; + gridbag.setConstraints(saveAsButton, c); + this.getContentPane().add(saveAsButton); + if (readOnly) saveAsButton.setEnabled(false); + System.out.println("Building Outcome Panel. Please wait . . ."); + outcome.run(); + pack(); + setVisible(true); + super.toFront(); + + } + + public File getFile(String title, String fileType) { + File targetFile = null; + chooser.setFileFilter(new SimpleFilter(fileType)); + chooser.setDialogTitle(title); + int returnVal = chooser.showDialog(this, "Select"); + if (returnVal == JFileChooser.APPROVE_OPTION) { + targetFile = chooser.getSelectedFile(); + } + try { + System.out.println(fileType+"="+targetFile.toURL()); + } catch (Exception ex) { } + return targetFile; + } + + public static void usage() { + System.out.println("-schema file:///schema.xsd"); + System.out.println("-inst file:///instance.xml"); + System.out.println("Leave one out to get a file open box."); + System.exit(0); + } + public static void main( String[] argv ) { + Logger.addLogStream(System.out, 6); + File instance = null; + File schema = null; + boolean readOnly = false; + for (int i = 0; i < argv.length; i++) { + if (argv[i].equals("-schema")) + schema = new File(argv[++i]); + if (argv[i].equals("-inst")) + instance = new File(argv[++i]); + if (argv[i].equals("-readOnly")) + readOnly = true; + if (argv[i].equals("-help") || argv[i].equals("-h")) + usage(); + } + new OutcomeEditor(schema, instance, readOnly); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().indexOf("save") == 0) { + String output; + output = outcome.getOutcome(); + + String errors = thisValid.validate(output); + if (errors != null && errors.length() > 0) { + int choice = JOptionPane.showConfirmDialog(null, errors+"\n\nSave anyway?", "Errors validating document", JOptionPane.YES_NO_OPTION); + if (choice != JOptionPane.YES_OPTION) + return; + } + + if (instanceFile == null || e.getActionCommand().equals("saveas")) { + instanceFile = getFile("Choose Instance File", "xml"); + if (instanceFile == null) { + System.out.println(output); + return; + } + } + try { + FileOutputStream targetStream = new FileOutputStream(instanceFile); + targetStream.write(output.getBytes()); + targetStream.close(); + } catch (Exception ex) {ex.printStackTrace();} + } + } + + private class SimpleFilter extends javax.swing.filechooser.FileFilter { + String extension; + + public SimpleFilter(String extension) { + super(); + this.extension = extension; + } + + @Override + public String getDescription() { + return extension.toUpperCase()+" Files"; + } + + @Override + public boolean accept(File f) { + if ((f.isFile() && f.getName().endsWith(extension.toLowerCase())) || f.isDirectory()) { + return true; + } + return false; + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java new file mode 100644 index 0000000..63c1d3d --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomePanel.java @@ -0,0 +1,370 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URL; + +import javax.swing.Box; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.xml.serialize.Method; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Schema; +import org.exolab.castor.xml.schema.reader.SchemaReader; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException; +import com.c2kernel.gui.tabs.outcome.InvalidSchemaException; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +// will load the outcome as instructed by other bits of the gui +// provides the 'save' button and creates the trees of objects to feed to the outcome form + +public class OutcomePanel extends JPanel implements OutcomeHandler +{ + + Schema schemaSOM; + //ASModel schemaASModel; + Document outcomeDOM; + OutcomeStructure documentRoot; + DocumentBuilder parser; + boolean readOnly; + boolean useForm = true; + boolean panelBuilt = false; + boolean unsaved = false; + JScrollPane scrollpane = new JScrollPane(); + HelpPane help = new HelpPane(); + + JTextArea basicView; + + public OutcomePanel() + { + GridBagLayout gridbag = new java.awt.GridBagLayout(); + setLayout(gridbag); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setValidating(false); + dbf.setNamespaceAware(false); + try + { + parser = dbf.newDocumentBuilder(); + } + catch (ParserConfigurationException e) + { + e.printStackTrace(); + } + + // Set up panel + + JComponent pane; + if (!MainFrame.getPref("ShowHelp", "true").equals("true")) + pane = scrollpane; + else { + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, scrollpane, help); + splitPane.setOneTouchExpandable(true); + splitPane.setDividerSize(9); + pane = splitPane; + } + + GridBagConstraints c = new GridBagConstraints(); + + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + c.weighty = 1.0; + c.ipadx = 5; + c.ipady = 5; + + gridbag.setConstraints(pane, c); + this.add(pane); + } + + public OutcomePanel(boolean readOnly) + { + this(); + setReadOnly(readOnly); + } + + public OutcomePanel(String schema, boolean readOnly) throws OutcomeException + { + this(readOnly); + this.setDescription(schema); + } + + public OutcomePanel(String schema, String outcome, boolean readOnly) throws OutcomeException + { + this(readOnly); + this.setDescription(schema); + this.setOutcome(outcome); + } + + // Parse from URLS + public void setOutcome(URL outcomeURL) throws InvalidOutcomeException + { + + try + { + setOutcome(new InputSource(outcomeURL.openStream())); + } + catch (IOException ex) + { + throw new InvalidOutcomeException("Error creating instance DOM tree: " + ex); + } + } + + public void setDescription(URL schemaURL) throws InvalidSchemaException + { + Logger.msg(7, "OutcomePanel.setDescription() - schemaURL:" + schemaURL.toString()); + try + { + setDescription(new InputSource(schemaURL.openStream())); + } + catch (IOException ex) + { + throw new InvalidSchemaException("Error creating exolab schema object: " + ex); + } + + } + + public OutcomePanel(URL schemaURL, boolean readOnly) throws OutcomeException + { + this(readOnly); + this.setDescription(schemaURL); + } + + public OutcomePanel(URL schemaURL, URL outcomeURL, boolean readOnly) throws OutcomeException + { + this(readOnly); + this.setDescription(schemaURL); + this.setOutcome(outcomeURL); + } + + // Parse from Strings + @Override + public void setOutcome(String outcome) throws InvalidOutcomeException + { + + try + { + setOutcome(new InputSource(new StringReader(outcome))); + } + catch (IOException ex) + { + throw new InvalidOutcomeException("Error creating instance DOM tree: " + ex); + } + } + + @Override + public void setDescription(String schema) throws InvalidSchemaException + { + if (schema == null) + throw new InvalidSchemaException("Null schema supplied"); + try + { + setDescription(new InputSource(new StringReader(schema))); + } + catch (Exception ex) + { + Logger.error(ex); + } + + } + + @Override + public void setReadOnly(boolean readOnly) + { + this.readOnly = readOnly; + } + + public void setDescription(InputSource schemaSource) throws InvalidSchemaException, IOException + { + + SchemaReader mySchemaReader = new SchemaReader(schemaSource); + this.schemaSOM = mySchemaReader.read(); + } + + public void setOutcome(InputSource outcomeSource) throws InvalidOutcomeException, IOException + { + try + { + outcomeDOM = parser.parse(outcomeSource); + } + catch (SAXException ex) + { + throw new InvalidOutcomeException("Sax error parsing Outcome " + ex); + } + } + + @Override + public void run() + { + Thread.currentThread().setName("Outcome Panel Builder"); + try + { + makeDisplay(); + } + catch (Exception oe) + { + scrollpane.setViewportView(new JLabel("Outcome View Generation Failed: " + oe.getMessage())); + Logger.error(oe); + } + } + + public void makeDisplay() + { + try + { + initPanel(); + } + catch (OutcomeException ex) + { + // something went wrong + useForm = false; + Box textPanel = Box.createVerticalBox(); + JLabel errorMsg = new JLabel("Could not create outcome view: " + ex.getMessage()); + errorMsg.setHorizontalAlignment(SwingConstants.LEFT); + textPanel.add(errorMsg); + textPanel.add(Box.createVerticalGlue()); + if (outcomeDOM!=null) { + basicView = new JTextArea(serialize(outcomeDOM, true)); + basicView.setEnabled(!readOnly); + textPanel.add(basicView); + } + scrollpane.setViewportView(textPanel); + } + } + + public void initPanel() throws OutcomeException + { + Element docElement; + /*if (panelBuilt) + return;*/ + Logger.msg(5, "Initialising Panel.."); + scrollpane.setViewportView(new JLabel("Building outcome. Please hang on two ticks . . .")); + if (schemaSOM == null) + throw new InvalidSchemaException("A valid schema has not been supplied."); + // create root panel with element declaration and maybe root document element node + + //find the root element declaration in the schema - may need to look for annotation?? + ElementDecl rootElementDecl = null; + docElement = (outcomeDOM == null) ? null : outcomeDOM.getDocumentElement(); + + for (ElementDecl elementDecl: schemaSOM.getElementDecls()) + { + rootElementDecl = elementDecl; + // REVISIT: We don't detect which is the most likely root element if there is more than one root decl + // xmlspy looks for an element not referenced elsewhere. simple but hard + // if we already have a document then use its root element to find the right decl + if (docElement != null && docElement.getTagName().equals(rootElementDecl.getName())) + break; + } + + if (rootElementDecl == null) + throw new InvalidSchemaException("No root elements defined"); + documentRoot = new DataRecord(rootElementDecl, readOnly, help, false); + + Logger.msg(5, "Finished structure. Populating..."); + if (docElement == null) + { + outcomeDOM = parser.newDocument(); + docElement = documentRoot.initNew(outcomeDOM); + outcomeDOM.appendChild(docElement); + } + else + documentRoot.addInstance(docElement, outcomeDOM); + + // got a fully rendered Outcome! put it in the scrollpane + // initialise container panel + + JTabbedPane outcomeTab = new JTabbedPane(); + outcomeTab.addTab(rootElementDecl.getName(), documentRoot); + outcomeTab.setSelectedIndex(0); + + scrollpane.setViewportView(outcomeTab); + panelBuilt = true; + + revalidate(); + doLayout(); + if (!readOnly) + documentRoot.grabFocus(); + } + + @Override + public JPanel getPanel() throws OutcomeNotInitialisedException + { + return this; + } + + @Override + public String getOutcome() + { + if (useForm) + { + documentRoot.validateStructure(); + return serialize(outcomeDOM, false); + } + else + { + return basicView.getText(); + } + } + + static public String serialize(Document doc, boolean prettyPrint) + { + String serializedDoc = null; + OutputFormat format = new OutputFormat(Method.XML, null, prettyPrint); + StringWriter stringOut = new StringWriter(); + XMLSerializer serial = new XMLSerializer(stringOut, format); + try + { + serial.asDOMSerializer(); + serial.serialize(doc); + } + catch (java.io.IOException ex) + { + Logger.error(ex.toString()); + } + serializedDoc = stringOut.toString(); + return serializedDoc; + } + + @Override + public boolean isUnsaved() { + return unsaved; + } + + @Override + public void saved() { + unsaved = false; + } + + @Override + public void export(File targetFile) throws Exception { + FileStringUtility.string2File(targetFile, getOutcome()); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java new file mode 100644 index 0000000..aee09df --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/OutcomeStructure.java @@ -0,0 +1,283 @@ +package com.c2kernel.gui.tabs.outcome.form; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +import org.exolab.castor.types.AnyNode; +import org.exolab.castor.xml.schema.Annotated; +import org.exolab.castor.xml.schema.Annotation; +import org.exolab.castor.xml.schema.ComplexType; +import org.exolab.castor.xml.schema.ContentModelGroup; +import org.exolab.castor.xml.schema.Documentation; +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Group; +import org.exolab.castor.xml.schema.ModelGroup; +import org.exolab.castor.xml.schema.Order; +import org.exolab.castor.xml.schema.Particle; +import org.exolab.castor.xml.schema.SimpleType; +import org.exolab.castor.xml.schema.SimpleTypesFactory; +import org.exolab.castor.xml.schema.XMLType; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; + +// contains child outcome elements - creates new ones +public abstract class OutcomeStructure extends JPanel { + + ElementDecl model; + Element myElement = null; + boolean readOnly; + HashMap subStructure = new HashMap(); + ArrayList order = new ArrayList(); + String help = ""+Language.translate("No help is available for this element")+""; + HelpPane helpPane; + boolean deferChild = false; + + public OutcomeStructure(ElementDecl model, boolean readOnly , HelpPane helpPane) { + this.model = model; + this.readOnly = readOnly; + this.helpPane = helpPane; + subStructure = new HashMap(); + Logger.msg(8, "Creating " + model.getName() + " structure as " + + this.getClass().getName().substring(this.getClass().getName().lastIndexOf('.') + 1)); + + String doc = extractHelp(model); + if (doc.length() > 0) help = doc; + } + + public boolean getReadOnly() { + return readOnly; + } + /** Contains the rules for deciding which OutcomeStructure will represent a chosen Element Declaration. + * In this order + *
    + *
  1. if maxOccurs>1 then Dimension + *
  2. SimpleTypes are Fields + *
  3. No element children is a Field + *
  4. Everything else is a DataRecord + *
+ */ + public OutcomeStructure createStructure(ElementDecl model, boolean readOnly, HelpPane help) throws OutcomeException { + XMLType elementType = model.getType(); + ComplexType elementComplexType; + + if (model.getMaxOccurs() == 0) return null; + + // if more than one can occur - dimension + if (model.getMaxOccurs() > 1 + || model.getMaxOccurs() == Particle.UNBOUNDED + || model.getMinOccurs() == 0) + return new Dimension(model, readOnly, help); + + // must have a type from now on + if (elementType == null) + throw new StructuralException("Element "+model.getName()+" is elementary yet has no type."); + // simple types will be fields + if (elementType instanceof SimpleType) return new Field(model, readOnly, help); + + // otherwise is a complex type + try { + elementComplexType = (ComplexType)elementType; + } + catch (ClassCastException e) { + throw new StructuralException("Unknown XMLType for element " + model.getName()); + } + + //when no element children - field + if (elementComplexType.getParticleCount() == 0) return new Field(model, readOnly, help); + + //everything else is a data record + return new DataRecord(model, readOnly, help, deferChild); + } + + /** Extracts child Element declarations from a content group and recursively from any group + * (not Element) of that group. calls createStructure() to find the corresponding OutcomeStructure + * then adds it to this structure. + */ + public void enumerateElements(ContentModelGroup group) throws OutcomeException { + + // process base types first if complex type + //HACK: castor does not include elements from basetype, so we do it manually. if they fix it, this will duplicate child elements. + if (group instanceof ComplexType) { + XMLType base = ((ComplexType)group).getBaseType(); + if (base instanceof ComplexType) + enumerateElements((ComplexType)base); + } + + for (Enumeration elements = group.enumerate(); elements.hasMoreElements(); ) { + Particle thisParticle = (Particle)elements.nextElement(); + if (thisParticle instanceof Group) { + Group thisGroup = (Group)thisParticle; + if (thisGroup instanceof ModelGroup) { + // HACK: Castor strangeness - model groups don't seem to resolve their own references. If fixed, this will still work + ModelGroup thisModel = (ModelGroup)thisGroup; + if (thisModel.hasReference()) thisGroup = thisModel.getReference(); + } + Order thisOrder = thisGroup.getOrder(); + if (thisOrder == Order.sequence || thisOrder == Order.all) enumerateElements(thisGroup); + else // we only support sequences in data structures such as these + throw new StructuralException("The '"+thisGroup.getOrder()+"' group is not supported"); + } + else if (thisParticle instanceof ElementDecl) { + ElementDecl thisElement = (ElementDecl)thisParticle; + addStructure(createStructure(thisElement, readOnly, helpPane)); + } + else throw new StructuralException("Particle " + thisParticle.getClass() + " not implemented"); + } + } + + /** Adds a generated OutcomeStructure as a child of this one. A separate structure as is often overridden. + */ + public void addStructure(OutcomeStructure newElement) throws OutcomeException { + if (newElement == null) return; + subStructure.put(newElement.getName(), newElement); + order.add(newElement.getName()); + } + + /** After schema processing, addInstance() propogates the XML instance document down the layout. + * Most OutcomeStructures will throw an exception if called more than once, except Dimension, which is the only + * Outcome Structure to support maxOccurs>1 + */ + public abstract void addInstance(Element myElement, Document parentDoc) throws OutcomeException; + + public Element getElement() { + return myElement; + } + + @Override + public String getName() { + if (model == null) return null; + return model.getName(); + } + + public ElementDecl getModel() { + return model; + } + + public String getHelp() { + return help; + } + + public String validateStructure() { + StringBuffer errors = new StringBuffer(); + for (OutcomeStructure element : subStructure.values()) { + errors.append(element.validateStructure()); + } + return errors.toString(); + } + + public abstract Element initNew(Document parent); + + public static String extractHelp(Annotated model) { + Enumeration e = model.getAnnotations(); + StringBuffer doc = new StringBuffer(); + if (e.hasMoreElements()) { // look for HTML + Annotation note = (Annotation)e.nextElement(); + for (Enumeration g = note.getDocumentation(); g.hasMoreElements();) { + Documentation thisDoc = (Documentation)g.nextElement(); + for (Enumeration h = thisDoc.getObjects(); h.hasMoreElements();) { + AnyNode node = (AnyNode)h.nextElement(); + String line = node.toString(); + if (line.length() == 0) + line = node.getStringValue(); + if (line.length() > 0) { + doc.append(line).append("\n"); + } + } + } + } + + return doc.toString(); + } + + @Override + public abstract void grabFocus(); + + public static Class getJavaClass(int typeCode) { + switch (typeCode) { + + // boolean + case SimpleTypesFactory.BOOLEAN_TYPE: + return Boolean.class; + + // integers + case SimpleTypesFactory.INTEGER_TYPE: + case SimpleTypesFactory.NON_POSITIVE_INTEGER_TYPE: + case SimpleTypesFactory.NEGATIVE_INTEGER_TYPE: + case SimpleTypesFactory.NON_NEGATIVE_INTEGER_TYPE: + case SimpleTypesFactory.POSITIVE_INTEGER_TYPE: + case SimpleTypesFactory.INT_TYPE: + case SimpleTypesFactory.UNSIGNED_INT_TYPE: + case SimpleTypesFactory.SHORT_TYPE: + case SimpleTypesFactory.UNSIGNED_SHORT_TYPE: + case SimpleTypesFactory.LONG_TYPE: + case SimpleTypesFactory.UNSIGNED_LONG_TYPE: + case SimpleTypesFactory.BYTE_TYPE: + case SimpleTypesFactory.UNSIGNED_BYTE_TYPE: + return BigInteger.class; + // floats + case SimpleTypesFactory.FLOAT_TYPE: + case SimpleTypesFactory.DOUBLE_TYPE: + case SimpleTypesFactory.DECIMAL_TYPE: + return BigDecimal.class; + + // images + case SimpleTypesFactory.BASE64BINARY_TYPE: + case SimpleTypesFactory.HEXBINARY_TYPE: + return ImageIcon.class; + + // everything else is a string for now + default: + return String.class; + } + } + + public static Object getTypedValue(String value, Class type) { + try { + if (type.equals(Boolean.class)) + if (value == null || value.equals("")) + return Boolean.FALSE; + else + return Boolean.valueOf(value); + else if (type.equals(BigInteger.class)) + if (value == null || value.equals("")) + return new BigInteger("0"); + else + return new BigInteger(value); + else if (type.equals(BigDecimal.class)) + if (value == null || value.equals("")) + return new BigDecimal(0); + else + return new BigDecimal(value); + } catch (Exception ex) { + Logger.error("Cannot convert value '"+value+"' to a "+type.getName()); + } + return value==null?"":value; + } + + public static boolean isEmpty(Object value) { + if (value == null) return true; + + if (value instanceof String) { + if (((String)value).length() == 0) return true; + } + else if (value instanceof Boolean) { + if (((Boolean)value).booleanValue() == false) return true; + } + else if (value instanceof BigInteger) { + if (((BigInteger)value).intValue() == 0) return true; + } + else if (value instanceof BigDecimal) { + if (((BigDecimal)value).floatValue() == 0.0) return true; + } + return false; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java new file mode 100644 index 0000000..5aff436 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/StructuralException.java @@ -0,0 +1,12 @@ +package com.c2kernel.gui.tabs.outcome.form; +import com.c2kernel.gui.tabs.outcome.OutcomeException; + +public class StructuralException extends OutcomeException { + + public StructuralException() { + super(); + } + public StructuralException(String ex) { + super(ex); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java new file mode 100644 index 0000000..742d1b4 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayEditField.java @@ -0,0 +1,173 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.text.JTextComponent; + +import org.exolab.castor.xml.schema.SimpleType; + +import com.c2kernel.utils.Language; + +/************************************************************************** + * + * $Revision: 1.7 $ + * $Date: 2006/05/24 07:51:51 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ArrayEditField extends StringEditField implements ActionListener { + + Box arrayBox; + Box expandBox; + Box editBox; + JScrollPane arrayView; + JButton arrayButton; + JButton expandButton; + JButton contractButton; + JButton addButton; + JButton removeButton; + ArrayTableModel arrayModel; + JLabel arrayLabel = new JLabel("Array"); + boolean panelShown = false; + boolean readOnly = false; + + public ArrayEditField(SimpleType type) { + arrayBox = Box.createVerticalBox(); + arrayBox.add(arrayLabel); + arrayButton = new JButton(Language.translate("Show")); + arrayButton.addActionListener(this); + arrayButton.setActionCommand("toggle"); + arrayBox.add(arrayButton); + + expandBox = Box.createHorizontalBox(); + expandButton = new JButton(">>"); + expandButton.setToolTipText("Increase the number of columns displaying this array"); + expandButton.addActionListener(this); + expandButton.setActionCommand("extend"); + + contractButton = new JButton("<<"); + contractButton.setToolTipText("Decrease the number of columns displaying this array"); + contractButton.addActionListener(this); + contractButton.setActionCommand("contract"); + + expandBox.add(contractButton); + expandBox.add(Box.createHorizontalGlue()); + expandBox.add(expandButton); + + arrayModel = new ArrayTableModel(type); + if (arrayModel.getColumnCount() < 2) contractButton.setEnabled(false); + arrayView = new JScrollPane(new JTable(arrayModel)); + + editBox = Box.createHorizontalBox(); + addButton = new JButton("+"); + addButton.setToolTipText("Add a field to the end of this array"); + addButton.addActionListener(this); + addButton.setActionCommand("add"); + removeButton = new JButton("-"); + removeButton.setToolTipText("Remove the last field from this array"); + removeButton.addActionListener(this); + removeButton.setActionCommand("remove"); + editBox.add(addButton); + editBox.add(Box.createHorizontalGlue()); + editBox.add(removeButton); + } + /** + * + */ + @Override + public String getDefaultValue() { + return ""; + } + /** + * + */ + @Override + public String getText() { + return arrayModel.getData(); + } + /** + * + */ + @Override + public void setText(String text) { + arrayModel.setData(text); + arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)"); + } + /** + * + */ + @Override + public Component getControl() { + return arrayBox; + } + /** + * + */ + @Override + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("toggle")) { + arrayBox.removeAll(); + if (panelShown) { + arrayBox.add(arrayLabel); + arrayBox.add(Box.createVerticalStrut(7)); + arrayBox.add(arrayButton); + arrayButton.setText("Show"); + } + else { + arrayBox.add(arrayLabel); + arrayBox.add(Box.createVerticalStrut(7)); + arrayBox.add(arrayButton); + arrayBox.add(Box.createVerticalStrut(7)); + arrayBox.add(expandBox); + arrayBox.add(Box.createVerticalStrut(7)); + arrayBox.add(arrayView); + if (!readOnly) arrayBox.add(editBox); + arrayButton.setText("Hide"); + } + panelShown = !panelShown; + arrayBox.validate(); + } + else if (e.getActionCommand().equals("add")) { + arrayModel.addField(); + arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)"); + } + else if (e.getActionCommand().equals("remove")) { + arrayModel.removeField(); + arrayLabel.setText("Array ("+arrayModel.getArrayLength()+" values)"); + } + else { + int currentCols = arrayModel.getColumnCount(); + if (e.getActionCommand().equals("extend")) + currentCols++; + else if (e.getActionCommand().equals("contract")) + currentCols--; + arrayModel.setColumnCount(currentCols); + contractButton.setEnabled(currentCols > 1); + } + + } + + /** + * + */ + @Override + public JTextComponent makeTextField() { + // not used by array + return null; + } + @Override + public void setEditable(boolean editable) { + readOnly = !editable; + arrayModel.setReadOnly(!readOnly); + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java new file mode 100644 index 0000000..341c33a --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ArrayTableModel.java @@ -0,0 +1,113 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.swing.table.AbstractTableModel; + +import org.exolab.castor.xml.schema.SimpleType; + +import com.c2kernel.gui.tabs.outcome.form.OutcomeStructure; +import com.c2kernel.utils.Language; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2006/05/24 07:51:53 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ArrayTableModel extends AbstractTableModel { + + ArrayList contents = new ArrayList(); + Class type; + int numCols = 1; + boolean readOnly = false; + + public ArrayTableModel(SimpleType type) { + super(); + this.type = OutcomeStructure.getJavaClass(type.getTypeCode()); + } + + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + public void setData(String data) { + contents.clear(); + StringTokenizer tok = new StringTokenizer(data); + while(tok.hasMoreTokens()) + contents.add(OutcomeStructure.getTypedValue(tok.nextToken(), type)); + fireTableStructureChanged(); + } + + public String getData() { + if (contents.size() == 0) return ""; + Iterator iter = contents.iterator(); + StringBuffer result = new StringBuffer(iter.next().toString()); + while (iter.hasNext()) + result.append(" ").append(iter.next().toString()); + return result.toString(); + } + + public void addField() { + contents.add(OutcomeStructure.getTypedValue("", type)); + fireTableStructureChanged(); + } + + public void removeField() { + contents.remove(contents.size()-1); + fireTableStructureChanged(); + } + + @Override + public Class getColumnClass(int columnIndex) { + return type; + } + + @Override + public int getColumnCount() { + return numCols; + } + + public int getArrayLength() { + return contents.size(); + } + + public void setColumnCount(int newCols) { + numCols = newCols; + fireTableStructureChanged(); + } + + @Override + public String getColumnName(int column) { + return Language.translate("Value"); + } + + @Override + public int getRowCount() { + return (contents.size()/numCols)+1; + } + + @Override + public Object getValueAt(int arg0, int arg1) { + int index = arg1+(arg0 * numCols); + if (index >= contents.size()) + return null; + return contents.get(arg1+(arg0 * numCols)); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + if (columnIndex+(rowIndex*numCols) > contents.size()-1) return false; + return !readOnly; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + contents.set(columnIndex+(rowIndex*numCols), aValue); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java new file mode 100644 index 0000000..c831eb4 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/BooleanEditField.java @@ -0,0 +1,75 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Component; +import java.awt.event.FocusEvent; + +import javax.swing.JCheckBox; +import javax.swing.text.JTextComponent; + +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.7 $ + * $Date: 2005/08/16 13:59:56 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class BooleanEditField extends StringEditField { + + JCheckBox checkbox; + + public BooleanEditField() { + checkbox = new JCheckBox(); + checkbox.setSelected(false); + checkbox.addFocusListener(this); + } + + @Override + public String getText() { + return String.valueOf(checkbox.isSelected()); + } + + @Override + public void setText(String text) { + boolean newState = false; + try { + newState = Boolean.valueOf(text).booleanValue(); + } catch (Exception ex) { + Logger.error("Invalid value for checkbox: "+text); + } + checkbox.setSelected(newState); + } + + @Override + public void setEditable(boolean editable) { + super.setEditable(editable); + checkbox.setEnabled(editable); + } + + @Override + public Component getControl() { + return checkbox; + } + + @Override + public String getDefaultValue() { + return "false"; + } + + /** don't reserve the item finder for a boolean */ + @Override + public void focusGained(FocusEvent e) { + helpPane.setHelp(name, helpText); + } + + /** + * + */ + @Override + public JTextComponent makeTextField() { + // not used by boolean + return null; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java new file mode 100644 index 0000000..2c4ce05 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ComboField.java @@ -0,0 +1,144 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Component; +import java.util.Enumeration; +import java.util.StringTokenizer; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.text.JTextComponent; + +import org.exolab.castor.types.AnyNode; +import org.exolab.castor.xml.schema.AttributeDecl; +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Facet; +import org.exolab.castor.xml.schema.SimpleType; + +import com.c2kernel.gui.tabs.outcome.form.StructuralException; +import com.c2kernel.scripting.Script; +import com.c2kernel.utils.Logger; + +/******************************************************************************* + * + * $Revision: 1.4 $ $Date: 2005/08/16 13:59:56 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research All + * rights reserved. + ******************************************************************************/ + +public class ComboField extends StringEditField { + + JComboBox comboField; + ListOfValues vals; + DefaultComboBoxModel comboModel; + AnyNode listNode; + + public ComboField(SimpleType type, AnyNode listNode) { + super(); + comboField = new JComboBox(); + content = type; + this.listNode = listNode; + createLOV(); + } + + @Override + public String getDefaultValue() { + if (vals.getDefaultKey() != null) + return vals.get(vals.getDefaultKey()).toString(); + else + return ""; + } + + @Override + public String getText() { + return vals.get(comboModel.getSelectedItem()).toString(); + } + + @Override + public JTextComponent makeTextField() { + // not used by this control + return null; + } + + @Override + public void setText(String text) { + comboModel.setSelectedItem(text); + } + + @Override + public Component getControl() { + return comboField; + } + + private void createLOV() { + vals = new ListOfValues(); + + if (listNode != null) { // schema instructions for list building + String lovType = listNode.getLocalName(); + String param = listNode.getFirstChild().getStringValue(); + if (lovType.equals("ScriptList")) + populateLOVFromScript(param); + if (lovType.equals("PathList")) + populateLOVFromLDAP(param); + } + + // handle enumerations + // TODO: should be ANDed with above results + if (content.hasFacet(Facet.ENUMERATION)) { + //ListOfValues andList = new ListOfValues(); + Enumeration enums = content.getFacets(Facet.ENUMERATION); + while (enums.hasMoreElements()) { + Facet thisEnum = enums.nextElement(); + vals.put(thisEnum.getValue(), thisEnum.getValue(), false); + } + } + + String[] keyArray = new String[vals.keySet().size()]; + comboModel = new DefaultComboBoxModel(vals.keySet().toArray(keyArray)); + comboModel.setSelectedItem(vals.getDefaultKey()); + comboField.setModel(comboModel); + } + + /** + * @param param + */ + private void populateLOVFromLDAP(String param) { + // TODO List of Values from LDAP properties, eg '/root/path;prop=val;prop=val' + + + } + + private void populateLOVFromScript(String scriptName) { + try { + StringTokenizer tok = new StringTokenizer(scriptName, "_"); + if (tok.countTokens() != 2) + throw new Exception("Invalid LOVScript name"); + Script lovscript = new Script(tok.nextToken(), Integer.parseInt(tok.nextToken())); + lovscript.setInputParamValue("LOV", vals); + lovscript.execute(); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + + @Override + public void setDecl(AttributeDecl model) throws StructuralException { + super.setDecl(model); + createLOV(); + } + + @Override + public void setDecl(ElementDecl model) throws StructuralException { + super.setDecl(model); + createLOV(); + } + + /** + * + */ + + @Override + public void setEditable(boolean editable) { + comboField.setEditable(editable); + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java new file mode 100644 index 0000000..fabaed8 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/DecimalEditField.java @@ -0,0 +1,122 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Toolkit; +import java.math.BigDecimal; + +import javax.swing.JTextField; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import javax.swing.text.PlainDocument; + +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2005/08/16 13:59:56 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class DecimalEditField extends StringEditField { + + public DecimalEditField() { + super(); + field.addFocusListener(this); + field.setToolTipText("This field must contains a decimal number e.g. 3.14159265"); + } + + @Override + public String getText() { + return field.getText(); + } + + @Override + public void setText(String text) { + field.setText(text); + } + + @Override + public String getDefaultValue() { + return "0.0"; + } + + @Override + public JTextComponent makeTextField() { + return new DecimalTextField(); + } + + private class DecimalTextField extends JTextField { + + public DecimalTextField() { + super(); + setHorizontalAlignment(RIGHT); + } + @Override + protected Document createDefaultModel() { + return new Decimal(); + } + } + + private class Decimal extends PlainDocument { + + BigDecimal currentVal = new BigDecimal(0.0); + + + @Override + public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { + + if (str == null || str.equals("")) { + return; + } + + String proposedResult = null; + + if (getLength() == 0) { + proposedResult = str; + } else { + StringBuffer currentBuffer = new StringBuffer( this.getText(0, getLength()) ); + currentBuffer.insert(offs, str); + proposedResult = currentBuffer.toString(); + } + + try { + currentVal = parse(proposedResult); + super.insertString(offs, str, a); + } catch (Exception e) { + Toolkit.getDefaultToolkit().beep(); + } + + } + + @Override + public void remove(int offs, int len) throws BadLocationException { + + String currentText = this.getText(0, getLength()); + String beforeOffset = currentText.substring(0, offs); + String afterOffset = currentText.substring(len + offs, currentText.length()); + String proposedResult = beforeOffset + afterOffset; + + if (proposedResult.length() == 0) { // empty is ok + super.remove(offs, len); + return; + } + try { + currentVal = parse(proposedResult); + super.remove(offs, len); + } catch (Exception e) { + Toolkit.getDefaultToolkit().beep(); + } + + } + + public BigDecimal parse(String proposedResult) throws NumberFormatException { + + BigDecimal value = new BigDecimal(0); + if ( proposedResult.length() != 0) { + value = new BigDecimal(proposedResult); + } + return value; + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java new file mode 100644 index 0000000..716a073 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ImageEditField.java @@ -0,0 +1,112 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Component; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileInputStream; +import java.lang.reflect.Array; + +import javax.swing.Box; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JLabel; + +import org.apache.xerces.impl.dv.util.Base64; + +import com.c2kernel.utils.Logger; + +public class ImageEditField extends StringEditField { + + JLabel imageLabel; + + Box imagePanel; + + JButton browseButton; + + String encodedImage; + + static JFileChooser chooser = new JFileChooser(); + static { + chooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter() { + @Override + public String getDescription() { + return "Image Files"; + } + + @Override + public boolean accept(File f) { + return (f.isDirectory() || (f.isFile() && (f.getName() + .endsWith(".gif") + || f.getName().endsWith(".jpg") + || f.getName().endsWith(".jpeg") + || f.getName().endsWith(".png")))); + } + }); + } + + public ImageEditField() { + super(); + imageLabel = new JLabel(); + imagePanel = Box.createVerticalBox(); + browseButton = new JButton("Browse"); + browseButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + int returnVal = chooser.showOpenDialog(null); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = chooser.getSelectedFile(); + try { + FileInputStream fis = new FileInputStream(file); + byte[] bArray = (byte[]) Array.newInstance(byte.class, + (int) file.length()); + fis.read(bArray, 0, (int) file.length()); + fis.close(); + + ImageIcon newImage = new ImageIcon(Toolkit + .getDefaultToolkit().createImage(bArray)); + imageLabel.setIcon(newImage); + encodedImage = Base64.encode(bArray); + } catch (Exception ex) { + Logger.exceptionDialog(ex); + } + } + } + }); + imagePanel.add(imageLabel); + imagePanel.add(Box.createVerticalStrut(5)); + imagePanel.add(browseButton); + } + + @Override + public String getDefaultValue() { + return ""; + } + + @Override + public Component getControl() { + return imagePanel; + } + + @Override + public String getText() { + return encodedImage == null ? "" : encodedImage; + } + + @Override + public void setText(String text) { + encodedImage = text; + if (text != null && text.length() > 0) { + byte[] decodedImage = Base64.decode(encodedImage); + imageLabel.setIcon(new ImageIcon(Toolkit.getDefaultToolkit() + .createImage(decodedImage))); + } + } + + @Override + public void setEditable(boolean editable) { + browseButton.setVisible(false); + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java new file mode 100644 index 0000000..e2c3df4 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/IntegerEditField.java @@ -0,0 +1,120 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Toolkit; +import java.math.BigInteger; + +import javax.swing.JTextField; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import javax.swing.text.PlainDocument; + +/************************************************************************** + * + * $Revision: 1.4 $ + * $Date: 2005/08/16 13:59:56 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class IntegerEditField extends StringEditField { + + public IntegerEditField() { + super(); + field.setToolTipText("This field must contains a whole number e.g. 3"); + } + + @Override + public String getText() { + return field.getText(); + } + + @Override + public void setText(String text) { + field.setText(text); + } + + @Override + public String getDefaultValue() { + return "0"; + } + + @Override + public JTextComponent makeTextField() { + return new IntegerTextField(); + } + + private class IntegerTextField extends JTextField { + + public IntegerTextField() { + super(); + setHorizontalAlignment(RIGHT); + } + @Override + protected Document createDefaultModel() { + return new IntegerDocument(); + } + } + + private class IntegerDocument extends PlainDocument { + + BigInteger currentVal = new BigInteger("0"); + + @Override + public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { + + if (str == null || str.equals("")) { + return; + } + + String proposedResult = null; + + if (getLength() == 0) { + proposedResult = str; + } else { + StringBuffer currentBuffer = new StringBuffer( this.getText(0, getLength()) ); + currentBuffer.insert(offs, str); + proposedResult = currentBuffer.toString(); + } + + try { + currentVal = parse(proposedResult); + super.insertString(offs, str, a); + } catch (Exception e) { + Toolkit.getDefaultToolkit().beep(); + } + + } + + @Override + public void remove(int offs, int len) throws BadLocationException { + + String currentText = this.getText(0, getLength()); + String beforeOffset = currentText.substring(0, offs); + String afterOffset = currentText.substring(len + offs, currentText.length()); + String proposedResult = beforeOffset + afterOffset; + if (proposedResult.length() == 0) { // empty is ok + super.remove(offs, len); + return; + } + + try { + currentVal = parse(proposedResult); + super.remove(offs, len); + } catch (Exception e) { + Toolkit.getDefaultToolkit().beep(); + } + + } + + public BigInteger parse(String proposedResult) throws NumberFormatException { + + BigInteger value = new BigInteger("0"); + if ( proposedResult.length() != 0) { + value = new BigInteger(proposedResult); + } + return value; + } + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java new file mode 100644 index 0000000..f95c5c9 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/ListOfValues.java @@ -0,0 +1,31 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.util.HashMap; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2005/04/26 06:48:12 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ListOfValues extends HashMap { + + String defaultKey = null; + + public ListOfValues() { + super(); + } + + public String put(String key, String value, boolean isDefaultKey) { + if (isDefaultKey) defaultKey = key; + return (String)super.put(key, value); + } + + public String getDefaultKey() { + return defaultKey; + } + +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java new file mode 100644 index 0000000..140d7f2 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/LongStringEditField.java @@ -0,0 +1,40 @@ +package com.c2kernel.gui.tabs.outcome.form.field; + +import java.awt.Component; + +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.text.JTextComponent; + +import com.c2kernel.utils.Language; + + +/************************************************************************** + * + * $Revision$ + * $Date$ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class LongStringEditField extends StringEditField { + + JTextArea bigText; + JScrollPane bigScroller; + public LongStringEditField() { + super(); + field.setToolTipText(Language.translate("This field can contain any string.")); + } + + @Override + public JTextComponent makeTextField() { + return new JTextArea(); + } + @Override + public Component getControl() { + if (bigScroller == null) { + bigScroller = new JScrollPane(field); + } + return bigScroller; + } +} diff --git a/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java new file mode 100644 index 0000000..0e5fee9 --- /dev/null +++ b/src/main/java/com/c2kernel/gui/tabs/outcome/form/field/StringEditField.java @@ -0,0 +1,257 @@ +package com.c2kernel.gui.tabs.outcome.form.field; +import java.awt.Component; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Enumeration; + +import javax.swing.ImageIcon; +import javax.swing.JTextField; +import javax.swing.text.JTextComponent; + +import org.exolab.castor.types.AnyNode; +import org.exolab.castor.xml.schema.Annotation; +import org.exolab.castor.xml.schema.AppInfo; +import org.exolab.castor.xml.schema.AttributeDecl; +import org.exolab.castor.xml.schema.ElementDecl; +import org.exolab.castor.xml.schema.Facet; +import org.exolab.castor.xml.schema.SimpleType; +import org.exolab.castor.xml.schema.Structure; +import org.exolab.castor.xml.schema.XMLType; +import org.exolab.castor.xml.schema.simpletypes.ListType; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import com.c2kernel.gui.DomainKeyConsumer; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.form.HelpPane; +import com.c2kernel.gui.tabs.outcome.form.OutcomeStructure; +import com.c2kernel.gui.tabs.outcome.form.StructuralException; +import com.c2kernel.lookup.DomainPath; + +/** Superclass for the entry field for Field and AttributeList. + */ +public class StringEditField implements FocusListener, DomainKeyConsumer { + + Node data; + Structure model; + protected SimpleType content; + HelpPane helpPane; + String helpText; + protected JTextComponent field; + + boolean isValid = true; + boolean editable = true; + String name; + + + public StringEditField() { + field = makeTextField(); + if (field != null) + field.addFocusListener(this); + } + + private static StringEditField getFieldForType(SimpleType type) { + // handle lists special + if (type instanceof ListType) + return new ArrayEditField(type.getBuiltInBaseType()); + + // is a combobox + if (type.hasFacet(Facet.ENUMERATION)) + return new ComboField(type, null); + //find LOVscript TODO: Implement LOV + Enumeration e = type.getAnnotations(); + while (e.hasMoreElements()) { + Annotation note = e.nextElement(); + for (Enumeration f = note.getAppInfo(); f.hasMoreElements();) { + AppInfo thisAppInfo = f.nextElement(); + for (Enumeration g = thisAppInfo.getObjects(); g.hasMoreElements();) { + AnyNode appInfoNode = (AnyNode)g.nextElement(); + if (appInfoNode.getLocalName().equals("ScriptList") + || appInfoNode.getLocalName().equals("LDAPList")) { + return new ComboField(type, appInfoNode); + } + } + } + } + // find info on length before we go to the base type + long length = -1; + if (type.getLength()!=null) length = type.getLength().longValue(); + else if (type.getMaxLength()!=null) length = type.getMaxLength().longValue(); + else if (type.getMinLength()!=null) length = type.getMinLength().longValue(); + + // find base type if derived + if (!(type.isBuiltInType())) + type = type.getBuiltInBaseType(); + // else derive the class + Class contentClass = OutcomeStructure.getJavaClass(type.getTypeCode()); + // disable list edits for the moment + if (contentClass.equals(Boolean.class)) + return new BooleanEditField(); + else if (contentClass.equals(BigInteger.class)) + return new IntegerEditField(); + else if (contentClass.equals(BigDecimal.class)) + return new DecimalEditField(); + else if (contentClass.equals(ImageIcon.class)) + return new ImageEditField(); + else if (length > 60) + return new LongStringEditField(); + else return new StringEditField(); + } + + public static StringEditField getEditField(AttributeDecl model) throws StructuralException { + if (model.isReference()) model = model.getReference(); + StringEditField newField = getFieldForType(model.getSimpleType()); + newField.setDecl(model); + return newField; + } + + public static StringEditField getEditField(ElementDecl model) throws StructuralException { + try { + XMLType baseType = model.getType(); + while (!(baseType instanceof SimpleType)) + baseType = baseType.getBaseType(); + StringEditField newField = getFieldForType((SimpleType)baseType); + newField.setDecl(model); + return newField; + } catch (Exception ex) { + throw new StructuralException("No type defined in model"); + } + } + + public void setDecl(AttributeDecl model) throws StructuralException { + this.model=model; + this.content=model.getSimpleType(); + this.name = model.getName(); + if (model.isFixed()) setEditable(false); + } + + public void setDecl(ElementDecl model) throws StructuralException { + this.model=model; + this.name = model.getName(); + XMLType type = model.getType(); + + // derive base type + if (type.isSimpleType()) + this.content = (SimpleType)type; + else + this.content = (SimpleType)(type.getBaseType()); + + if (this.content == null) throw new StructuralException("No declared base type of element"); + + // + if (model.getFixedValue() != null) setEditable(false); + + } + + public void setData(Attr newData) throws StructuralException { + if (!(newData.getName().equals(name))) + throw new StructuralException("Tried to add a "+newData.getName()+" into a "+name+" attribute."); + + this.data = newData; + setText(newData.getValue()); + } + + public void setData(Text newData) { + String contents = newData.getData(); + this.data = newData; + setText(contents); + } + + public void setData(String newData) throws OutcomeException { + if (data == null) throw new OutcomeException("No node exists"); + setText(newData); + updateNode(); + + } + + public Structure getModel() { + return model; + } + + public String getName() { + return name; + } + + public Node getData() { + return data; + } + + public String getDefaultValue() { + return ""; + } + + public void setHelp(HelpPane helpPane, String helpText) { + this.helpPane = helpPane; + this.helpText = helpText; + } + + @Override + public void focusLost(FocusEvent e) { + if (MainFrame.itemFinder != null) + MainFrame.itemFinder.clearConsumer(this); + updateNode(); + } + + @Override + public void focusGained(FocusEvent e) { + helpPane.setHelp(name, helpText); + if (editable && MainFrame.itemFinder != null) + MainFrame.itemFinder.setConsumer(this, "Insert"); + } + + public void updateNode() { + if (data == null) return; + if (data instanceof Text) { + ((Text)data).setData(getText()); + } + else { //attribute + ((Attr)data).setValue(getText()); + } + } + + /** + * Read domkey from barcode input + */ + @Override + public void push(DomainPath key) { + setText(key.getName()); + } + + /** + * Read string from barcode input + */ + @Override + public void push(String key) { + setText(key); + } + + public void setEditable(boolean editable) { + this.editable = editable; + if (field != null) + field.setEditable(editable); + } + + public String getText() { + return field.getText(); + } + + public void setText(String text) { + field.setText(text); + } + + public JTextComponent makeTextField() { + return new JTextField(); + } + + public Component getControl() { + return field; + } + + public void grabFocus() { + getControl().requestFocus(); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/ActivityDef.java b/src/main/java/com/c2kernel/lifecycle/ActivityDef.java new file mode 100644 index 0000000..235275f --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/ActivityDef.java @@ -0,0 +1,143 @@ +package com.c2kernel.lifecycle; +import java.util.Vector; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.lifecycle.instance.stateMachine.StateMachine; +import com.c2kernel.utils.FileStringUtility; +/** + * @version $Revision: 1.45 $ $Date: 2005/10/05 07:39:36 $ + * @author $Author: abranson $ + */ +public class ActivityDef extends WfVertexDef implements C2KLocalObject +{ + private int mId = -1; + private String mName = ""; + private String mVersion = ""; + public boolean changed = false; + /** + * @see java.lang.Object#Object() + */ + public ActivityDef() + { + mErrors = new Vector(0, 1); + setProperties(new WfCastorHashMap()); + setIsLayoutable(false); + getProperties().put(StateMachine.SKIPPABLE, new Boolean(false)); + getProperties().put(StateMachine.REPEATABLE, new Boolean(false)); + getProperties().put(StateMachine.IGNORABLE, new Boolean(false)); + } + /** + * @see com.c2kernel.graph.model.Vertex#setID(int) + */ + @Override + public void setID(int id) + { + mId = id; + if (mName.equals("")) + setName(String.valueOf(id)); + } + /** + * @see com.c2kernel.graph.model.Vertex#getID() + */ + @Override + public int getID() + { + return mId; + } + /** + * @see com.c2kernel.graph.model.Vertex#setName(java.lang.String) + */ + @Override + public void setName(String n) + { + mName = n; + } + /** + * @see com.c2kernel.graph.model.Vertex#getName() + */ + @Override + public String getName() + { + return mName; + } + + public void setVersion(String v) + { + mVersion = v; + } + /** + * @see com.c2kernel.graph.model.Vertex#getName() + */ + public String getVersion() + { + return mVersion; + } + /** + * @see com.c2kernel.lifecycle.WfVertexDef#getErrors() + */ + @Override + public String getErrors() + { + return super.getErrors(); + } + /** + * Method linkToSlot. + * + * @param actSl + * @param name + */ + public void linkToSlot(ActivitySlotDef actSl, String name, String name2) + { + actSl.setActivityDef(FileStringUtility.convert(name)); + actSl.getProperties().put("Name", name2.replace('/', '_')); + actSl.setName(name+" slot"); + setName(FileStringUtility.convert(name)); + } + /** + * @see com.c2kernel.lifecycle.WfVertexDef#verify() + */ + @Override + public boolean verify() + { + return true; + } + /** + * @see com.c2kernel.entity.C2KLocalObject#getClusterType() + */ + @Override + public String getClusterType() + { + return null; + } + public String getActName() + { + return getName(); + } + + /* + * (non-Javadoc) + * + * @see com.c2kernel.lifecycle.commonInterface.ActType#getDescName() + */ + public String getDescName() + { + return getName(); + } + + @Override + public WfVertex instantiate() throws ObjectNotFoundException, InvalidDataException{ + return instantiate(getName()); + } + public WfVertex instantiate(String name) throws ObjectNotFoundException, InvalidDataException + { + Activity act = new Activity(); + configureInstance(act); + act.setName(name); + act.setType(getName()); + return act; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/ActivitySlotDef.java b/src/main/java/com/c2kernel/lifecycle/ActivitySlotDef.java new file mode 100644 index 0000000..74d8305 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/ActivitySlotDef.java @@ -0,0 +1,156 @@ +package com.c2kernel.lifecycle; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.utils.KeyValuePair; +import com.c2kernel.utils.LocalObjectLoader; +/** + * @version $Revision: 1.46 $ $Date: 2005/10/05 07:39:36 $ + * @author $Author: abranson $ + */ +public class ActivitySlotDef extends WfVertexDef +{ + private String activityDef; + + /** + * Method setActivityDef. + * + * @param oActivityDef + */ + public void setActivityDef(String oActivityDef) + { + activityDef = oActivityDef; + } + /** + * Method getActivityDef. + * + * @return String + */ + public String getActivityDef() + { + return activityDef; + } + /** + * @see java.lang.Object#Object() + */ + public ActivitySlotDef() + { + getProperties().put("Name", ""); + getProperties().put("Version", "last"); + } + + public ActivityDef getTheActivityDef() throws ObjectNotFoundException, InvalidDataException + { + ActivityDef actDef = LocalObjectLoader.getActDef(getActivityDef(), getActVersion()); + if (actDef instanceof CompositeActivityDef) + mIsComposite = true; + return actDef; + } + /** + * @see com.c2kernel.lifecycle.WfVertexDef#verify() + */ + /** launch the verification of the ActivityDef */ + @Override + public boolean verify() + { + mErrors.removeAllElements(); + boolean err = true; + int nbInEdgres = getInEdges().length; + int nbOutEdges = getOutEdges().length; + if (nbInEdgres == 0 && this.getID() != getParent().getChildrenGraphModel().getStartVertexId()) + { + mErrors.add("Unreachable"); + err = false; + } + else if (nbInEdgres > 1) + { + mErrors.add("Bad nb of previous"); + err = false; + } + else if (nbOutEdges > 1) + { + mErrors.add("too many next"); + err = false; + } + else if (nbOutEdges == 0) + { + if (!((CompositeActivityDef) getParent()).hasGoodNumberOfActivity()) + { + mErrors.add("too many endpoints"); + err = false; + } + } + else + { + Vertex[] outV = getOutGraphables(); + Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + boolean errInLoop = false; + for (Vertex element : outV) { + for (Vertex anteVertice : anteVertices) + if (!loop() && element.getID() == anteVertice.getID()) + errInLoop = true; + } + if (errInLoop) + { + mErrors.add("Problem in Loop"); + err = false; + } + } + return err; + } + /** + * Method getNextWfVertices. + * + * @return WfVertexDef[] + */ + public WfVertexDef[] getNextWfVertices() + { + return (WfVertexDef[]) getOutGraphables(); + } + /** + * @see com.c2kernel.graph.model.GraphableVertex#isLayoutable() + */ + /** + * @see com.c2kernel.graph.model.GraphableVertex#getIsLayoutable() + */ + public boolean isLayoutable() + { + return true; + } + /** + * Method getInfo. + * + * @return CastorHashMap + */ + public void configureInstance(Activity act) + { + KeyValuePair[] k = getProperties().getKeyValuePairs(); + for (KeyValuePair element : k) + act.getProperties().put(element.getKey(), element.getValue()); + act.setCentrePoint(getCentrePoint()); + act.setOutlinePoints(getOutlinePoints()); + act.setInEdgeIds(getInEdgeIds()); + act.setOutEdgeIds(getOutEdgeIds()); + act.setName(getActName()); + act.setID(getID()); + } + + public String getActName() + { + return (String) getProperties().get("Name"); + } + public String getActVersion() + { + return (String) getProperties().get("Version"); + } + + @Override + public WfVertex instantiate() throws ObjectNotFoundException, InvalidDataException { + Activity newActivity = (Activity)getTheActivityDef().instantiate(); + configureInstance(newActivity); + return newActivity; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/AndSplitDef.java b/src/main/java/com/c2kernel/lifecycle/AndSplitDef.java new file mode 100644 index 0000000..af87b18 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/AndSplitDef.java @@ -0,0 +1,114 @@ +package com.c2kernel.lifecycle; + +import java.util.Vector; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lifecycle.instance.AndSplit; +import com.c2kernel.lifecycle.instance.WfVertex; +/** + * @version $Revision: 1.19 $ $Date: 2005/09/29 10:18:31 $ + * @author $Author: abranson $ + */ + +public class AndSplitDef extends WfVertexDef +{ + /** + * @see java.lang.Object#Object() + */ + public AndSplitDef() + { + mErrors = new Vector(0, 1); + getProperties().put("RoutingScriptName", ""); + getProperties().put("RoutingScriptVersion", ""); + } + + /** + * @see com.c2kernel.lifecycle.WfVertexDef#verify() + */ + @Override + public boolean verify() + { + mErrors.removeAllElements(); + boolean err = true; + int nbInEdges = getInEdges().length; + if (nbInEdges == 0 && this.getID() != getParent().getChildrenGraphModel().getStartVertexId()) + { + mErrors.add("Unreachable"); + err = false; + } + else if (nbInEdges > 1) + { + mErrors.add("Bad nb of previous"); + err = false; + } + else + { + if (getOutEdges().length <= 1) + { + mErrors.add("not enough next"); + err = false; + } + else if (!(this instanceof LoopDef)) + { + Vertex[] outV = getOutGraphables(); + Vertex[] anteVertices = + GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + boolean loop = false; + boolean errInLoop = true; + for (int i = 0; i < outV.length; i++) + { + for (int j = 0; j < anteVertices.length; j++) + if (!loop && outV[i].getID() == anteVertices[j].getID()) + { + if (outV[i] instanceof LoopDef) + { + loop = true; + j = anteVertices.length; + i = outV.length; + } + else + { + errInLoop = false; + } + } + } + if (errInLoop && loop) + { + mErrors.add("Problem in Loop"); + err = false; + } + } + } + return err; + } + + @Override + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + { + Vertex[] outVertices = getOutGraphables(); + for (int i = 0; i < outVertices.length; i++) + { + WfVertexDef tmp = (WfVertexDef) getOutGraphables()[i]; + loop2 = loop2 || tmp.loop(); + } + } + } + loopTested = false; + return loop2; + } + + @Override + public WfVertex instantiate() { + AndSplit newSplit = new AndSplit(); + configureInstance(newSplit); + return newSplit; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/CompositeActivityDef.java b/src/main/java/com/c2kernel/lifecycle/CompositeActivityDef.java new file mode 100644 index 0000000..86b6f88 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/CompositeActivityDef.java @@ -0,0 +1,227 @@ +package com.c2kernel.lifecycle; +import java.awt.Point; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.GraphModel; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.lifecycle.gui.model.WfVertexDefOutlineCreator; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Next; +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.93 $ $Date: 2005/10/05 07:39:36 $ + * @author $Author: abranson $ + */ +public class CompositeActivityDef extends ActivityDef +{ + private final TypeNameAndConstructionInfo[] mVertexTypeNameAndConstructionInfo = + { + new TypeNameAndConstructionInfo(Language.translate("Atomic"), "Atomic"), + new TypeNameAndConstructionInfo(Language.translate("Composite"), "Composite"), + new TypeNameAndConstructionInfo(Language.translate("AND Split"), "And"), + new TypeNameAndConstructionInfo(Language.translate("OR Split"), "Or"), + new TypeNameAndConstructionInfo(Language.translate("XOR Split"), "XOr"), + new TypeNameAndConstructionInfo(Language.translate("Junction"), "Join"), + new TypeNameAndConstructionInfo(Language.translate("Loop"), "Loop"), + }; + private final TypeNameAndConstructionInfo[] mEdgeTypeNameAndConstructionInfo = + { + new TypeNameAndConstructionInfo(Language.translate("Next Edge"), "Next") + }; + public TypeNameAndConstructionInfo[] getVertexTypeNameAndConstructionInfo() + { + return mVertexTypeNameAndConstructionInfo; + } + public TypeNameAndConstructionInfo[] getEdgeTypeNameAndConstructionInfo() + { + return mEdgeTypeNameAndConstructionInfo; + } + + public CompositeActivityDef() + { + super(); + setChildrenGraphModel(new GraphModel(new WfVertexDefOutlineCreator())); + setIsComposite(true); + } + + /** + * Method addNextDef. + * + * @param origin + * @param terminus + * @return NextDef + */ + public NextDef addNextDef(WfVertexDef origin, WfVertexDef terminus) + { + NextDef returnNxt = new NextDef(origin, terminus); + getChildrenGraphModel().addEdgeAndCreateId(returnNxt, origin, terminus); + return returnNxt; + } + /** + * Method addExistingActivityDef. + * + * @param actDef + * @param point + */ + public ActivitySlotDef addExistingActivityDef(String name, ActivityDef actDef, GraphPoint point) + { + changed = true; + ActivitySlotDef child = new ActivitySlotDef(); + addChild(child, point); + actDef.linkToSlot(child, actDef.getName(), name); + return child; + } + /** + * Method newChild. + * + * @param Name + * @param Type + * @param location + * @return WfVertexDef + */ + public WfVertexDef newChild(String Name, String Type, Point location) + { + changed = true; + WfVertexDef child; + if (Type.equals("Or")) + { + child = new OrSplitDef(); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("XOr")) + { + child = new XOrSplitDef(); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("And")) + { + child = new AndSplitDef(); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("Loop")) + { + child = new LoopDef(); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("Atomic")) + { + child = new ActivitySlotDef(); + ActivityDef act = new ActivityDef(); + act.changed = true; + addChild(child, location); + act.linkToSlot((ActivitySlotDef) child, Name, Name); + act.getProperties().put("Description", Name); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("Join")) + { + child = new JoinDef(); + child.getProperties().put("Type", "Join"); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else if (Type.equals("Route")) + { + child = new JoinDef(); + child.getProperties().put("Type", "Route"); + addChild(child, location); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + else + { + child = new ActivitySlotDef(); + CompositeActivityDef act = new CompositeActivityDef(); + act.changed = true; + addChild(child, location); + act.linkToSlot((ActivitySlotDef) child, Name, Name); + Logger.msg(5, Type + " " + child.getID() + " added to " + this.getID()); + } + return child; + } + /** + * Method instantiateAct. + * + * @return CompositeActivity + */ + @Override + public WfVertex instantiate() throws ObjectNotFoundException, InvalidDataException { + return instantiate(getName()); + } + + @Override + public WfVertex instantiate(String name) throws ObjectNotFoundException, InvalidDataException + { + CompositeActivity cAct = new CompositeActivity(); + cAct.setType(getName()); + cAct.setName(name); + GraphableVertex[] vertexDefs = getLayoutableChildren(); + WfVertex[] wfVertices = new WfVertex[vertexDefs.length]; + for (int i = 0; i < vertexDefs.length; i++) + { + WfVertexDef vertDef = (WfVertexDef)vertexDefs[i]; + wfVertices[i] = vertDef.instantiate(); + wfVertices[i].setParent(cAct); + } + Next[] nexts = new Next[getChildrenGraphModel().getEdges().length]; + for (int i = 0; i < getChildrenGraphModel().getEdges().length; i++) + { + NextDef nextDef = (NextDef) getChildrenGraphModel().getEdges()[i]; + nexts[i] = nextDef.instantiate(); + nexts[i].setParent(cAct); + } + cAct.getChildrenGraphModel().setStartVertexId(getChildrenGraphModel().getStartVertexId()); + cAct.getChildrenGraphModel().setEdges(nexts); + cAct.getChildrenGraphModel().setVertices(wfVertices); + cAct.getChildrenGraphModel().setNextId(getChildrenGraphModel().getNextId()); + cAct.getChildrenGraphModel().resetVertexOutlines(); + return cAct; + } + + /** + * Method hasGoodNumberOfActivity. + * + * @return boolean + */ + + public boolean hasGoodNumberOfActivity() + { + int endingAct = 0; + GraphableVertex[] graphableVertices = this.getLayoutableChildren(); + if (graphableVertices != null) + for (GraphableVertex graphableVertice : graphableVertices) { + WfVertexDef vertex = (WfVertexDef) graphableVertice; + if (getChildrenGraphModel().getOutEdges(vertex).length == 0) + endingAct++; + } + if (endingAct > 1) + return false; + return true; + } + + /** + * @see com.c2kernel.graph.model.GraphableVertex#getPath() + */ + @Override + public String getPath() + { + if (getParent() == null) + return getName(); + return super.getPath(); + } + + //deprecated + public String[] getCastorNonLayoutableChildren() { + return new String[0]; + } + + public void setCastorNonLayoutableChildren(String[] dummy) { } +} diff --git a/src/main/java/com/c2kernel/lifecycle/JoinDef.java b/src/main/java/com/c2kernel/lifecycle/JoinDef.java new file mode 100644 index 0000000..95e2ec4 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/JoinDef.java @@ -0,0 +1,68 @@ +package com.c2kernel.lifecycle; + +import com.c2kernel.lifecycle.instance.Join; +import com.c2kernel.lifecycle.instance.WfVertex; + +/** + * @version $Revision: 1.18 $ $Date: 2005/09/29 10:18:31 $ + * @author $Author: abranson $ + */ +public class JoinDef extends WfVertexDef +{ + /** + * @see java.lang.Object#Object() + */ + public JoinDef() + { + } + /** + * @see com.c2kernel.lifecycle.WfVertexDef#verify() + */ + @Override + public boolean verify() + { + mErrors.removeAllElements(); + int nbOutEdges = getOutEdges().length; + int nbInEdges = getInEdges().length; + String type = (String) getProperties().get("Type"); + if (nbInEdges < 1) + { + mErrors.add("not enough previous"); + return false; + } + if (type != null && type.equals("Route")) + { + if (nbInEdges > 1) + { + mErrors.add("Bad nb of previous"); + return false; + } + } + if (nbOutEdges > 1) + { + mErrors.add("too many next"); + return false; + } + if (nbOutEdges == 0) + { + if (!((CompositeActivityDef) getParent()).hasGoodNumberOfActivity()) + { + mErrors.add("too many endpoints"); + return false; + } + } + return true; + } + @Override + public boolean isJoin() + { + return true; + } + + @Override + public WfVertex instantiate() { + Join newJoin = new Join(); + configureInstance(newJoin); + return newJoin; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/LoopDef.java b/src/main/java/com/c2kernel/lifecycle/LoopDef.java new file mode 100644 index 0000000..36108ad --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/LoopDef.java @@ -0,0 +1,78 @@ +package com.c2kernel.lifecycle; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lifecycle.instance.Loop; +import com.c2kernel.lifecycle.instance.WfVertex; + +/** + * @version $Revision: 1.19 $ $Date: 2005/09/29 10:18:31 $ + * @author $Author: abranson $ + */ + +public class LoopDef extends XOrSplitDef +{ + public boolean hasLoop = false; + public int isNext = 0; + + /** + * @see java.lang.Object#Object() + */ + public LoopDef() + { + super(); + } + + /** + * @see com.c2kernel.lifecycle.WfVertexDef#loop() + */ + @Override + public boolean loop() + { + return true; + } + + /** + * @see com.c2kernel.lifecycle.WfVertexDef#verify() + */ + @Override + public boolean verify() + { + if (!super.verify()) return false; + Vertex[] nexts = getOutGraphables(); + Vertex[] anteVertices = + GraphTraversal.getTraversal(this.getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + int k = 0; + int l = 0; + Vertex[] brothers = getParent().getChildren(); + for (Vertex brother : brothers) + if (brother instanceof LoopDef) l++; + for (Vertex next : nexts) + for (Vertex anteVertice : anteVertices) + if (next.equals(anteVertice)) + k++; + if (k != 1 && !(l>1)) + { + mErrors.add("bad number of pointing back nexts"); + return false; + } +// if (nexts.length>2) { +// mErrors.add("you must only have 2 nexts"); +// return false; +// } + return true; + } + + @Override + public boolean isLoop() { + return true; + } + + @Override + public WfVertex instantiate() { + Loop newLoop = new Loop(); + configureInstance(newLoop); + return newLoop; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/NextDef.java b/src/main/java/com/c2kernel/lifecycle/NextDef.java new file mode 100644 index 0000000..d196066 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/NextDef.java @@ -0,0 +1,95 @@ +package com.c2kernel.lifecycle; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.GraphableEdge; +import com.c2kernel.lifecycle.instance.Next; +/** + * @version $Revision: 1.32 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ +public class NextDef extends GraphableEdge +{ + /** + * @see java.lang.Object#Object() + */ + public NextDef() + { + } + /** + * Method verify. + * + * @return boolean + */ + public boolean verify() + { + return true; + } + /** + * Method NextDef. + * + * @param pre + * @param nex + */ + /** create and initialize a link between an Activities */ + public NextDef(WfVertexDef pre, WfVertexDef nex) + { + setParent(pre.getParent()); + if (pre instanceof OrSplitDef || pre instanceof XOrSplitDef) + { + int num = pre.getOutGraphables().length; + try + { + num = Integer.parseInt((String) pre.getProperties().get("LastNum")); + } + catch (Exception e) + { + } + getProperties().put("Alias", String.valueOf(num)); + pre.getProperties().put("LastNum", String.valueOf(num + 1)); + } + } + @Override + public boolean containsPoint(GraphPoint p) + { + GraphPoint originPoint = getOriginPoint(); + GraphPoint terminusPoint = getTerminusPoint(); + GraphPoint midPoint = new GraphPoint(); + if (("Broken +".equals(getProperties().get("Type")))) + { + midPoint.x = (originPoint.x + terminusPoint.x) / 2; + midPoint.y = (originPoint.y + terminusPoint.y) / 2; + } + else if (("Broken -".equals(getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + } + else if (("Broken |".equals(getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + } + else + { + midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + } + int minX = midPoint.x - 10; + int minY = midPoint.y - 10; + int maxX = midPoint.x + 10; + int maxY = midPoint.y + 10; + return (p.x >= minX) && (p.x <= maxX) && (p.y >= minY) && (p.y <= maxY); + } + + public Next instantiate() { + Next next = new Next(); + next.setID(getID()); + next.setOriginVertexId(getOriginVertexId()); + next.setTerminusVertexId(getTerminusVertexId()); + next.setProperties(getProperties()); + next.setOriginPoint(getOriginPoint()); + next.setTerminusPoint(getTerminusPoint()); + return next; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/OrSplitDef.java b/src/main/java/com/c2kernel/lifecycle/OrSplitDef.java new file mode 100644 index 0000000..df68f22 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/OrSplitDef.java @@ -0,0 +1,24 @@ +package com.c2kernel.lifecycle; +import com.c2kernel.lifecycle.instance.OrSplit; +import com.c2kernel.lifecycle.instance.WfVertex; +/** + * @version $Revision: 1.13 $ $Date: 2005/12/01 14:23:15 $ + * @author $Author: abranson $ + */ +public class OrSplitDef extends AndSplitDef +{ + /** + * @see java.lang.Object#Object() + */ + public OrSplitDef() + { + super(); + } + + @Override + public WfVertex instantiate() { + OrSplit newSplit = new OrSplit(); + configureInstance(newSplit); + return newSplit; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/WfCastorHashMap.java b/src/main/java/com/c2kernel/lifecycle/WfCastorHashMap.java new file mode 100644 index 0000000..7d88ea9 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/WfCastorHashMap.java @@ -0,0 +1,33 @@ +package com.c2kernel.lifecycle; +import com.c2kernel.lifecycle.instance.stateMachine.StateMachine; +import com.c2kernel.utils.CastorHashMap; +/** + * @version $Revision: 1.29 $ $Date: 2005/05/20 13:07:13 $ + * @author $Author: abranson $ + */ +public class WfCastorHashMap extends CastorHashMap +{ + /** + * @see java.lang.Object#Object() + */ + public WfCastorHashMap() + { + put(StateMachine.AUTOSTART, new Boolean(true)); + put(StateMachine.SKIPPABLE, new Boolean(true)); + put(StateMachine.REPEATABLE, new Boolean(true)); + put(StateMachine.IGNORABLE, new Boolean(false)); + put("AlwaysUseOutcome", new Boolean(false)); + put("Viewpoint", ""); + put("Show time", new Boolean(true)); + put("Description", ""); + put("Mail Message", ""); + put("Mail event", ""); + put("Agent Role", ""); + put("Agent Name", ""); + put("SchemaType", ""); + put("SchemaVersion", ""); + put("ScriptName", ""); + put("ScriptVersion", ""); + put("Viewpoint", ""); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/WfVertexDef.java b/src/main/java/com/c2kernel/lifecycle/WfVertexDef.java new file mode 100644 index 0000000..6a46bee --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/WfVertexDef.java @@ -0,0 +1,83 @@ +package com.c2kernel.lifecycle; + +import java.util.Vector; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.utils.KeyValuePair; + +/** + * @version $Revision: 1.22 $ $Date: 2005/11/15 15:56:38 $ + * @author $Author: abranson $ + */ +public abstract class WfVertexDef extends GraphableVertex +{ + public Vector mErrors; + + protected boolean loopTested; + + /** + * @see java.lang.Object#Object() + */ + /** @label wf */ + public WfVertexDef() + { + mErrors = new Vector(0, 1); + setIsLayoutable(true); + } + + public abstract WfVertex instantiate() throws ObjectNotFoundException, InvalidDataException; + + public void configureInstance(WfVertex newVertex) { + KeyValuePair[] k = getProperties().getKeyValuePairs(); + for (KeyValuePair element : k) + newVertex.getProperties().put(element.getKey(), element.getValue()); + newVertex.setID(getID()); + if (getIsLayoutable()) { + newVertex.setInEdgeIds(getInEdgeIds()); + newVertex.setOutEdgeIds(getOutEdgeIds()); + newVertex.setCentrePoint(getCentrePoint()); + newVertex.setOutlinePoints(getOutlinePoints()); + } + } + + /** + * Method verify. + * + * @return boolean + */ + public abstract boolean verify(); + + /** + * Method getErrors. + * + * @return String + */ + public String getErrors() + { + if (mErrors.size() == 0) + return "No error"; + else + return mErrors.elementAt(0); + } + + /** + * Method loop. + * + * @return boolean + */ + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + loop2 = ((WfVertexDef) getOutGraphables()[0]).loop(); + } + loopTested = false; + return loop2; + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/lifecycle/XOrSplitDef.java b/src/main/java/com/c2kernel/lifecycle/XOrSplitDef.java new file mode 100644 index 0000000..73c578f --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/XOrSplitDef.java @@ -0,0 +1,29 @@ + +package com.c2kernel.lifecycle; + +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.lifecycle.instance.XOrSplit; + + +/** + * @version $Revision: 1.14 $ $Date: 2005/09/29 10:18:31 $ + * @author $Author: abranson $ + */ + +public class XOrSplitDef extends AndSplitDef +{ + /** + * @see java.lang.Object#Object() + */ + public XOrSplitDef() + { + super(); + } + + @Override + public WfVertex instantiate() { + XOrSplit newSplit = new XOrSplit(); + configureInstance(newSplit); + return newSplit; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/chooser/ActivityChooser.java b/src/main/java/com/c2kernel/lifecycle/chooser/ActivityChooser.java new file mode 100644 index 0000000..d5f62a0 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/chooser/ActivityChooser.java @@ -0,0 +1,194 @@ +/* + * Created on 1 sept. 2003 + * + * To change the template for this generated file go to Window>Preferences>Java>Code Generation>Code and Comments + */ +package com.c2kernel.lifecycle.chooser; + +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.HashMap; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +/** + * @author Developpement + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public class ActivityChooser extends JFrame +{ + private LDAPFileChooser mLDAPFileChooserActivity = null; + + private JButton mButtonOK = null; + + private JButton mButtonCancel = null; + + private JPanel mJPanelVertical = null; + + private JPanel mJPanelHorizontal = null; + + private String mMessage = "Choose or modify"; + + private WorkflowDialogue mParent = null; + + private JLabel label = null; + + HashMap mhashmap = null; + + public ActivityChooser(String message, String title, Image img, WorkflowDialogue parent, HashMap hashmap) + { + super(title); + mMessage = message; + img = Resource.findImage("graph/newvertex_large.png").getImage(); + setIconImage(img); + mParent = parent; + mhashmap = hashmap; + initialize(); + } + + private JButton getJButtonOK() + { + if (mButtonOK == null) + mButtonOK = new JButton(Language.translate("OK")); + return mButtonOK; + } + + private JButton getJButtonCancel() + { + if (mButtonCancel == null) + mButtonCancel = new JButton(Language.translate("Cancel")); + return mButtonCancel; + } + + private LDAPFileChooser getLDAPFileChooserActivity() + { + if (mLDAPFileChooserActivity == null) + { + try + { + mLDAPFileChooserActivity = new LDAPFileChooser(LDAPFileChooser.ACTIVITY_CHOOSER); + mLDAPFileChooserActivity.setName("LDAPFileChooserRouting"); + mLDAPFileChooserActivity.setEditable(false); + //mLDAPFileChooserActivity.setBounds(125, 13, 400, 19); + } catch (Exception mExc) + { + Logger.error(mExc); + } + } + return mLDAPFileChooserActivity; + } + + private void initialize() + { + getJButtonOK().addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + Logger.debug(5, "mLDAPFileChooserActivity.getEntryName()" + mLDAPFileChooserActivity.getEntryName()); + setCursor(new Cursor(Cursor.WAIT_CURSOR)); + mParent.loadThisWorkflow(mLDAPFileChooserActivity.getEntryName(), mhashmap); + setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + close(); + } + }); + getJButtonCancel().addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + close(); + } + }); + //getContentPane().add(getJPanelVertical()); + Container contentPane = getContentPane(); + contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); + contentPane.add(getJPanelVertical()); + contentPane.add(getJPanelHorizontal()); + contentPane.add(Box.createGlue()); + Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((d.width - getWidth()) / 2, (d.height - getHeight()) / 2); + setResizable(true); + pack(); + setSize(new Dimension(getWidth(), getJButtonCancel().getHeight() + getLDAPFileChooserActivity().getHeight() + label.getHeight() + 100)); + setVisible(true); + setVisible(true); + } + + private void close() + { + mParent = null; + this.setEnabled(false); + this.setVisible(false); + } + + private JPanel getJPanelVertical() + { + if (mJPanelVertical == null) + { + try + { + Logger.debug(8, "Panel button"); + mJPanelVertical = new JPanel(); + mJPanelVertical.setName("JPanelV"); + mJPanelVertical.setLayout(new BoxLayout(mJPanelVertical, BoxLayout.Y_AXIS)); + label = new JLabel(mMessage); + JPanel labelP = new JPanel(); + labelP.setLayout(new BoxLayout(labelP, BoxLayout.X_AXIS)); + labelP.add(label); + labelP.add(Box.createGlue()); + mJPanelVertical.add(labelP); + mJPanelVertical.add(Box.createRigidArea(new Dimension(0, 5))); + mJPanelVertical.add(getLDAPFileChooserActivity(), getLDAPFileChooserActivity().getName()); + //mJPanelVertical.add(Box.createRigidArea(new Dimension(0, + // 10))); + mJPanelVertical.add(Box.createGlue()); + mJPanelVertical.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mJPanelVertical.setVisible(true); + } catch (java.lang.Throwable mExc) + { + //handleException(mExc); + } + } + return mJPanelVertical; + } + + private JPanel getJPanelHorizontal() + { + if (mJPanelHorizontal == null) + { + try + { + Logger.debug(8, "Panel button"); + mJPanelHorizontal = new JPanel(); + mJPanelHorizontal.setName("JPanelH"); + mJPanelHorizontal.setLayout(new BoxLayout(mJPanelHorizontal, BoxLayout.X_AXIS)); + mJPanelHorizontal.add(getJButtonOK(), getJButtonOK().getName()); + mJPanelHorizontal.add(Box.createRigidArea(new Dimension(10, 0))); + mJPanelHorizontal.add(getJButtonCancel(), getJButtonCancel().getName()); + mJPanelHorizontal.setVisible(true); + } catch (java.lang.Throwable mExc) + { + //handleException(mExc); + } + } + return mJPanelHorizontal; + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/lifecycle/chooser/LDAPEntryChooser.java b/src/main/java/com/c2kernel/lifecycle/chooser/LDAPEntryChooser.java new file mode 100644 index 0000000..d21f6d5 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/chooser/LDAPEntryChooser.java @@ -0,0 +1,70 @@ +package com.c2kernel.lifecycle.chooser; +/** + * @version $Revision: 1.2 $ $Date: 2005/12/01 14:23:15 $ + * @author $Author: abranson $ + */ + +import java.awt.Dimension; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; + +import javax.swing.JComboBox; + +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + +public class LDAPEntryChooser extends JComboBox +{ + + DomainPath mDomainPath = null; + ArrayList allItems = new ArrayList(); + + public LDAPEntryChooser(DomainPath domPath, boolean editable) + { + super(); + setEditable(editable); + mDomainPath = domPath; + initialise(); + } + + private void initialise() + { + try + { + Enumeration children = Gateway.getLDAPLookup().searchAliases(mDomainPath); + while (children.hasMoreElements()) + { + DomainPath domPath = (DomainPath)children.nextElement(); + allItems.add(domPath.getName()); + } + } + catch (Exception ex) + { + Logger.exceptionDialog(ex); + } + + Collections.sort(allItems); + addItem(""); + for (String element : allItems) { + addItem(element); + } + + } + + public void reload() + { + removeAllItems(); + initialise(); + } + + @Override + public synchronized Dimension getSize() + { + if ("1".equals(Gateway.getProperty("ResizeCombo"))) + return new Dimension(super.getSize().width<400?400:super.getSize().width,super.getSize().height); + return super.getSize(); + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/chooser/LDAPFileChooser.java b/src/main/java/com/c2kernel/lifecycle/chooser/LDAPFileChooser.java new file mode 100644 index 0000000..9843d61 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/chooser/LDAPFileChooser.java @@ -0,0 +1,121 @@ +package com.c2kernel.lifecycle.chooser; +import java.awt.Dimension; +import java.awt.event.ItemListener; +import java.util.HashMap; + +import javax.swing.BoxLayout; +import javax.swing.JPanel; + +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Logger; + +//import fr.agilium.gui.tabs.wfPropertiesViewer.JPanelTabbedProperties; +/** + * @version $Revision: 1.2 $ $Date: 2005/06/27 15:16:12 $ + * @author $Author: abranson $ + */ + +public class LDAPFileChooser extends JPanel +{ + public static String SCRIPT_CHOOSER = "Script"; + public static String SCHEMA_CHOOSER = "Schema"; + public static String ACTIVITY_CHOOSER = "Activity"; + private String chooserMode = null; + private HashMap mHashList = null; + public LDAPEntryChooser mLec; + private boolean mEditable = false; + DomainPath domainPath; + String itemQuery = null; + boolean showversion = true; + + public LDAPFileChooser(String choose) + { + super(); + chooserMode = choose; + initialise(); + } + + private void initialise() + { + if (chooserMode.equals(SCHEMA_CHOOSER)) + { + itemQuery = ClusterStorage.VIEWPOINT + "/Schema/all"; + domainPath = new DomainPath("/desc/OutcomeDesc/"); + } + else if (chooserMode.equals(SCRIPT_CHOOSER)) + { + itemQuery = ClusterStorage.VIEWPOINT + "/Script/all"; + domainPath = new DomainPath("/desc/Script/"); + } + else if (chooserMode.equals(ACTIVITY_CHOOSER)) + { + domainPath = new DomainPath("/desc/ActivityDesc/"); + showversion = false; + } + else + return; + mLec = new LDAPEntryChooser(domainPath, mEditable); + + mLec.setPreferredSize(new Dimension(220, 19)); + mLec.setMaximumSize(new Dimension(3000, 22)); + mLec.setMinimumSize(new Dimension(50, 19)); + //mLec.getRenderer().getListCellRendererComponent(); + + BoxLayout blyt = new BoxLayout(this, BoxLayout.X_AXIS); + setLayout(blyt); + add(mLec); + mLec.setVisible(true); + this.validate(); + this.setVisible(true); + + } + + public String getEntryName() + { + return (String) mLec.getSelectedItem(); + } + + public void addItemListener(ItemListener il) + { + mLec.addItemListener(il); + } + public void setSelectedItem(String name, String version) + { + Logger.debug(5,"setSelectedItem " + name + " " + version); + if (name == null||name.equals("-1")) name=""; + mLec.setSelectedItem(name); + } + + public void reload() + { + mLec.reload(); + } + + public void removeAllItems() + { + mLec.removeAllItems(); + } + + /** + * @param b + */ + public void setEditable(boolean b) + { + mEditable = b; + mLec.setEditable(b); + } + + @Override + public void updateUI() + { + if (mLec!=null) mLec.updateUI(); + super.updateUI(); + } + + @Override + public void setEnabled(boolean enabled) + { + mLec.setEnabled(enabled); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/chooser/WorkflowDialogue.java b/src/main/java/com/c2kernel/lifecycle/chooser/WorkflowDialogue.java new file mode 100644 index 0000000..2ddd489 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/chooser/WorkflowDialogue.java @@ -0,0 +1,20 @@ +/* + * Created on 2 sept. 2003 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +package com.c2kernel.lifecycle.chooser; + +import java.util.HashMap; + +/** + * @author Developpement + * + * To change the template for this generated type comment go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +public interface WorkflowDialogue +{ + public void loadThisWorkflow(String name, HashMap hashMap); +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/model/WfDefGraphPanel.java b/src/main/java/com/c2kernel/lifecycle/gui/model/WfDefGraphPanel.java new file mode 100644 index 0000000..e0f4f65 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/model/WfDefGraphPanel.java @@ -0,0 +1,59 @@ +/*Created on 21 nov. 2003 */ +package com.c2kernel.lifecycle.gui.model; + +import java.awt.Graphics2D; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.view.DirectedEdgeRenderer; +import com.c2kernel.graph.view.GraphPanel; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.NextDef; + +/** @author XSeb74*/ +public class WfDefGraphPanel extends GraphPanel +{ + public WfDefGraphPanel(DirectedEdgeRenderer d,VertexRenderer v) + { + super(d,v); + } + // Draws the highlight of the specified edge + @Override + protected void drawEdgeHighlight(Graphics2D g2d, DirectedEdge edge) + { + GraphPoint originPoint = edge.getOriginPoint(); + GraphPoint terminusPoint = edge.getTerminusPoint(); + GraphPoint midPoint = new GraphPoint(); + + if ("Straight".equals(((NextDef)edge).getProperties().get("Type")) || ((NextDef)edge).getProperties().get("Type") == null) + { + midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + } + else if (("Broken +".equals(((NextDef)edge).getProperties().get("Type")))) + { + midPoint.x = (originPoint.x + terminusPoint.x) / 2; + midPoint.y = (originPoint.y + terminusPoint.y) / 2; + } + else if (("Broken -".equals(((NextDef)edge).getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + } + else if (("Broken |".equals(((NextDef)edge).getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + } + int minX = midPoint.x - 10; + int minY = midPoint.y - 10; + int maxX = midPoint.x + 10; + int maxY = midPoint.y + 10; + g2d.drawLine(minX, minY, maxX, minY); + g2d.drawLine(maxX, minY, maxX, maxY); + g2d.drawLine(maxX, maxY, minX, maxY); + g2d.drawLine(minX, maxY, minX, minY); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/model/WfEdgeDefFactory.java b/src/main/java/com/c2kernel/lifecycle/gui/model/WfEdgeDefFactory.java new file mode 100644 index 0000000..6e6727a --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/model/WfEdgeDefFactory.java @@ -0,0 +1,30 @@ +package com.c2kernel.lifecycle.gui.model; +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.EdgeFactory; +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.lifecycle.NextDef; +import com.c2kernel.lifecycle.WfVertexDef; +public class WfEdgeDefFactory implements EdgeFactory +{ + @Override + public void create( + GraphModelManager graphModelManager, + Vertex origin, + Vertex terminus, + TypeNameAndConstructionInfo typeNameAndConstructionInfo) + { + if (validCreation(graphModelManager, origin, terminus)) + { + NextDef nextDef = new NextDef((WfVertexDef) origin, (WfVertexDef) terminus); + graphModelManager.getModel().addEdgeAndCreateId(nextDef, origin, terminus); + } + } + private static boolean validCreation(GraphModelManager graphModelManager, Vertex origin, Vertex terminus) + { + DirectedEdge[] connectingEdgesAToB = graphModelManager.getModel().getConnectingEdges(origin.getID(), terminus.getID()); + DirectedEdge[] connectingEdgesBToA = graphModelManager.getModel().getConnectingEdges(terminus.getID(), origin.getID()); + return (origin != terminus) && (connectingEdgesAToB.length == 0) && (connectingEdgesBToA.length == 0); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefFactory.java b/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefFactory.java new file mode 100644 index 0000000..132fdcf --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefFactory.java @@ -0,0 +1,97 @@ +package com.c2kernel.lifecycle.gui.model; +import java.awt.Point; +import java.io.Serializable; +import java.util.HashMap; + +import javax.swing.JOptionPane; + +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.graph.model.VertexFactory; +import com.c2kernel.lifecycle.ActivityDef; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lifecycle.chooser.ActivityChooser; +import com.c2kernel.lifecycle.chooser.WorkflowDialogue; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +public class WfVertexDefFactory implements VertexFactory, WorkflowDialogue +{ + protected CompositeActivityDef mCompositeActivityDef = null; + @Override + public void create(GraphModelManager graphModelManager, Point location, TypeNameAndConstructionInfo typeNameAndConstructionInfo) + { + String vertexTypeId = null; + if (mCompositeActivityDef != null && typeNameAndConstructionInfo.mInfo instanceof String) + { + vertexTypeId = (String) typeNameAndConstructionInfo.mInfo; + if (vertexTypeId.equals("Atomic") || vertexTypeId.equals("Composite")) + { + // ask for a name + HashMap mhm = new HashMap(); + mhm.put("P1", vertexTypeId); + mhm.put("P2", location); + //************************************************ + ActivityChooser a = + new ActivityChooser( + Language.translate("Please enter a Type for the new activityDef"), + Language.translate("New " + vertexTypeId + " Activity"), + Resource.findImage("graph/newvertex_large.png").getImage(), + this, + mhm); + a.setVisible(true); + } + else + mCompositeActivityDef.newChild("", vertexTypeId, location); + } + } + @Override + public void loadThisWorkflow(String newName, HashMap hashMap) + { + String vertexTypeId = (String) hashMap.get("P1"); + Point location = (Point) hashMap.get("P2"); + if (newName == null || newName.equals("")) + return; + Logger.debug(5, newName); + ActivityDef act = (ActivityDef) mCompositeActivityDef.search(mCompositeActivityDef.getID() + "/" + newName); + if (act != null) + { + String unicName = newName; + while (unicName == null + || unicName == "" + || mCompositeActivityDef.search(mCompositeActivityDef.getID() + "/" + unicName) != null) + unicName = + (String) JOptionPane.showInputDialog( + null, + Language.translate("Please type a Name"), + Language.translate("New " + vertexTypeId + " Activity"), + JOptionPane.QUESTION_MESSAGE, + Resource.findImage("graph/newvertex_large.png"), + null, + null); + act = (ActivityDef) mCompositeActivityDef.search(mCompositeActivityDef.getID() + "/" + newName); + mCompositeActivityDef.addExistingActivityDef(unicName, act, new GraphPoint(location.x, location.y)); + } + else + { + try + { + act = LocalObjectLoader.getActDef(newName, "last"); + } + catch (Exception ex) + { + Logger.exceptionDialog(ex); + return; + } + mCompositeActivityDef.newChild(newName, vertexTypeId, location); + } + } + @Override + public void setCreationContext(Object newContext) + { + if (newContext != null && newContext instanceof CompositeActivityDef) + mCompositeActivityDef = (CompositeActivityDef) newContext; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefOutlineCreator.java b/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefOutlineCreator.java new file mode 100644 index 0000000..63d3b2f --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/model/WfVertexDefOutlineCreator.java @@ -0,0 +1,51 @@ +package com.c2kernel.lifecycle.gui.model; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.model.VertexOutlineCreator; +import com.c2kernel.lifecycle.ActivitySlotDef; + +public class WfVertexDefOutlineCreator implements VertexOutlineCreator +{ + private final int mActivityWidth = 130; + private final int mActivityHeight = 60; + private final int mSplitJoinWidth = 60; + private final int mSplitJoinHeight = 25; + + @Override + public void setOutline(Vertex vertex) + { + GraphPoint centrePoint = vertex.getCentrePoint(); + GraphPoint[] outlinePoints = new GraphPoint[ 4 ]; + int vertexWidth = 0; + int vertexHeight = 0; + + + if ( vertex instanceof ActivitySlotDef ) + { + vertexWidth = mActivityWidth; + vertexHeight = mActivityHeight; + } + else + { + vertexWidth = mSplitJoinWidth; + vertexHeight = mSplitJoinHeight; + } + + outlinePoints[ 0 ] = new GraphPoint(); + outlinePoints[ 0 ].x = centrePoint.x - vertexWidth / 2; + outlinePoints[ 0 ].y = centrePoint.y - vertexHeight / 2; + outlinePoints[ 1 ] = new GraphPoint(); + outlinePoints[ 1 ].x = centrePoint.x + vertexWidth / 2; + outlinePoints[ 1 ].y = centrePoint.y - vertexHeight / 2; + outlinePoints[ 2 ] = new GraphPoint(); + outlinePoints[ 2 ].x = centrePoint.x + vertexWidth / 2; + outlinePoints[ 2 ].y = centrePoint.y + vertexHeight / 2; + outlinePoints[ 3 ] = new GraphPoint(); + outlinePoints[ 3 ].x = centrePoint.x - vertexWidth / 2; + outlinePoints[ 3 ].y = centrePoint.y + vertexHeight / 2; + + vertex.setOutlinePoints( outlinePoints ); + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/gui/view/ActivitySlotDefRenderer.java b/src/main/java/com/c2kernel/lifecycle/gui/view/ActivitySlotDefRenderer.java new file mode 100644 index 0000000..c4309ee --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/view/ActivitySlotDefRenderer.java @@ -0,0 +1,71 @@ +package com.c2kernel.lifecycle.gui.view; + +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Paint; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.ActivitySlotDef; +import com.c2kernel.utils.Language; + +public class ActivitySlotDefRenderer implements VertexRenderer +{ + private Paint mInactivePaint = new Color(255, 255, 255); + private Paint mErrorPaint = new Color( 255, 50, 0 ); + private Paint mCompositePaint= new Color(200, 200, 255); + private Paint mTextPaint = Color.black; + + + @Override + public void draw( Graphics2D g2d, Vertex vertex) + { + ActivitySlotDef activitySlotDef = ( ActivitySlotDef )vertex; + boolean hasError = activitySlotDef.verify(); + boolean isComposite = false; + isComposite = activitySlotDef.getIsComposite(); + GraphPoint centrePoint = activitySlotDef.getCentrePoint(); + int vertexHeight = activitySlotDef.getHeight(); + int vertexWidth = activitySlotDef.getWidth(); + + String[] linesOfText = new String[2+(hasError?0:1)]; + FontMetrics metrics = g2d.getFontMetrics(); + int lineWidth = 0; + int lineHeight = metrics.getHeight(); + int linesHeight = lineHeight * linesOfText.length; + int linesStartY = centrePoint.y - linesHeight / 2 + lineHeight * 2 / 3; + int x = 0; + int y = 0; + int i = 0; + + linesOfText[0]="("+activitySlotDef.getActivityDef()+")"; + linesOfText[1]=(String)activitySlotDef.getProperties().get("Name"); + + if (!hasError)linesOfText[2]=Language.translate(activitySlotDef.getErrors()); + + g2d.setPaint( !hasError ? mErrorPaint : isComposite ? mCompositePaint : mInactivePaint ); + g2d.fill3DRect + ( + centrePoint.x - vertexWidth / 2, + centrePoint.y - vertexHeight / 2, + vertexWidth, + vertexHeight, + true + ); + + g2d.setPaint( mTextPaint ); + + // Draw the lines of text + for ( i = 0; i < linesOfText.length; i++ ) + { + if (linesOfText[i] == null) linesOfText[i] = ""; + lineWidth = metrics.stringWidth( linesOfText[ i ] ); + x = centrePoint.x - lineWidth / 2; + y = linesStartY + i * lineHeight; + g2d.drawString( linesOfText[ i ], x, y ); + } + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/gui/view/CompActDefOutcomeHandler.java b/src/main/java/com/c2kernel/lifecycle/gui/view/CompActDefOutcomeHandler.java new file mode 100644 index 0000000..4c69f15 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/view/CompActDefOutcomeHandler.java @@ -0,0 +1,233 @@ +package com.c2kernel.lifecycle.gui.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; + +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.JSplitPane; + +import com.c2kernel.graph.layout.DefaultGraphLayoutGenerator; +import com.c2kernel.graph.view.EditorPanel; +import com.c2kernel.graph.view.VertexPropertyPanel; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException; +import com.c2kernel.gui.tabs.outcome.InvalidSchemaException; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lifecycle.gui.model.WfDefGraphPanel; +import com.c2kernel.lifecycle.gui.model.WfEdgeDefFactory; +import com.c2kernel.lifecycle.gui.model.WfVertexDefFactory; +import com.c2kernel.lifecycle.gui.model.WfVertexDefOutlineCreator; +import com.c2kernel.lifecycle.instance.gui.view.FindActDefPanel; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +/************************************************************************** + * + * $Revision: 1.14 $ + * $Date: 2005/09/07 13:46:31 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class CompActDefOutcomeHandler + extends JPanel + implements OutcomeHandler { + + protected JButton mLoadButton = new JButton(Resource.findImage("graph/load.png")); + protected JButton mLayoutButton = new JButton(Resource.findImage("graph/autolayout.png")); + protected JButton[] mOtherToolBarButtons = { mLayoutButton, mLoadButton }; + + protected CompositeActivityDef mCompActDef = null; + protected WfEdgeDefFactory mWfEdgeDefFactory = new WfEdgeDefFactory(); + protected WfVertexDefFactory mWfVertexDefFactory = new WfVertexDefFactory(); + + protected EditorPanel mEditorPanel; + protected VertexPropertyPanel mPropertyPanel; + protected JSplitPane mSplitPane; + boolean unsaved; + + public CompActDefOutcomeHandler() { + super(); + mPropertyPanel = loadPropertyPanel(); + mPropertyPanel.createLayout(new FindActDefPanel()); + mEditorPanel = + new EditorPanel( + mWfEdgeDefFactory, + mWfVertexDefFactory, + new WfVertexDefOutlineCreator(), + true, + mOtherToolBarButtons, + new WfDefGraphPanel(new WfDirectedEdgeDefRenderer(), + new WfVertexDefRenderer())); + } + + protected void createLayout() + { + mLoadButton.setToolTipText("Load from local disc"); + mLayoutButton.setToolTipText("Auto-Layout"); + + // Add the editor pane + GridBagLayout gridbag = new GridBagLayout(); + setLayout(gridbag); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.BOTH; + c.weighty = 2.0; + c.weightx = 2.0; + mSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mEditorPanel, mPropertyPanel); + mSplitPane.setDividerSize(5); + gridbag.setConstraints(mSplitPane, c); + add(mSplitPane); + } + + protected void createListeners() + { + mLoadButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + File selectedFile = null; + + int returnValue = MainFrame.xmlChooser.showOpenDialog(null); + + switch (returnValue) + { + case JFileChooser.APPROVE_OPTION : + selectedFile = MainFrame.xmlChooser.getSelectedFile(); + try { + String newWf = FileStringUtility.file2String(selectedFile); + setOutcome(newWf); + setUpGraphEditor(); + } catch (Exception e) { + Logger.exceptionDialog(e); + } + case JFileChooser.CANCEL_OPTION : + case JFileChooser.ERROR_OPTION : + + default : + } + } + }); + + mLayoutButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ae) { + DefaultGraphLayoutGenerator.layoutGraph(mEditorPanel.mGraphModelManager.getModel()); + } + }); + } + + public void setUpGraphEditor() { + mEditorPanel.mGraphModelManager.setModel(mCompActDef.getChildrenGraphModel()); + // Give the editor panel the edge and vertex types + mEditorPanel.updateVertexTypes(mCompActDef.getVertexTypeNameAndConstructionInfo()); + mEditorPanel.updateEdgeTypes(mCompActDef.getEdgeTypeNameAndConstructionInfo()); + mEditorPanel.enterSelectMode(); + mWfVertexDefFactory.setCreationContext(mCompActDef); + } + + /** + * + */ + @Override + public void setOutcome(String outcome) throws InvalidOutcomeException { + try { + CompositeActivityDef newAct = (CompositeActivityDef)CastorXMLUtility.unmarshall(outcome); + if (mCompActDef != null) + newAct.setName(mCompActDef.getName()); + mCompActDef = newAct; + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidOutcomeException(ex.getMessage()); + } + } + /** + * + */ + @Override + public void setDescription(String description) + throws InvalidSchemaException { + // ignore - always the same + } + /** + * + */ + @Override + public void setReadOnly(boolean readOnly) { + mLayoutButton.setEnabled(!readOnly); + mLoadButton.setEnabled(!readOnly); + mEditorPanel.setEditable(!readOnly); + mPropertyPanel.setEditable(!readOnly); + } + /** + * + */ + @Override + public JPanel getPanel() throws OutcomeNotInitialisedException { + return this; + } + /** + * + */ + @Override + public String getOutcome() throws OutcomeException { + try { + return CastorXMLUtility.marshall(mCompActDef); + } catch (Exception ex) { + throw new OutcomeException(ex.getMessage()); + } + } + /** + * + */ + @Override + public void run() { + Thread.currentThread().setName("Composite Act Def Viewer"); + createLayout(); + createListeners(); + mPropertyPanel.setGraphModelManager(mEditorPanel.mGraphModelManager); + setUpGraphEditor(); + } + + public VertexPropertyPanel loadPropertyPanel() + { + String wfPanelClass = Gateway.getProperty("WfPropertyPanel"); + if (wfPanelClass != null) { + try { + Class panelClass = Class.forName(wfPanelClass); + return (VertexPropertyPanel)panelClass.newInstance(); + } catch (Exception ex) { + Logger.error("Could not load wf props panel:"+wfPanelClass); + Logger.error(ex); + } + } + return new VertexPropertyPanel(); + } + + @Override + public boolean isUnsaved() { + return unsaved; + } + + @Override + public void saved() { + unsaved = false; + } + + @Override + public void export(File targetFile) throws Exception { + ElemActDefOutcomeHandler.exportAct(targetFile.getParentFile(), mCompActDef); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/view/ElemActDefOutcomeHandler.java b/src/main/java/com/c2kernel/lifecycle/gui/view/ElemActDefOutcomeHandler.java new file mode 100644 index 0000000..c37e5a7 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/view/ElemActDefOutcomeHandler.java @@ -0,0 +1,161 @@ +package com.c2kernel.lifecycle.gui.view; + +import java.io.File; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.graph.view.VertexPropertyPanel; +import com.c2kernel.gui.tabs.outcome.InvalidOutcomeException; +import com.c2kernel.gui.tabs.outcome.InvalidSchemaException; +import com.c2kernel.gui.tabs.outcome.OutcomeException; +import com.c2kernel.gui.tabs.outcome.OutcomeHandler; +import com.c2kernel.gui.tabs.outcome.OutcomeNotInitialisedException; +import com.c2kernel.lifecycle.ActivityDef; +import com.c2kernel.lifecycle.ActivitySlotDef; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.5 $ + * $Date: 2005/10/05 07:39:37 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class ElemActDefOutcomeHandler extends VertexPropertyPanel implements OutcomeHandler { + + ActivityDef act; + boolean unsaved; + public ElemActDefOutcomeHandler() { + super(); + createLayout(null); + } + + /** + * + */ + @Override + public void setOutcome(String outcome) throws InvalidOutcomeException { + try { + act = (ActivityDef)CastorXMLUtility.unmarshall(outcome); + setVertex(act); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidOutcomeException(); + } + } + + /** + * + */ + @Override + public void setDescription(String description) + throws InvalidSchemaException { + // ignore + } + + /** + * + */ + @Override + public void setReadOnly(boolean readOnly) { + setEditable(!readOnly); + + } + + /** + * + */ + @Override + public JPanel getPanel() throws OutcomeNotInitialisedException { + return this; + } + + /** + * + */ + @Override + public String getOutcome() throws OutcomeException { + try { + return CastorXMLUtility.marshall(act); + } catch (Exception ex) { + Logger.error(ex); + throw new OutcomeException(); + } + } + + /** + * + */ + @Override + public void run() { + validate(); + } + + @Override + public boolean isUnsaved() { + return unsaved; + } + + @Override + public void saved() { + unsaved = false; + } + + @Override + public void export(File targetFile) throws Exception { + exportAct(targetFile.getParentFile(), act); + } + + public static void exportAct(File dir, ActivityDef actDef) throws Exception { + FileStringUtility.string2File(new File(dir, actDef.getActName()+".xml"), CastorXMLUtility.marshall(actDef)); + // Export associated schema + exportSchema((String)actDef.getProperties().get("SchemaType"), (String)actDef.getProperties().get("SchemaVersion"), dir); + // Export associated script + exportScript((String)actDef.getProperties().get("ScriptName"), (String)actDef.getProperties().get("ScriptVersion"), dir); + + //Export child act if composite + if (actDef instanceof CompositeActivityDef) { + CompositeActivityDef compActDef = (CompositeActivityDef)actDef; + for (int i=0; i -5 + && originPoint.x - terminusPoint.x < 5 ? originPoint.y : (originPoint.y + terminusPoint.y) / 2, + terminusPoint.x, + originPoint.x - terminusPoint.x > -5 + && originPoint.x - terminusPoint.x < 5 ? terminusPoint.y : (originPoint.y + terminusPoint.y) / 2)); + } + else if (("Broken -".equals(nextDef.getProperties().get("Type")))) + { + g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, originPoint.y); + g2d.drawLine(terminusPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y); + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + transform.translate(midPoint.x, midPoint.y); + transform + .rotate( + calcArrowAngle( + arrowOnY ? terminusPoint.x : originPoint.x, + arrowOnY ? originPoint.y : originPoint.y, + arrowOnY ? terminusPoint.x : terminusPoint.x, + arrowOnY ? terminusPoint.y : originPoint.y)); + } + else if (("Broken |".equals(nextDef.getProperties().get("Type")))) + { + g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, terminusPoint.y); + g2d.drawLine(originPoint.x, terminusPoint.y, terminusPoint.x, terminusPoint.y); + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + transform.translate(midPoint.x, midPoint.y); + transform + .rotate( + calcArrowAngle( + arrowOnY ? terminusPoint.x : originPoint.x, + arrowOnY ? originPoint.y : originPoint.y, + arrowOnY ? terminusPoint.x : terminusPoint.x, + arrowOnY ? terminusPoint.y : originPoint.y)); + } + else + { + g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y); + midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + transform.translate(midPoint.x, midPoint.y); + transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y)); + } + + arrow = mArrowTemplate.createTransformedShape(transform); + g2d.draw(arrow); + if (text != null) + g2d.drawString(text, midPoint.x + 10, midPoint.y); + } + private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY) + { + double width = terminusX - originX; + double height = terminusY - originY; + if ((width == 0) && (height > 0)) + { + return Math.PI; + } + if ((width == 0) && (height < 0)) + { + return 0; + } + if ((width > 0) && (height == 0)) + { + return Math.PI / 2.0; + } + if ((width < 0) && (height == 0)) + { + return -1.0 * Math.PI / 2.0; + } + if ((width > 0) && (height > 0)) + { + return Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width)); + } + if ((width > 0) && (height < 0)) + { + return Math.atan(Math.abs(width) / Math.abs(height)); + } + if ((width < 0) && (height < 0)) + { + return -1.0 * Math.atan(Math.abs(width) / Math.abs(height)); + } + if ((width < 0) && (height > 0)) + { + return -1.0 * (Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width))); + } + return 0.0; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/gui/view/WfVertexDefRenderer.java b/src/main/java/com/c2kernel/lifecycle/gui/view/WfVertexDefRenderer.java new file mode 100644 index 0000000..9199615 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/gui/view/WfVertexDefRenderer.java @@ -0,0 +1,30 @@ +package com.c2kernel.lifecycle.gui.view; + +import java.awt.Graphics2D; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.ActivitySlotDef; +import com.c2kernel.lifecycle.AndSplitDef; +import com.c2kernel.lifecycle.JoinDef; + +public class WfVertexDefRenderer implements VertexRenderer +{ + protected ActivitySlotDefRenderer mActivitySlotDefRenderer = new ActivitySlotDefRenderer(); + protected SplitJoinDefRenderer mSplitJoinDefRenderer = new SplitJoinDefRenderer(); + + + @Override + public void draw( Graphics2D g2d, Vertex vertex) + { + if ( vertex instanceof ActivitySlotDef ) + { + mActivitySlotDefRenderer.draw( g2d, vertex); + } + else if ( ( vertex instanceof AndSplitDef ) || ( vertex instanceof JoinDef ) ) + { + mSplitJoinDefRenderer.draw( g2d, vertex); + } + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Activity.java b/src/main/java/com/c2kernel/lifecycle/instance/Activity.java new file mode 100644 index 0000000..8a07d15 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Activity.java @@ -0,0 +1,689 @@ +package com.c2kernel.lifecycle.instance; +import java.util.ArrayList; +import java.util.Vector; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.GTimeStamp; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.events.Event; +import com.c2kernel.events.History; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.lifecycle.WfCastorHashMap; +import com.c2kernel.lifecycle.instance.stateMachine.StateMachine; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.lookup.LDAPRoleManager; +import com.c2kernel.lookup.RolePath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.TransactionManager; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.process.Gateway; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.DateUtility; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.222 $ $Date: 2005/10/05 07:39:37 $ + * @author $Author: abranson $ + */ +public class Activity extends WfVertex +{ + /** + * vector of errors (Strings) that is constructed each time verify() is launched + */ + protected Vector mErrors; + /** @associates a State machine engine */ + private StateMachine machine; + /** true is avalaibe to be executed */ + public boolean active = false; + /** used in verify() */ + private boolean loopTested; + //public Vector eventIds; + /** Storage of eventIds thrown by the Activity */ + public EventStorage eventIds; + private GTimeStamp mStartDate; + private GTimeStamp mActiveDate; + private String mType; + private EntityPath mEntityPath; + public Activity() + { + super(); + setProperties(new WfCastorHashMap()); + mErrors = new Vector(0, 1); + machine = new StateMachine(this); + eventIds = new EventStorage(); + mStartDate = new GTimeStamp(); + mActiveDate = new GTimeStamp(); + DateUtility.setToNow(mActiveDate); + DateUtility.setToNow(mStartDate); + } + /** @return the SystemKey of the item that contains the workflow */ + public EntityPath getItemEntityPath() + { + if (mEntityPath == null) + try + { + Integer i = (Integer) (getWf().getProperties().get("ItemSystemKey")); + if (i == null) + return null; // no item yet + EntityPath entityPath = new EntityPath(i.intValue()); + mEntityPath = entityPath; + } + catch (InvalidEntityPathException ex) + { + Logger.error("InvalidEntityPathException::Activity::getItemSystemKey() " + ex.toString()); + return null; + } + return mEntityPath; + } + /** @return the StateMachine */ + public StateMachine getMachine() + { + return machine; + } + /** sets the StateMachine (Only for Serialisation) */ + public void setMachine(StateMachine sm) + { + machine = sm; + } + /** add the activity which id is idNext as next of the current one */ + void addNext(String idNext) + { + new Next(this, (WfVertex) getParent().search(idNext)); + } + /** + * adds a New link between the current Activity and the WfVertex passed in param + */ + @Override + public Next addNext(WfVertex vertex) + { + return new Next(this, vertex); + } + /** return the current State of the State machine */ + public int getCurrentState() + { + return machine.getCurrentState(); + } + /** return the current State of the State machine (Used in Serialisation) */ + public int getState() + { + if (machine == null) + machine = new StateMachine(this); + return getCurrentState(); + } + /** Sets a new State in a State machine */ + public void setState(int stat) + { + if (machine == null) + machine = new StateMachine(this); + machine.state = stat; + } + /** check the abiltity of the agent passed in param to act on the activity */ + //return's the agentName + public String checkAccessRights(AgentPath agent) throws AccessRightsException + { + String agentID = getCurrentAgentName(); + boolean authorised = agentID.equals(agent.getAgentName()); + String actRole = getCurrentAgentRole(); + if (!authorised) + { + authorised = actRole == null || actRole.equals("") || actRole.equals("all"); + } + if (!authorised) + { + RolePath[] roles = agent.getRoles(); + for (int i = 0; !authorised && i < roles.length; i++) + { + if (roles[i].getName().equalsIgnoreCase("Admin")) + authorised = true; + if (roles[i].getName().equalsIgnoreCase(actRole)) + authorised = true; + if (roles[i].getName().equalsIgnoreCase("Guest")) + throw new AccessRightsException("Guest execution forbidden"); + } + } + if (!authorised) + throw new AccessRightsException("Activity::checkAccessRights() - Agent does not hold the correct role."); + return agent.getAgentName(); + } + /** cf Item request */ + public void request(AgentPath agent, int transitionID, String requestData) throws AccessRightsException, InvalidTransitionException, InvalidDataException, ObjectAlreadyExistsException + { + int state = getState(); + String agentName = checkAccessRights(agent); + if (machine.traverse(transitionID)) + { + setReservation(transitionID, agentName); + sendEventStoreOutcome(transitionID, requestData, agent); + if (transitionID == Transitions.REPEAT) + { + setActive(true); + if (getIsComposite()) + { + WfVertex v = (WfVertex) ((CompositeActivity) this).search(getPath() + "/" + ((CompositeActivity) this).getChildGraphModel().getStartVertexId()); + v.reinit(getID()); + try + { + runfirst(agent); + } + catch (ScriptingEngineException e) + { + Logger.error(e); + } + } + } + if (transitionID == Transitions.COMPLETE && state == States.RSTARTED) + setActive(false); + if (transitionID == Transitions.START) + start(); + if ((transitionID == Transitions.SKIP && getActive()) + || transitionID == Transitions.DONE + || (transitionID == Transitions.COMPLETE && state == States.STARTED) + || transitionID == Transitions.PROCEED) + try + { + runNext(agent); + } + catch (ScriptingEngineException e) + { + Logger.error(e); + } + // run post execution script now + try + { + String postSubmitScr = (String) getProperties().get("PostExecScriptName"); + String postSubmitVer = (String) getProperties().get("PostExecScriptVersion"); + if (postSubmitScr != null && (transitionID == Transitions.COMPLETE || transitionID == Transitions.DONE)) + evaluateScript(postSubmitScr, postSubmitVer); + } + catch (ScriptingEngineException ex) + { + Logger.error(ex); + } + //refresh all the job lists + pushJobsToAgents(); + } + else + throw new InvalidTransitionException("Activity is in the wrong state."); + } + public void setReservation(int transitionID, String agentName) + { + String actAgentName = (String) getProperties().get("Agent Name"); + switch (transitionID) + { + // these transition reserve the activity + case Transitions.REASSIGN : + case Transitions.RESERVE : + case Transitions.START : + actAgentName = agentName; + break; + // these clear any current reservation + case Transitions.COMPLETE : + case Transitions.DONE : + case Transitions.IGNORE : + case Transitions.SKIP : + actAgentName = ""; + // other transitions have no effect on the reservations + default : + } + getProperties().put("Agent Name", actAgentName); + } + public String getTransitions() + { + String result = ""; + int i; + for (i = 0; i < machine.possibleTransition().length; i++) + { + result += machine.possibleTransition()[i] + ","; + } + //cuts out the last comma(',') if required + if (i > 0) + { + result = result.substring(0, result.length() - 1); + } + result += ""; + return result; + } + /** launch the verification of the activity */ + @Override + public boolean verify() + { + mErrors.removeAllElements(); + int nbInEdgres = getInEdges().length; + int nbOutEdges = getOutEdges().length; + if (nbInEdgres == 0 && this.getID() != getParent().getChildrenGraphModel().getStartVertexId()) + { + mErrors.add("Unreachable"); + return false; + } + else if (nbInEdgres > 1) + { + mErrors.add("Bad nb of previous"); + return false; + } + else if (nbOutEdges > 1) + { + mErrors.add("too many next"); + return false; + } + else if (nbOutEdges == 0) + { + if (!((CompositeActivity) getParent()).hasGoodNumberOfActivity()) + { + mErrors.add("too many endpoints"); + return false; + } + } +// else +// { +// Vertex[] outV = getOutGraphables(); +// Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); +// boolean errInLoop = false; +// for (int i = 0; i < outV.length; i++) +// { +// for (int j = 0; j < anteVertices.length; j++) +// if (!loop() && outV[i].getID() == anteVertices[j].getID()) +// errInLoop = true; +// } +// if (errInLoop) +// { +// mErrors.add("Error In Loop"); +// return false; +// } +// } + return true; + } + /** Used in verify() */ + @Override + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + loop2 = ((WfVertex) getOutGraphables()[0]).loop(); + } + loopTested = false; + return loop2; + } + /** sets the next activity available if possible */ + @Override + public void runNext(AgentPath agent) throws ScriptingEngineException + { + setActive(false); + try + { + Vertex[] outVertices = getOutGraphables(); + Vertex[] outVertices2 = getOutGraphables(); + boolean hasNoNext = false; + boolean out = false; + while (!out) + if (outVertices2.length > 0) + { + if (outVertices2[0] instanceof Join) + outVertices2 = ((WfVertex) outVertices2[0]).getOutGraphables(); + else + out = true; + } + else + { + hasNoNext = true; + out = true; + } + Logger.debug(8, outVertices + " " + outVertices2); + if (!hasNoNext) + ((WfVertex) outVertices[0]).run(agent); + else + { + if (getParent() != null && getParent().getName().equals("domain")) // workflow + // finished + setActive(true); + else + { + CompositeActivity parent = (CompositeActivity) getParent(); + if (parent != null) + parent.runNext(agent); + } + } + } + catch (ScriptingEngineException s) + { + setActive(true); + throw s; + } + } + /** @return the only Next of the Activity */ + public Next getNext() + { + if (getOutEdges().length > 0) + return (Next) getOutEdges()[0]; + else + return null; + } + /** reinitialises the Activity and propagate (for Loop) */ + @Override + public void reinit(int idLoop) + { + Logger.debug(7, "reinit " + getItemEntityPath().getSysKey() + " " + getPath()); + Vertex[] outVertices = getOutGraphables(); + machine.state = States.WAITING; + if (outVertices.length > 0) + { + WfVertex nextAct = (WfVertex) outVertices[0]; + nextAct.reinit(idLoop); + } + } + /** return the String that identifies the errors found in th activity */ + @Override + public String getErrors() + { + if (mErrors.size() == 0) + return "No error"; + return mErrors.elementAt(0); + } + /** + * called by precedent Activity runNext() for setting the activity able to be executed + */ + @Override + public void run(AgentPath agent) throws ScriptingEngineException + { + Logger.debug(8, getPath() + " run " + getCurrentState()); + if (!getActive()) + setActive(true); + + if (getMachine().getCurrentState() == States.FINISHED) + { + runNext(agent); + } + else + { + DateUtility.setToNow(mActiveDate); + if (((Boolean) getProperties().get(StateMachine.AUTOSTART)).booleanValue() && machine.state == States.WAITING) + { + machine.traverse(Transitions.START); + start(); + } + pushJobsToAgents(); + } + } + /** + * sets the activity available to be executed on start of Workflow or composite activity (when it is the first one of the (sub)process + */ + @Override + public void runfirst(AgentPath agent) throws ScriptingEngineException + { + Logger.debug(8, getPath() + " runfirst"); + run(agent); + } + /** @return the current ability to be executed */ + public boolean getActive() + { + return active; + } + /** sets the ability to be executed */ + public void setActive(boolean acti) + { + active = acti; + } + /** @return the Description field of properties */ + public String getDescription() + { + if (getProperties().containsKey("Description")) + return (String) (getProperties().get("Description")); + return "No description"; + } + public String getCurrentAgentName() + { + return (String) getProperties().get("Agent Name"); + } + public String getCurrentAgentRole() + { + return (String) getProperties().get("Agent Role"); + } + /** + * @return an array of Steps that matches the querry + * @param agentID + * Agent concerned by the query + * @param agentRole + * Agent concerned by the query @int stateID state to test in the query, use -1 for all + * @param filter + * if tru will be filtered by agent, else won't + */ + public Activity[] query(AgentPath agent, int stateID, boolean filter) + { + if (getCurrentState() == stateID || stateID == -1) + { + Activity[] steps = { this }; + if (!filter) + return steps; + else + { + try + { + checkAccessRights(agent); + return steps; + } + catch (AccessRightsException e) + { + //case that agent is not allowed + Logger.msg(7, "Activity :: AccessRightsException in " + this.getItemEntityPath() + "/" + this.getPath()); + } + } + } + return new Activity[0]; + } + /** + * returns the lists of jobs for the activity and children (cf com.c2kernel.entity.Job) + */ + public ArrayList calculateJobs(AgentPath agent, boolean recurse) + { + return calculateJobsBase(agent, false); + } // + public ArrayList calculateAllJobs(AgentPath agent, boolean recurse) + { + return calculateJobsBase(agent, true); + } + private ArrayList calculateJobsBase(AgentPath agent, boolean all) + { + Logger.msg(7, "calculateJobs - " + getPath()); + int[] transitions = { + }; + ArrayList jobs = new ArrayList(); + try + { + String agentName = checkAccessRights(agent); + String currentAgentName = getCurrentAgentName(); + boolean isCurrent = currentAgentName == null || currentAgentName.equals("") || agentName.equals(currentAgentName); + if ((all || getActive()) && !getName().equals("domain")) + transitions = machine.possibleTransition(); + Logger.msg(7, "Activity.calculateJobs() - Got " + transitions.length + " transitions."); + for (int i = 0; i < transitions.length; i++) + { + Logger.msg(7, "Creating Job object for transition " + transitions[i]); + if ((isCurrent && !(transitions[i] == Transitions.REASSIGN && agentName.equals(currentAgentName))) || (transitions[i] == Transitions.REASSIGN && !agentName.equals(currentAgentName))) + jobs.add(new Job(getItemEntityPath().getSysKey(), getPath(), transitions[i], getCurrentState(), machine.simulate(transitions[i]), getName(), getProperties(), getType(), agentName)); + } + } + catch (AccessRightsException ex) + { + Logger.msg(6, "Agent "+ agent.getAgentName() +" is not allowed to interact with "+getItemEntityPath().getSysKey()+":"+getPath()); + } // empty joblist then + return jobs; + } + // + //methods written by kovax + // + /** Adds an event to the AuditTrail of the Item if any */ + private Event auditEvent(int transitionID, AgentPath agent) + { + EntityPath entityPath = getItemEntityPath(); + if (entityPath != null) + { + Event event = null; + History hist = null; + try + { + hist = (History) Gateway.getStorage().get(entityPath.getSysKey(), ClusterStorage.HISTORY, this); + event = hist.addEvent(agent.getAgentName(), getCurrentAgentRole(), transitionID, getName(), getPath(), getType(), getCurrentState()); + Logger.msg(7, "Activity::auditEvent() - Event:" + event.getName() + " was added to the AuditTrail"); + } + catch (Exception ex) + { + Logger.error("Activity::auditEvent() - Item '" + entityPath.toString() + "'!"); + Logger.error(ex); + } + return event; + } + else + return null; + } /** + * Stores the request data as an outcome of the Item It does a great deal of storing outcomes in different configuration + */ //requestdata is xmlstring + private String storeOutcome(int eventID, String requestData) + { + EntityPath entityPath = getItemEntityPath(); + if (entityPath != null) + { + String schemaType = (String) getProperties().get("SchemaType"); + if (schemaType == null || schemaType.length() == 0) // no + // outcome + // required + return null; + int schemaVersion = 0; + String versionString = (String) getProperties().get("SchemaVersion"); + try + { + schemaVersion = Integer.parseInt(versionString); + } + catch (Exception e) + { + Logger.error("Activity.storeOutcome() - invalid schemaVersion " + versionString); + } + Logger.msg(5, "Activity::storeOutcome() - type:" + schemaType + " version:" + schemaVersion); + try + { + Outcome newOutcome = new Outcome(eventID, requestData, schemaType, schemaVersion); + Gateway.getStorage().put(entityPath.getSysKey(), newOutcome, this); + // update specific view if defined + String specificView = (String) getProperties().get("Viewpoint"); + if (specificView != null && !specificView.equals("")) + { + Viewpoint currentView = new Viewpoint(entityPath.getSysKey(), schemaType, specificView, schemaVersion, eventID); + Gateway.getStorage().put(entityPath.getSysKey(), currentView, this); + } // update last view + Viewpoint currentView = new Viewpoint(entityPath.getSysKey(), schemaType, "last", schemaVersion, eventID); + Gateway.getStorage().put(entityPath.getSysKey(), currentView, this); + return schemaType + "/" + schemaVersion + "/" + eventID; + } + catch (Exception ex) + { + Logger.error("ActivityBase::storeOutcome() - Item '" + entityPath.toString() + "'!"); + Logger.error(ex); + } + return null; + } + else + return null; + } /** the method to be called by the requestAction() method */ + public void sendEventStoreOutcome(int transitionID, String requestData, AgentPath agent) + { + int eventID = -1; + Event event = null; + event = auditEvent(transitionID, agent); + if (event != null) + eventID = event.getID(); + if (transitionID == Transitions.DONE || transitionID == Transitions.COMPLETE) + storeOutcome(eventID, requestData); + EntityPath entityPath = getItemEntityPath(); + TransactionManager storage = Gateway.getStorage(); + if (entityPath != null) + { + storage.commit(this); + } + } + public void pushJobsToAgents() + { + String agentRole = getCurrentAgentRole(); + if (agentRole == null || agentRole.length()==0) return; + + LDAPRoleManager roleMan = Gateway.getLDAPLookup().getRoleManager(); + RolePath myRole; + try { + myRole = roleMan.getRolePath(agentRole); + } catch (ObjectNotFoundException ex) { // non-existent role + Logger.msg(7, "Activity.pushJobsToAgents() - Activity role '"+agentRole+" not found."); + return; + } + + if (myRole.hasJobList()) + new JobPusher(this, myRole).start(); + } + + + /** + * Returns the activeDate. + * + * @return GTimeStamp + */ + public GTimeStamp getActiveDate() + { + return mActiveDate; + } /** + * Returns the startDate. + * + * @return GTimeStamp + */ + public GTimeStamp getStartDate() + { + return mStartDate; + } /** + * Sets the activeDate. + * + * @param activeDate + * The activeDate to set + */ + public void setActiveDate(GTimeStamp activeDate) + { + mActiveDate = activeDate; + } /** + * Sets the startDate. + * + * @param startDate + * The startDate to set + */ + public void setStartDate(GTimeStamp startDate) + { + mStartDate = startDate; + } /** + * Returns the type. + * + * @return String + */ + public String getType() + { + return mType; + } /** + * Sets the type. + * + * @param type + * The type to set + */ + public void setType(String type) + { + mType = type; + } + private void start() + { + Logger.debug(8, getPath() + " start"); + DateUtility.setToNow(mStartDate); + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/AdvancementCalculator.java b/src/main/java/com/c2kernel/lifecycle/instance/AdvancementCalculator.java new file mode 100644 index 0000000..6a3abe7 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/AdvancementCalculator.java @@ -0,0 +1,225 @@ +/* Created on 11 mars 2004 */ +package com.c2kernel.lifecycle.instance; +import java.io.Serializable; +import java.util.Hashtable; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.lifecycle.instance.stateMachine.States; +//import com.c2kernel.utils.Logger; +/** @author XSeb74 */ +public class AdvancementCalculator implements Serializable +{ + private CompositeActivity activity; + private Hashtable isMarked; + private Hashtable HasNextMarked; + public Hashtable hasprevActive; + private long mCurrentNbActExp = 0; + private long mMaximuNbActexp = 0; + private long mNbActpassed = 0; + private long mNbActpassedWithCurrent = 0; + private long mNbActLeftWithCurrent = 0; + private long mNbActLeftWithoutCurrent = 0; + private boolean mIsbranchActive = false; + private boolean mIsbranchFinished = true; + private boolean mHasPrevActive = false; + public AdvancementCalculator() + { + isMarked = new Hashtable(); + HasNextMarked = new Hashtable(); + hasprevActive = new Hashtable(); + } + public void calculate(CompositeActivity act) + { +// Logger.debug(0, act.getName()+" >>>>>>>>>"); + if (act instanceof Workflow) + { + calculate((CompositeActivity) act.search("workflow/domain")); + return; + } + activity = act; + Vertex v = activity.getChildGraphModel().getStartVertex(); + check(v, this); + isMarked = new Hashtable(); + calc(v, this); +// Logger.debug(0, act.getName()+" <<<<<<<<<"); + } + private void check(Vertex v, AdvancementCalculator current) + { + current.isMarked.put(v, ""); + Vertex[] nexts = current.activity.getChildGraphModel().getOutVertices(v); + for (Vertex next : nexts) + if (current.isMarked.get(next) != null) + current.HasNextMarked.put(v, next); + else + check(next, current); + int j=0; + for (Vertex next : nexts) + if (current.HasNextMarked.get(next) != null) + j++; + if (j != 0 && j==nexts.length) current.HasNextMarked.put(v, nexts[0]); + } + private void calc(Vertex v, AdvancementCalculator current) + { + if (current.isMarked.get(v) != null && !(v instanceof Join)) + return; + if (v instanceof Activity) + { + current.isMarked.put(v, current); + Activity act = (Activity) v; + if (v instanceof CompositeActivity) + { + CompositeActivity cact = (CompositeActivity) v; + AdvancementCalculator adv = new AdvancementCalculator(); + adv.isMarked = current.isMarked; + adv.HasNextMarked = current.HasNextMarked; + adv.calculate(cact); + current.mCurrentNbActExp += adv.mCurrentNbActExp; + current.mMaximuNbActexp += adv.mMaximuNbActexp; + current.mNbActpassed += adv.mNbActpassed; + current.mNbActpassedWithCurrent += adv.mNbActpassedWithCurrent; + current.mIsbranchActive = current.mIsbranchActive || adv.mIsbranchActive||act.getActive(); + current.mNbActLeftWithCurrent += adv.mNbActLeftWithCurrent; + current.mNbActLeftWithoutCurrent += adv.mNbActLeftWithoutCurrent; + current.mHasPrevActive = adv.mHasPrevActive||act.getActive(); + if (adv.hasprevActive.size()!=0) current.mHasPrevActive=true; + } + else + { + current.mCurrentNbActExp += 1; + current.mMaximuNbActexp += 1; + if (act.getCurrentState() == States.FINISHED) + { + current.mNbActpassed += 1; + current.mNbActpassedWithCurrent += 1; + } + else if (act.getActive()&&act.getState() steps = new Vector(); + Activity[] returnArray = null; + for (int i = 0; i < getChildren().length; i++) + { + if (getChildren()[i] instanceof Activity) + steps.addElement(((Activity) getChildren()[i]).query(agent, stateID, filter)); + } + int j = 0; + for (int i = 0; i < steps.size(); i++) + j += steps.elementAt(i).length; + Activity[] tmp = super.query(agent, stateID, filter); + if (tmp.length == 1) + { + returnArray = new Activity[j + 1]; + returnArray[j] = tmp[0]; + } else + returnArray = new Activity[j]; + j = 0; + for (int i = 0; i < steps.size(); i++) + { + Activity[] stepArray = steps.elementAt(i); + for (Activity element : stepArray) + returnArray[j++] = element; + } + return returnArray; + } + + /** + * @see com.c2kernel.lifecycle.instance.Activity#calculateJobs() + */ + @Override + public ArrayList calculateJobs(AgentPath agent, boolean recurse) + { + ArrayList jobs = new ArrayList(); + boolean childActive = false; + if (recurse) + for (int i = 0; i < getChildren().length; i++) + if (getChildren()[i] instanceof Activity) + { + Activity child = (Activity) getChildren()[i]; + jobs.addAll(child.calculateJobs(agent, recurse)); + childActive |= child.active; + } + if (!childActive) + jobs.addAll(super.calculateJobs(agent, recurse)); + return jobs; + } + + @Override + public ArrayList calculateAllJobs(AgentPath agent, boolean recurse) + { + ArrayList jobs = new ArrayList(); + if (recurse) + for (int i = 0; i < getChildren().length; i++) + if (getChildren()[i] instanceof Activity) + { + Activity child = (Activity) getChildren()[i]; + jobs.addAll(child.calculateAllJobs(agent, recurse)); + } + jobs.addAll(super.calculateAllJobs(agent, recurse)); + return jobs; + } + + /** + * Method addNext. + * + * @param origin + * @param terminus + * @return Next + */ + public Next addNext(WfVertex origin, WfVertex terminus) + { + return new Next(origin, terminus); + } + + /** + * Method addNext. + * + * @param originID + * @param terminusID + * @return Next + */ + public Next addNext(int originID, int terminusID) + { + Next n = new Next(); + n.setParent(this); + getChildrenGraphModel().addEdgeAndCreateId(n, originID, terminusID); + return n; + } + + /** + * Method hasGoodNumberOfActivity. + * + * @return boolean + */ + public boolean hasGoodNumberOfActivity() + { + int endingAct = 0; + for (int i = 0; i < getChildren().length; i++) + { + WfVertex vertex = (WfVertex) getChildren()[i]; + if (getChildrenGraphModel().getOutEdges(vertex).length == 0) + endingAct++; + } + if (endingAct > 1) + return false; + return true; + } + + /** + * @see com.c2kernel.lifecycle.instance.Activity#getType() + */ + @Override + public String getType() + { + if (getName().equals("domain")) + return "domain"; + return super.getType(); + } + + /** + * + */ + @Override + public void reinit(int idLoop) + { + super.reinit(idLoop); + if (getChildrenGraphModel().getStartVertex() != null && getMachine().getCurrentState() != States.FINISHED) + ((WfVertex) getChildrenGraphModel().getStartVertex()).reinit(idLoop); + } + + @Override + public void request(AgentPath agent, int transitionID, String requestData) throws AccessRightsException, InvalidTransitionException, InvalidDataException, ObjectAlreadyExistsException + { + if (getChildrenGraphModel().getStartVertex() != null && getMachine().getCurrentState() != States.FINISHED && transitionID == Transitions.START) + try + { + ((WfVertex) getChildrenGraphModel().getStartVertex()).run(agent); + } catch (ScriptingEngineException e) + { + Logger.error(e); + } + super.request(agent, transitionID, requestData); + } + public void refreshJobs() + { + GraphableVertex[] children = getChildren(); + for (GraphableVertex element : children) + if (element instanceof CompositeActivity) + ((CompositeActivity) element).refreshJobs(); + else if (element instanceof Activity) + ((Activity) element).pushJobsToAgents(); + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/lifecycle/instance/EventList.java b/src/main/java/com/c2kernel/lifecycle/instance/EventList.java new file mode 100644 index 0000000..be255fb --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/EventList.java @@ -0,0 +1,19 @@ +package com.c2kernel.lifecycle.instance; + +import java.io.Serializable; + +/** + * @version $Revision: 1.9 $ $Date: 2005/06/08 19:47:59 $ + * @author $Author: abranson $ + */ +public class EventList implements Serializable { + private int[] dummy = new int[0]; + public int transition=-1; + + public int[] getNums() { + return dummy; + } + + public void setNums(int[] nums) { + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/EventStorage.java b/src/main/java/com/c2kernel/lifecycle/instance/EventStorage.java new file mode 100644 index 0000000..40cffaf --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/EventStorage.java @@ -0,0 +1,24 @@ +package com.c2kernel.lifecycle.instance; +import java.io.Serializable; +import java.util.Hashtable; + +/** + * @version $Revision: 1.15 $ $Date: 2005/06/08 19:48:00 $ + * @author $Author: abranson $ + */ +public class EventStorage implements Serializable +{ + private Hashtable mLists; + private EventList[] dummy = new EventList[0]; + public Integer lastTransitionStored; + + public EventList[] getLists() + { + return dummy; + } + + public void setLists(EventList[] lists) + { + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/JobPusher.java b/src/main/java/com/c2kernel/lifecycle/instance/JobPusher.java new file mode 100644 index 0000000..5b8be63 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/JobPusher.java @@ -0,0 +1,70 @@ +package com.c2kernel.lifecycle.instance; + +import java.util.Enumeration; +import java.util.Iterator; + +import com.c2kernel.entity.Agent; +import com.c2kernel.entity.AgentHelper; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.agent.JobArrayList; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.RolePath; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +final class JobPusher extends Thread { + private final Activity activity; + private final RolePath myRole; + + JobPusher(Activity activity, RolePath role) { + this.activity = activity; + this.myRole = role; + } + + @Override + public void run() + { + Thread.currentThread().setName("Agent job pusher for "+activity.getName()+" to role "+myRole); + for (Enumeration e = myRole.getChildren(); e.hasMoreElements();) + { + AgentPath nextAgent = e.nextElement(); + Logger.msg(7, "Activity.pushJobsToAgents() - Calculating jobs for " + nextAgent.getAgentName()); + try + { + // get joblist for user + JobArrayList jobList = new JobArrayList(this.activity.calculateJobs(nextAgent, false)); + // only transmit start, complete and resume jobs + for (Iterator element = jobList.list.iterator(); element.hasNext();) + { + Job thisJob = element.next(); + if (thisJob.getPossibleTransition() != Transitions.START + && thisJob.getPossibleTransition() != Transitions.COMPLETE + && thisJob.getPossibleTransition() != Transitions.RESUME + && thisJob.getPossibleTransition() != Transitions.SUSPEND + && thisJob.getPossibleTransition() != Transitions.REASSIGN) + element.remove(); + } + Logger.msg(7, "Activity.pushJobsToAgents() - User will receive " + jobList.list.size() + " jobs"); + String stringJobs = CastorXMLUtility.marshall(jobList); + // push it to the agent + org.omg.CORBA.Object agentIOR = nextAgent.getIOR(); + Agent thisAgent = AgentHelper.narrow(agentIOR); + Logger.debug("Calling agent "+thisAgent.getSystemKey()+" from "+activity.getPath()); + thisAgent.refreshJobList(this.activity.getItemEntityPath().getSysKey(), activity.getPath(), stringJobs); + } + catch (Exception ex) + { + Logger.error( + "Agent " + + nextAgent.getAgentName() + + " of role " + + myRole + + " could not be found to be informed of a change in " + + this.activity.getItemEntityPath().getSysKey()); + Logger.error(ex); + } + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Join.java b/src/main/java/com/c2kernel/lifecycle/instance/Join.java new file mode 100644 index 0000000..3a4fd7d --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Join.java @@ -0,0 +1,216 @@ +package com.c2kernel.lifecycle.instance; +import java.util.Vector; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.scripting.ScriptingEngineException; +/** + * @version $Revision: 1.52 $ $Date: 2005/05/10 15:14:54 $ + * @author $Author: abranson $ + */ +public class Join extends WfVertex +{ + public Vector mErrors; + /** + * @see java.lang.Object#Object() + */ + public Join() + { + super(); + mErrors = new Vector(0, 1); + } + private boolean loopTested; + public int counter = 0; + private String mItemSystemKey = ""; + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#runNext() + */ + @Override + public void runNext(AgentPath agent) throws ScriptingEngineException + { + AdvancementCalculator adv = new AdvancementCalculator(); + adv.calculate((CompositeActivity) getParent()); + if (adv.hasprevActive.get(String.valueOf(getID())) == null) + { + Vertex[] outVertices = getOutGraphables(); + if (outVertices.length > 0) + { + WfVertex nextAct = (WfVertex) outVertices[0]; + nextAct.run(agent); + } + else + super.runNext(agent); + } + } + /** + * Method addNext. + * + * @param idNext + */ + public void addNext(String idNext) + { + new Next(this, (WfVertex) getParent().search(idNext)); + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#reinit(int) + */ + @Override + public void reinit(int idLoop) + { + Vertex[] outVertices = getOutGraphables(); + if (outVertices.length == 1) + { + WfVertex nextAct = (WfVertex) outVertices[0]; + nextAct.reinit(idLoop); + } + } + /** + * Method getItemSystemKey. + * + * @return String + */ + /* + * public CompositeActivity process() { return parent.process(); } + */ + public String getItemSystemKey() + { + return mItemSystemKey; + } + /** + * Method setItemSystemKey. + * + * @param itemSystemKey + */ + public void setItemSystemKey(String itemSystemKey) + { + mItemSystemKey = itemSystemKey; + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#verify() + */ + // public void initItemSystemKey(String systemKey) { + // this.setItemSystemKey(systemKey); + // } + @Override + public boolean verify() + { + mErrors.removeAllElements(); + int nbOutEdges = getOutEdges().length; + int nbInEdges = getInEdges().length; + String type = (String) getProperties().get("Type"); + if (nbInEdges < 1) + { + mErrors.add("not enough previous"); + return false; + } + if (type != null && type.equals("Route")) + { + if (nbInEdges > 1) + { + mErrors.add("Bad nb of previous"); + return false; + } + } + if (nbOutEdges > 1) + { + mErrors.add("too many next"); + return false; + } + if (nbOutEdges == 0) + { + if (!((CompositeActivity) getParent()).hasGoodNumberOfActivity()) + { + mErrors.add("too many endpoints"); + return false; + } + } + Vertex[] outV = getOutGraphables(); + Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + boolean loop = false; + boolean errInLoop = false; + for (int i = 0; i < outV.length; i++) + { + for (int j = 0; j < anteVertices.length; j++) + if (!loop && outV[i].getID() == anteVertices[j].getID()) + { + if (outV[i] instanceof Loop) + { + loop = true; + j = anteVertices.length; + i = outV.length; + } + else + { + errInLoop = true; + } + } + } + if (errInLoop && loop) + { + mErrors.add("Problem in Loop"); + return false; + } + return true; + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#getErrors() + */ + @Override + public String getErrors() + { + if (mErrors.size() == 0) + return "No error"; + else + return mErrors.elementAt(0); + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#run() + */ + @Override + public void run(AgentPath agent) throws ScriptingEngineException + { + runNext(agent); + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#addNext(com.c2kernel.lifecycle.instance.WfVertex) + */ + @Override + public Next addNext(WfVertex vertex) + { + return new Next(this, vertex); + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#loop() + */ + @Override + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + loop2 = ((WfVertex) getOutGraphables()[0]).loop(); + } + else + loop2 = true; + loopTested = false; + return loop2; + } + @Override + public void runfirst(AgentPath agent) throws ScriptingEngineException + { + runNext(agent); + } + /* + * (non-Javadoc) + * + * @see com.c2kernel.graph.model.Vertex#isJoin() + */ + @Override + public boolean isJoin() + { + return true; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Loop.java b/src/main/java/com/c2kernel/lifecycle/instance/Loop.java new file mode 100644 index 0000000..8228ba9 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Loop.java @@ -0,0 +1,107 @@ +package com.c2kernel.lifecycle.instance; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.35 $ $Date: 2005/05/10 15:14:54 $ + * @author $Author: abranson $ + */ +public class Loop extends XOrSplit +{ + /** + * @see java.lang.Object#Object() + */ + public Loop() + { + super(); + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#loop() + */ + @Override + public boolean loop() + { + return true; + } + @Override + public void followNext(Next activeNext, AgentPath agent) throws ScriptingEngineException + { + WfVertex v = activeNext.getTerminusVertex(); + if (!isInPrev(v)) + v.run(agent); + else + { + v.reinit(getID()); + v.run(agent); + } + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#reinit(int) + */ + @Override + public void reinit(int idLoop) + { + Logger.msg(8, "Loop.reinit"); + if (idLoop == getID()) + return; + else + { + Vertex[] outVertices = getOutGraphables(); + for (int j = 0; j < outVertices.length; j++) + { + if (!isInPrev(outVertices[j])) + ((WfVertex) outVertices[j]).reinit(idLoop); + } + } + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#verify() + */ + @Override + public boolean verify() + { + boolean err = super.verify(); + Vertex[] nexts = getOutGraphables(); + Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + int k = 0; + int l = 0; + Vertex[] brothers = getParent().getChildren(); + for (Vertex brother : brothers) + if (brother instanceof Loop) + l++; + for (Vertex next : nexts) { + for (Vertex anteVertice : anteVertices) + if (next.getID() == anteVertice.getID()) + k++; + } + if (k != 1 && !(l > 1)) + { + mErrors.add("bad number of pointing back nexts"); + return false; + } + // if (nexts.length>2) { + // mErrors.add("you must only have 2 nexts"); + // return false; + // } + return err; + } + private boolean isInPrev(Vertex vertex) + { + int id = vertex.getID(); + Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + for (Vertex anteVertice : anteVertices) { + if (anteVertice.getID() == id) + { + return true; + } + } + return false; + } + @Override + public boolean isLoop() + { + return true; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Next.java b/src/main/java/com/c2kernel/lifecycle/instance/Next.java new file mode 100644 index 0000000..4df775c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Next.java @@ -0,0 +1,83 @@ +package com.c2kernel.lifecycle.instance; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.GraphableEdge; + +/** + * @version $Revision: 1.58 $ $Date: 2005/05/10 15:14:54 $ + * @author $Author: abranson $ + */ +/** this class represents the link between 2 successive activities */ +public class Next extends GraphableEdge +{ + /** + * @see java.lang.Object#Object() + */ + public Next() + { + super(); + } + + /** + * Method Next. + * @param pre + * @param nex + */ + /** create and initialize a link between an Activities */ + public Next(WfVertex pre, WfVertex nex) + { + super(pre, nex); + getProperties().put("Alias",""); + getProperties().put("Type","Straight"); + } + + /** + * Method verify. + * @return boolean + */ + public boolean verify() + { + return true; + } + public WfVertex getTerminusVertex() + { + return (WfVertex)((CompositeActivity)getParent()).getWf().search(getParent().getPath()+"/"+this.getTerminusVertexId()); + } + @Override + public boolean containsPoint(GraphPoint p) + { + GraphPoint originPoint = getOriginPoint(); + GraphPoint terminusPoint = getTerminusPoint(); + GraphPoint midPoint = new GraphPoint(); + + if (("Broken +".equals(getProperties().get("Type")))) + { + midPoint.x = (originPoint.x + terminusPoint.x) / 2; + midPoint.y = (originPoint.y + terminusPoint.y) / 2; + } + else if (("Broken -".equals(getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + } + else if (("Broken |".equals(getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + } + else + { + midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + } + + int minX = midPoint.x - 10; + int minY = midPoint.y - 10; + int maxX = midPoint.x + 10; + int maxY = midPoint.y + 10; + + return (p.x >= minX) && (p.x <= maxX) && (p.y >= minY) && (p.y <= maxY); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/OrSplit.java b/src/main/java/com/c2kernel/lifecycle/instance/OrSplit.java new file mode 100644 index 0000000..aea34b2 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/OrSplit.java @@ -0,0 +1,62 @@ +package com.c2kernel.lifecycle.instance; +import java.util.StringTokenizer; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.22 $ $Date: 2005/05/10 15:14:54 $ + * @author $Author: abranson $ + */ +public class OrSplit extends Split +{ + /** + * @see java.lang.Object#Object() + */ + public OrSplit() + { + super(); + } + @Override + public void runNext(AgentPath agent) throws ScriptingEngineException + { + String nexts = + this + .evaluateScript((String) getProperties().get("RoutingScriptName"), (String) getProperties().get("RoutingScriptVersion")) + .toString(); + StringTokenizer tok = new StringTokenizer(nexts, ","); + Logger.msg(7, tok.countTokens() + " nexts to activate:" + nexts); + int active = 0; + try + { + DirectedEdge[] outEdges = getOutEdges(); + AdvancementCalculator adv = new AdvancementCalculator(); + adv.calculate((CompositeActivity)getParent()); + while (tok.hasMoreTokens()) + { + String thisNext = tok.nextToken(); + Logger.msg(7, "Finding next " + thisNext); + for (DirectedEdge outEdge : outEdges) { + Next nextEdge = (Next) outEdge; + if (thisNext != null && thisNext.equals(nextEdge.getProperties().get("Alias"))) + { + WfVertex term = nextEdge.getTerminusVertex(); + term.run(agent); + Logger.msg(7, "Running " + nextEdge.getProperties().get("Alias")); + active++; + } + } + } + // if no active nexts throw exception + } + catch (Exception e) + { + Logger.error(e); + } + if (active == 0) + throw new ScriptingEngineException("No nexts were activated!"); + } + + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/ParserWF.java b/src/main/java/com/c2kernel/lifecycle/instance/ParserWF.java new file mode 100644 index 0000000..02a0c6d --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/ParserWF.java @@ -0,0 +1,356 @@ +package com.c2kernel.lifecycle.instance; + +import java.awt.Point; +import java.io.IOException; +import java.util.Vector; + +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.Logger; + +/** + * @version $Revision: 1.26 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ +public class ParserWF +{ + static Vector nexts; + static String file = ""; + static int i; + static CastorHashMap mInfo = new CastorHashMap(); + + /** + * Method addStep. + * @param act + * @param xmlfile + * @return CompositeActivity + * @throws IOException + */ + /** + * @associates <{com.c2kernel.lifecycle.instance.Workflow}> + * @label creates + */ + public static CompositeActivity addStep(CompositeActivity act, String xmlfile, AgentPath agent) throws IOException + { + nexts = new Vector(1, 1); + i = 0; + file = xmlfile; + while (i < file.length() - 5) + { + if (file.substring(i, i + 5).equals("")) + { + if (file.substring(i, i + 5).equals("")) + { + Logger.msg(7, ""); + i += 13; + int j = 0; + ; + while (file.charAt(i + j) != '<') + { + j++; + } + step[9] = file.substring(i, i + j); + i += (j + 14); + } + else if (file.substring(i, i + 6).equals("")) + { + Logger.msg(7, ""); + i += 6; + int j = 0; + ; + String[] tmp = new String[2]; + while (file.charAt(i + j) != '<') + { + j++; + } + tmp[0] = step[0]; + tmp[0] = parent.getPath() + "/" + tmp[0]; + tmp[1] = file.substring(i, i + j); + tmp[1] = parent.getPath() + "/" + tmp[1]; + nexts.addElement(tmp); + i += (j + 8); + Logger.msg(7, ""); + } + else if (file.substring(i, i + 5).equals("Path=")) + { + Logger.msg(7, "Path="); + i += 6; + int j = 0; + ; + step[11] = file.substring(i, i + j); + while (file.charAt(i + j) != '"') + { + j++; + } + i += (j + 1); + } + else + { + i++; + } + } + i += 7; + if (!step[14].equals("done")) + act = parent.newAtomChild(step[0], step[12].startsWith("true"), new Point(0, 0)); + Logger.msg(7, "Step Created"); + + try + { + Logger.msg(7, "Starting to create info"); + if (!step[1].equals("")) + act.getProperties().put("Agent ID", step[1]); + if (!step[2].equals("")) + act.getProperties().put("Lc", step[2]); + if (!step[3].equals("")) + act.getProperties().put("Wc", step[3]); + if (!step[4].equals("")) + act.getProperties().put("Posts", step[4]); + if (!step[5].equals("")) + act.getProperties().put("PreparationTime", step[5]); + if (!step[6].equals("")) + act.getProperties().put("ActiveTime", step[6]); + if (!step[7].equals("")) + act.getProperties().put("OpStartdate", step[7]); + if (!step[8].equals("")) + act.getProperties().put("OpEnddate", step[8]); + if (!step[9].equals("")) + act.getProperties().put("Description", step[9]); + Logger.msg(7, "create info for " + act.getID()); + Logger.msg(7, "Finished to create info"); + } + catch (Exception e) + { + Logger.error(e); + } + file = file.substring(i); + i = 0; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Split.java b/src/main/java/com/c2kernel/lifecycle/instance/Split.java new file mode 100644 index 0000000..4fe1bfc --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Split.java @@ -0,0 +1,225 @@ +package com.c2kernel.lifecycle.instance; + +import java.util.Vector; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.traversal.GraphTraversal; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.scripting.ScriptingEngineException; + +/** + * @version $Revision: 1.47 $ $Date: 2006/05/29 13:17:45 $ + * @author $Author: abranson $ + */ +public abstract class Split extends WfVertex +{ + public Vector mErrors; + + /** + * @see java.lang.Object#Object() + */ + public Split() + { + mErrors = new Vector(0, 1); + getProperties().put("RoutingScriptName", ""); + getProperties().put("RoutingScriptVersion", ""); + } + + private boolean loopTested; + + private int mItemSystemKey = -1; + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#runNext() + */ + @Override + public abstract void runNext(AgentPath agent) throws ScriptingEngineException; + + /** + * Method addNext. + * + * @param idNext + */ + void addNext(String idNext) + { + new Next(this, (WfVertex) getParent().search(idNext)); + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#addNext(com.c2kernel.lifecycle.instance.WfVertex) + */ + @Override + public Next addNext(WfVertex vertex) + { + Next nxt = new Next(this, vertex); + int num = getOutGraphables().length; + try + { + num = Integer.parseInt((String) getProperties().get("LastNum")); + } catch (Exception e) + { + } + nxt.getProperties().put("Alias", String.valueOf(num)); + getProperties().put("LastNum", String.valueOf(num + 1)); + return nxt; + } + + /** + * Method getItemSystemKey. + * + * @return int + */ + public int getItemSystemKey() + { + return mItemSystemKey; + } + + /** + * Method setItemSystemKey. + * + * @param itemSystemKey + */ + public void setItemSystemKey(int itemSystemKey) + { + mItemSystemKey = itemSystemKey; + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#reinit(int) + */ + // public void initItemSystemKey(String systemKey) { + // setItemSystemKey(systemKey); + // } + @Override + public void reinit(int idLoop) + { + Vertex[] outVertices = getOutGraphables(); + for (Vertex outVertice : outVertices) + ((WfVertex) outVertice).reinit(idLoop); + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#verify() + */ + @Override + public boolean verify() + { + mErrors.removeAllElements(); + int nbInEdgres = getParent().getChildrenGraphModel().getInEdges(this).length; + if (nbInEdgres == 0 && this.getID() != getParent().getChildrenGraphModel().getStartVertexId()) + { + mErrors.add("not enough previous"); + return false; + } + if (nbInEdgres > 1) + { + mErrors.add("Bad nb of previous"); + return false; + } + if (getOutEdges().length <= 1 && !(this instanceof Loop)) + { + mErrors.add("not enough next"); + return false; + } + if (!(this instanceof Loop)) + { + Vertex[] outV = getOutGraphables(); + Vertex[] anteVertices = GraphTraversal.getTraversal(getParent().getChildrenGraphModel(), this, GraphTraversal.kUp, false); + boolean loop = false; + boolean errInLoop = true; + for (int i = 0; i < outV.length; i++) + { + for (int j = 0; j < anteVertices.length; j++) + if (!loop && outV[i].getID() == anteVertices[j].getID()) + { + if (outV[i] instanceof Loop) + { + loop = true; + j = anteVertices.length; + i = outV.length; + } else + { + errInLoop = false; + } + } + } + if (errInLoop && loop) + { + mErrors.add("Problem in Loop"); + return false; + } + } + return true; + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#getErrors() + */ + @Override + public String getErrors() + { + if (mErrors.size() == 0) + return "No error"; + else + return mErrors.elementAt(0); + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#run() + */ + @Override + public void run(AgentPath agent) throws ScriptingEngineException + { + runNext(agent); + } + + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#loop() + */ + @Override + public boolean loop() + { + boolean loop2 = false; + if (!loopTested) + { + loopTested = true; + if (getOutGraphables().length != 0) + { + Vertex[] outVertices = getOutGraphables(); + for (int i = 0; i < outVertices.length; i++) + { + WfVertex tmp = (WfVertex) getOutGraphables()[i]; + loop2 = loop2 || tmp.loop(); + } + } + } + loopTested = false; + return loop2; + } + + public String[] nextNames() + { + Vertex[] vs = getOutGraphables(); + String[] result = new String[vs.length]; + for (int i = 0; i < vs.length; i++) + result[i] = vs[i].getName(); + return result; + } + + protected boolean isInTable(String test, String[] list) + { + if (test == null) + return false; + for (String element : list) + if (test.equals(element)) + return true; + return false; + } + + @Override + public void runfirst(AgentPath agent) throws ScriptingEngineException + { + runNext(agent); + } + +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/lifecycle/instance/WfVertex.java b/src/main/java/com/c2kernel/lifecycle/instance/WfVertex.java new file mode 100644 index 0000000..f6cec33 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/WfVertex.java @@ -0,0 +1,180 @@ +package com.c2kernel.lifecycle.instance; + + + +import java.util.HashMap; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.GraphableVertex; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lifecycle.routingHelpers.ViewpointDataHelper; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.scripting.Script; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.KeyValuePair; +import com.c2kernel.utils.Logger; + +/** + * @version $Revision: 1.38 $ $Date: 2005/09/07 13:46:31 $ + * @author $Author: abranson $ + */ +public abstract class WfVertex extends GraphableVertex +{ + /**sets the activity available to be executed on start of Workflow or composite activity (when it is the first one of the + * (sub)process*/ + public abstract void runfirst(AgentPath agent) throws ScriptingEngineException; + + /** + * @see java.lang.Object#Object() + */ + public WfVertex() + { + super(); + setIsLayoutable(true); + setIsComposite(false); + } + + /** + * Method runNext. + */ + public void runNext(AgentPath agent) throws ScriptingEngineException + { + try + { + ((CompositeActivity)getParent()).request(agent, Transitions.COMPLETE, null); + } + catch (Exception e) + { + //Logger.error(e); + } + + } + + /** + * Method reinit. + * @param idLoop + */ + public abstract void reinit( int idLoop ); + + /** + * Method verify. + * @return boolean + */ + public abstract boolean verify(); + + /** + * Method getErrors. + * @return String + */ + public abstract String getErrors(); + + /** + * Method run. + */ + public abstract void run(AgentPath agent) throws ScriptingEngineException; + + /** + * Method loop. + * @return boolean + */ + public abstract boolean loop(); + + /** + * Method addNext. + * @param vertex + */ + public abstract Next addNext(WfVertex vertex); + + protected Object evaluateScript(String scriptName, String scriptVersion) throws ScriptingEngineException + { + + try + { + EntityPath entity = ((CompositeActivity) getParent()).getWf().getItemEntityPath(); + Script script = getScript(scriptName, scriptVersion); + + KeyValuePair[] k = getProperties().getKeyValuePairs(); + HashMap requiredInput = script.getAllInputParams(); + for (KeyValuePair element : k) { + if (requiredInput.containsKey(element.getKey())) + { + String value = element.getStringValue(); + Object inputParam = value; + + if (value.startsWith("viewpoint//")) + { + value = value.substring(11); + if (value.startsWith(".")) + value = entity.getSysKey() + value.substring(1); + try { + inputParam = ViewpointDataHelper.get(value)[0]; + } catch (ArrayIndexOutOfBoundsException ex) { + throw new InvalidDataException("Could not retrieve data from viewpoint: "+value, ""); + } + } + if (value.startsWith("property//")) + { + value = value.substring(10); + try { + inputParam = Gateway.getStorage().get(entity.getSysKey(), ClusterStorage.PROPERTY+"/"+value, null); + } catch (ObjectNotFoundException ex) { + inputParam = null; + } + } + Logger.msg(5, "Split.evaluateScript() - Setting param " + element.getKey() + " to " + inputParam.toString()); + script.setInputParamValue(element.getKey(), inputParam); + } + } + + if (requiredInput.containsKey("item")) { + script.setInputParamValue("item", Gateway.getProxyManager().getProxy(entity)); + } + if (requiredInput.containsKey("agent")) { + AgentPath systemAgent = Gateway.getLDAPLookup().getRoleManager().getAgentPath("system"); + script.setInputParamValue("agent", Gateway.getProxyManager().getProxy(systemAgent)); + } + Object retVal = script.execute(); + Logger.msg(2, "Split.evaluateScript() - Script returned "+retVal); + if (retVal == null) retVal = ""; + return retVal; + } + catch (Exception e) + { + Logger.msg(1, "Split.evaluateScript() - Error: Script " + scriptName); + Logger.error(e); + throw new ScriptingEngineException(); + } + } + + private static Script getScript(String name, String version) throws ScriptingEngineException + { + Script script; + try + { + script = new Script(name, Integer.parseInt(version)); + } + catch (NumberFormatException e) + { // version not valid + int split = name.indexOf(":"); + if (split > -1) + { + script = new Script(name.substring(0, split), name.substring(split + 1)); + } + else + throw new ScriptingEngineException("Could not find script " + name + " v" + version); + } + + return script; + } + + + public Workflow getWf() + { + return ((CompositeActivity)getParent()).getWf(); + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/instance/Workflow.java b/src/main/java/com/c2kernel/lifecycle/instance/Workflow.java new file mode 100644 index 0000000..1d12ee6 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/Workflow.java @@ -0,0 +1,208 @@ +package com.c2kernel.lifecycle.instance; +import java.awt.Point; +import java.util.ArrayList; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStepContainer; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +/** + * @version $Revision: 1.64 $ $Date: 2005/09/30 07:09:48 $ + * @author $Author: abranson $ + */ +public class Workflow extends CompositeActivity implements C2KLocalObject +{ + /** TypeNameAndConstructionInfo[] variables added by Steve */ + private final TypeNameAndConstructionInfo[] mVertexTypeNameAndConstructionInfo = + { + new TypeNameAndConstructionInfo(Language.translate("AND Split"), "AndSplit"), + new TypeNameAndConstructionInfo(Language.translate("OR Split"), "OrSplit"), + new TypeNameAndConstructionInfo(Language.translate("XOR Split"), "XOrSplit"), + new TypeNameAndConstructionInfo(Language.translate("Join"), "Join"), + new TypeNameAndConstructionInfo(Language.translate("Loop"), "LoopSplit"), + new TypeNameAndConstructionInfo(Language.translate("Atomic"), "Atomic"), + new TypeNameAndConstructionInfo(Language.translate("Composite"), "Composite") + }; + private final TypeNameAndConstructionInfo[] mEdgeTypeNameAndConstructionInfo = + { + new TypeNameAndConstructionInfo(Language.translate("Next Edge"), "Next") + }; + /** + * @see java.lang.Object#Object() + */ + public Workflow() + { + getProperties().put("ItemSystemKey", null); + } + + public Workflow(CompositeActivity domain) { + this(); + domain.setName("domain"); + initChild(domain, true, new Point(150, 100)); + PredefinedStepContainer act = new PredefinedStepContainer(); + addChild(act, new GraphPoint(300, 100)); + } + + /** + * Method getVertexTypeNameAndConstructionInfo. + * + * @return TypeNameAndConstructionInfo[] + */ + /** getVertexTypeNameAndConstructionInfo() added by Steve */ + public TypeNameAndConstructionInfo[] getVertexTypeNameAndConstructionInfo() + { + return mVertexTypeNameAndConstructionInfo; + } + /** + * Method getEdgeTypeNameAndConstructionInfo. + * + * @return TypeNameAndConstructionInfo[] + */ + /** getVertexTypeNameAndConstructionInfo() added by Steve */ + public TypeNameAndConstructionInfo[] getEdgeTypeNameAndConstructionInfo() + { + return mEdgeTypeNameAndConstructionInfo; + } + /** + * Method requestAction. + * + * @param agentInfo + * @param stepPath + * @param transitionID + * @param reguestData + * @throws ObjectNotFoundException + * @throws AccessRightsException + * @throws InvalidTransitionException + * @throws InvalidDataException + */ + //requestData is xmlstring + public void requestAction(AgentPath agent, String stepPath, int transitionID, String requestData) + throws ObjectNotFoundException, AccessRightsException, InvalidTransitionException, InvalidDataException, ObjectAlreadyExistsException + { + Logger.msg(3, "Action: " + Transitions.getTransitionName(transitionID) + " " + stepPath + " by " + agent.getAgentName()); + if (search(stepPath) != null) + ((Activity) search(stepPath)).request(agent, transitionID, requestData); + else + throw new ObjectNotFoundException(stepPath + " not found", ""); + } + + /** + * @see com.c2kernel.graph.model.GraphableVertex#getPath() + */ + @Override + public String getPath() + { + return "workflow"; + } + /** + * @see com.c2kernel.graph.model.Vertex#getName() + */ + @Override + public String getName() + { + return "workflow"; + } + /** + * @see com.c2kernel.lifecycle.instance.Activity#getType() + */ + @Override + public String getType() + { + return "workflow"; + } + /** + * @see com.c2kernel.graph.model.Vertex#setName(java.lang.String) + */ + @Override + public void setName(String name) + { + } + /** + * @see com.c2kernel.lifecycle.instance.WfVertex#verify() + */ + @Override + public boolean verify() + { + for (int i = 0; i < getChildren().length; i++) + { + if (!((WfVertex) getChildren()[i]).verify()) + { + mErrors.add("error in children"); + return false; + } + } + return true; + } + /** + * @see com.c2kernel.lifecycle.instance.Activity#getWf() + */ + @Override + public Workflow getWf() + { + return this; + } + /** + * Method initialise. + * + * @param systemKey + */ + public void initialise(int systemKey, AgentPath agent) + { + this.getProperties().put("ItemSystemKey", new Integer(systemKey)); + try + { + runfirst(agent); + } + catch (ScriptingEngineException ex) + { + Logger.error(ex); + } + } + /** + * Method calculateJobs. + * + * @param type + * @return JobList + */ + /** + * if type = 0 only domain steps will be queried if type = 1 only predefined steps will be queried else both will be queried + */ + public ArrayList calculateJobs(AgentPath agent, int type) + { + ArrayList jobs = new ArrayList(); + if (type != 1) + jobs.addAll(((CompositeActivity) search("workflow/domain")).calculateJobs(agent, true)); + if (type != 0) + jobs.addAll(((CompositeActivity) search("workflow/predefined")).calculateJobs(agent, true)); + return jobs; + } + /** + * @see com.c2kernel.lifecycle.instance.CompositeActivity#hasGoodNumberOfActivity() + */ + @Override + public boolean hasGoodNumberOfActivity() + { + return true; + } + /** + * @see com.c2kernel.entity.C2KLocalObject#getClusterType() + */ + @Override + public String getClusterType() + { + return ClusterStorage.LIFECYCLE; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/XOrSplit.java b/src/main/java/com/c2kernel/lifecycle/instance/XOrSplit.java new file mode 100644 index 0000000..25baf0b --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/XOrSplit.java @@ -0,0 +1,54 @@ +package com.c2kernel.lifecycle.instance; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.scripting.ScriptingEngineException; + +/** + * @version $Revision: 1.23 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ +public class XOrSplit extends Split +{ + /** + * @see java.lang.Object#Object() + */ + public XOrSplit() + { + super(); + } + + @Override + public void runNext(AgentPath agent) throws ScriptingEngineException + { + ArrayList nextsToFollow = new ArrayList(); + String nexts = this.evaluateScript( + (String) getProperties().get("RoutingScriptName"), + (String) getProperties().get("RoutingScriptVersion")).toString(); + + StringTokenizer tok = new StringTokenizer(nexts,","); + String[] nextsTab = new String[tok.countTokens()]; + for (int i=0;i -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + } + else if (("Broken |".equals(((Next)edge).getProperties().get("Type")))) + { + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + } + int minX = midPoint.x - 10; + int minY = midPoint.y - 10; + int maxX = midPoint.x + 10; + int maxY = midPoint.y + 10; + g2d.drawLine(minX, minY, maxX, minY); + g2d.drawLine(maxX, minY, maxX, maxY); + g2d.drawLine(maxX, maxY, minX, maxY); + g2d.drawLine(minX, maxY, minX, minY); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexFactory.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexFactory.java new file mode 100644 index 0000000..39e7ee9 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexFactory.java @@ -0,0 +1,92 @@ +package com.c2kernel.lifecycle.instance.gui.model; +import java.awt.Point; +import java.io.Serializable; +import java.util.HashMap; + +import javax.swing.JOptionPane; + +import com.c2kernel.graph.model.GraphModelManager; +import com.c2kernel.graph.model.TypeNameAndConstructionInfo; +import com.c2kernel.graph.model.VertexFactory; +import com.c2kernel.lifecycle.ActivityDef; +import com.c2kernel.lifecycle.chooser.ActivityChooser; +import com.c2kernel.lifecycle.chooser.WorkflowDialogue; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Resource; +public class WfVertexFactory implements VertexFactory, WorkflowDialogue +{ + protected CompositeActivity mRootAct = null; + @Override + public void create(GraphModelManager graphModelManager, Point location, TypeNameAndConstructionInfo typeNameAndConstructionInfo) + { + String vertexTypeId = null; + if (mRootAct != null && typeNameAndConstructionInfo.mInfo instanceof String) + { + vertexTypeId = (String) typeNameAndConstructionInfo.mInfo; + if (vertexTypeId.equals("Atomic") || vertexTypeId.equals("Composite")) + { + HashMap mhm = new HashMap(); + mhm.put("P1", vertexTypeId); + mhm.put("P2", location); + //************************************************ + ActivityChooser a = + new ActivityChooser( + Language.translate("Please enter a Type for the new activity"), + Language.translate("New " + vertexTypeId + " Activity"), + Resource.findImage("graph/newvertex_large.png").getImage(), + this, + mhm); + a.setVisible(true); + } + else + mRootAct.newChild(vertexTypeId, location); + } + } + @Override + public void setCreationContext(Object newContext) + { + if (newContext != null && newContext instanceof CompositeActivity) + mRootAct = (CompositeActivity) newContext; + } + @Override + public void loadThisWorkflow(String newName, HashMap hashMap) + { + String vertexTypeId = (String) hashMap.get("P1"); + Point location = (Point) hashMap.get("P2"); + if (newName == null) + return; + + + String unicName = newName; + while (mRootAct.search(mRootAct.getPath() + "/" + unicName) != null) + { + unicName = + (String) JOptionPane.showInputDialog( + null, + Language.translate("Activity name not unique. Please give another."), + Language.translate("New " + vertexTypeId + " Activity"), + JOptionPane.QUESTION_MESSAGE, + Resource.findImage("graph/newvertex_large.png"), + null, + null); + if (newName.equals("")) + return; + } + Activity act = null; + try + { + ActivityDef actD = LocalObjectLoader.getActDef(newName, "last"); + act = (Activity)actD.instantiate(unicName); + } + catch (Exception e) + { + } + if (act == null) + mRootAct.newChild(unicName, vertexTypeId, location); + else + mRootAct.newExistingChild(act, unicName, location); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexOutlineCreator.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexOutlineCreator.java new file mode 100644 index 0000000..e8cb303 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/model/WfVertexOutlineCreator.java @@ -0,0 +1,52 @@ +package com.c2kernel.lifecycle.instance.gui.model; + +import java.io.Serializable; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.model.VertexOutlineCreator; +import com.c2kernel.lifecycle.instance.Activity; + +public class WfVertexOutlineCreator implements VertexOutlineCreator,Serializable +{ + private final int mActivityWidth = 130; + private final int mActivityHeight = 60; + private final int mSplitJoinWidth = 60; + private final int mSplitJoinHeight = 25; + + @Override + public void setOutline(Vertex vertex) + { + GraphPoint centrePoint = vertex.getCentrePoint(); + GraphPoint[] outlinePoints = new GraphPoint[ 4 ]; + int vertexWidth = 0; + int vertexHeight = 0; + + if(vertex instanceof Activity) + { + vertexWidth = mActivityWidth; + vertexHeight = mActivityHeight; + } + else + { + vertexWidth = mSplitJoinWidth; + vertexHeight = mSplitJoinHeight; + } + + outlinePoints[ 0 ] = new GraphPoint(); + outlinePoints[ 0 ].x = centrePoint.x - vertexWidth / 2; + outlinePoints[ 0 ].y = centrePoint.y - vertexHeight / 2; + outlinePoints[ 1 ] = new GraphPoint(); + outlinePoints[ 1 ].x = centrePoint.x + vertexWidth / 2; + outlinePoints[ 1 ].y = centrePoint.y - vertexHeight / 2; + outlinePoints[ 2 ] = new GraphPoint(); + outlinePoints[ 2 ].x = centrePoint.x + vertexWidth / 2; + outlinePoints[ 2 ].y = centrePoint.y + vertexHeight / 2; + outlinePoints[ 3 ] = new GraphPoint(); + outlinePoints[ 3 ].x = centrePoint.x - vertexWidth / 2; + outlinePoints[ 3 ].y = centrePoint.y + vertexHeight / 2; + + vertex.setOutlinePoints( outlinePoints ); + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/ActivityRenderer.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/ActivityRenderer.java new file mode 100644 index 0000000..046ed7c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/ActivityRenderer.java @@ -0,0 +1,117 @@ +package com.c2kernel.lifecycle.instance.gui.view; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Polygon; + +import com.c2kernel.common.GTimeStamp; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.utils.DateUtility; +import com.c2kernel.utils.Language; +public class ActivityRenderer implements VertexRenderer +{ + private Paint mActivePaint = new Color(100, 255, 100); + private Paint mActiveCompPaint = new Color(100, 255, 255); + private Paint mInactivePaint = new Color(255, 255, 255); + private Paint mInactiveCompPaint = new Color(200, 200, 255); + private Paint mErrorPaint = new Color(255, 50, 0); + private Paint mTextPaint = Color.black; + @Override + public void draw(Graphics2D g2d, Vertex vertex) + { + Activity activity = (Activity) vertex; + boolean active = activity.getActive(); + boolean hasError = !activity.verify(); + boolean isComposite = activity.getIsComposite(); + GraphPoint centrePoint = activity.getCentrePoint(); + //String description = activity.getDescription(); + String[] linesOfText = new String[3]; + linesOfText[0] = "(" + activity.getType() + ")"; + linesOfText[1] = activity.getName(); + if (hasError) + linesOfText[2] = Language.translate(activity.getErrors()); + else + { + int cs = activity.getCurrentState(); + if (cs == States.WAITING && activity.getActive()) + linesOfText[2] = + Language.translate(States.getStateName(cs)) + + (((Boolean) activity.getProperties().get("Show time")).booleanValue() + ? " " + getWaitTime(activity.getActiveDate()) + : ""); + else if (cs == States.STARTED) + linesOfText[2] = + Language.translate(States.getStateName(cs)) + + (((Boolean) activity.getProperties().get("Show time")).booleanValue() + ? " " + getWaitTime(activity.getStartDate()) + : ""); + else + linesOfText[2] = Language.translate(States.getStateName(cs)); + } + + FontMetrics metrics = g2d.getFontMetrics(); + int lineWidth = 0; + int lineHeight = metrics.getHeight(); + int linesHeight = lineHeight * linesOfText.length; + int linesStartY = centrePoint.y - linesHeight / 2 + lineHeight * 2 / 3; + int x = 0; + int y = 0; + int i = 0; + GraphPoint[] outline = vertex.getOutlinePoints(); + Paint actColour; + if (hasError) + actColour = mErrorPaint; + else if (active) + if (isComposite) + actColour = mActiveCompPaint; + else + actColour = mActivePaint; + else if (isComposite) + actColour = mInactiveCompPaint; + else + actColour = mInactivePaint; + g2d.setPaint(actColour); + //g2d.fill3DRect( centrePoint.x - mSize.width / 2, centrePoint.y - mSize.height / 2, mSize.width, mSize.height, true ); + g2d.fill(graphPointsToPolygon(outline)); + g2d.setPaint(mTextPaint); + for (i = 0; i < linesOfText.length; i++) + { + lineWidth = metrics.stringWidth(linesOfText[i]); + x = centrePoint.x - lineWidth / 2; + y = linesStartY + i * lineHeight; + g2d.drawString(linesOfText[i], x, y); + } + } + private static Polygon graphPointsToPolygon(GraphPoint[] points) + { + Polygon polygon = new Polygon(); + int i = 0; + for (i = 0; i < points.length; i++) + { + polygon.addPoint(points[i].x, points[i].y); + } + return polygon; + } + private static String getWaitTime(GTimeStamp date) + { + GTimeStamp now = new GTimeStamp(); + DateUtility.setToNow(now); + long diff = DateUtility.diff(now, date); + long secondes = diff % 60; + long minutes = (diff / 60) % 60; + long hours = (diff / 3600) % 24; + long days = (diff / 3600 / 24); + if (days > 0) + return days + " " + Language.translate("d") + " " + hours + " " + Language.translate("h"); + if (hours > 0) + return hours + " " + Language.translate("h") + " " + minutes + " " + Language.translate("min"); + if (minutes > 0) + return minutes + " " + Language.translate("min"); + return secondes + " " + Language.translate("sec"); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/FindActDefPanel.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/FindActDefPanel.java new file mode 100644 index 0000000..4c1a148 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/FindActDefPanel.java @@ -0,0 +1,72 @@ +package com.c2kernel.lifecycle.instance.gui.view; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.SelectedVertexPanel; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.lifecycle.ActivitySlotDef; +import com.c2kernel.lookup.DomainPath; + +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2005/12/01 14:23:15 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class FindActDefPanel extends SelectedVertexPanel { + + JButton findButton; + ActivitySlotDef currentAct; + + public FindActDefPanel() { + super(); + findButton = new JButton("Open Definition"); + findButton.setEnabled(false); + add(findButton); + findButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + try { + DomainPath actPath = (DomainPath)new DomainPath("/desc/ActivityDesc/").find(currentAct.getActivityDef()); + MainFrame.treeBrowser.push(actPath); + } catch (ObjectNotFoundException e1) { } + } + }); + } + + /** + * + */ + + @Override + public void select(Vertex vert) { + if (vert instanceof ActivitySlotDef) { + findButton.setEnabled(true); + currentAct = (ActivitySlotDef)vert; + } + else + clear(); + + } + + /** + * + */ + + @Override + public void clear() { + findButton.setEnabled(false); + currentAct = null; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/SplitJoinRenderer.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/SplitJoinRenderer.java new file mode 100644 index 0000000..036f79a --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/SplitJoinRenderer.java @@ -0,0 +1,142 @@ +package com.c2kernel.lifecycle.instance.gui.view; + +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Paint; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.instance.AndSplit; +import com.c2kernel.lifecycle.instance.Join; +import com.c2kernel.lifecycle.instance.Loop; +import com.c2kernel.lifecycle.instance.OrSplit; +import com.c2kernel.lifecycle.instance.WfVertex; +import com.c2kernel.lifecycle.instance.XOrSplit; +import com.c2kernel.utils.Language; + +public class SplitJoinRenderer implements VertexRenderer +{ + private Paint mTextPaint = Color.black; + private Paint mBoxPaint = new Color( 204, 204, 204 ); + private Paint mErrorPaint = new Color( 255, 0, 0 ); + private boolean mTextOffsetsNotInitialised = true; + private int mTextYOffset = 0; + private String mAndText = "And"; + private int mAndTextXOffset = 0; + private String mOrText = "Or"; + private int mOrTextXOffset = 0; + private String mLoopText = "Loop"; + private int mLoopTextXOffset = 0; + private String mXOrText = "XOr"; + private int mXOrTextXOffset = 0; + private String mJoinText = "Join"; + private int mJoinTextXOffset = 0; + private String mRouteText = ""; + private int mRouteTextXOffset = 0; + private String mXXXText = "XXX"; + private int mXXXTextXOffset = 0; + + + @Override + public void draw( Graphics2D g2d, Vertex vertex) + { + GraphPoint centrePoint = vertex.getCentrePoint(); + String text = null; + int textXOffset = 0; + int vertexHeight = vertex.getHeight(); + int vertexWidth = vertex.getWidth(); + + + if ( mTextOffsetsNotInitialised ) + { + initialiseTextOffsets( g2d ); + mTextOffsetsNotInitialised = false; + } + if ( vertex instanceof AndSplit ) + { + text = Language.translate(mAndText); + textXOffset = mAndTextXOffset; + } + else if ( vertex instanceof OrSplit ) + { + text = Language.translate(mOrText); + textXOffset = mOrTextXOffset; + } + else if ( vertex instanceof Loop ) + { + text = Language.translate(mLoopText); + textXOffset = mLoopTextXOffset; + } + else if ( vertex instanceof XOrSplit ) + { + text = Language.translate(mXOrText); + textXOffset = mXOrTextXOffset; + } + else if ( vertex instanceof Join ) + { + text = Language.translate(mJoinText); + textXOffset = mJoinTextXOffset; + } + else if ( vertex instanceof Join) + { + String type= (String)((Join)vertex).getProperties().get("Type"); + if (type!=null && type.equals("Route")) + { + text = mRouteText; + textXOffset = mRouteTextXOffset; + } + else + { + text = Language.translate(mJoinText); + textXOffset = mJoinTextXOffset; + } + } + else + { + text = mXXXText; + textXOffset = mXXXTextXOffset; + } + + boolean hasErrors = ((WfVertex)vertex).verify(); + g2d.setPaint( hasErrors ? mBoxPaint : mErrorPaint ); + g2d.fillRect + ( + centrePoint.x - vertexWidth / 2, + centrePoint.y - vertexHeight / 2, + vertexWidth, + vertexHeight + ); + g2d.setPaint( mTextPaint ); + g2d.drawRect + ( + centrePoint.x - vertexWidth / 2, + centrePoint.y - vertexHeight / 2, + vertexWidth, + vertexHeight + ); + g2d.drawString( text, centrePoint.x - textXOffset, centrePoint.y + mTextYOffset ); + + if (!hasErrors) { + g2d.setPaint( mErrorPaint ); + String errors = Language.translate(((WfVertex)vertex).getErrors()); + int errorWidth = g2d.getFontMetrics().stringWidth( errors ); + g2d.drawString( errors, centrePoint.x - ( errorWidth / 2), centrePoint.y + vertexHeight ); + } + } + + private void initialiseTextOffsets( Graphics2D g2d ) + { + FontMetrics metrics = g2d.getFontMetrics(); + + + mTextYOffset = metrics.getHeight() / 3; + mAndTextXOffset = metrics.stringWidth( Language.translate(mAndText) ) / 2; + mOrTextXOffset = metrics.stringWidth( Language.translate(mOrText) ) / 2; + mXOrTextXOffset = metrics.stringWidth( Language.translate(mXOrText) ) / 2; + mJoinTextXOffset = metrics.stringWidth( Language.translate(mJoinText) ) / 2; + mLoopTextXOffset = metrics.stringWidth( Language.translate(mLoopText) ) / 2; + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/TransitionPanel.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/TransitionPanel.java new file mode 100644 index 0000000..094f900 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/TransitionPanel.java @@ -0,0 +1,187 @@ +package com.c2kernel.lifecycle.instance.gui.view; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; + +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.SelectedVertexPanel; +import com.c2kernel.gui.MainFrame; +import com.c2kernel.gui.tabs.EntityTabPane; +import com.c2kernel.gui.tabs.execution.Executor; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.stateMachine.StateMachine; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.8 $ + * $Date: 2005/09/07 13:46:31 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class TransitionPanel extends SelectedVertexPanel implements ActionListener { + protected Activity mCurrentAct; + protected GridBagLayout gridbag; + protected GridBagConstraints c; + protected Box transBox; + protected JComboBox executors; + protected JComboBox states = new JComboBox(States.states); + protected JCheckBox active = new JCheckBox(); + protected JLabel status = new JLabel(); + protected ItemProxy mItem; + + public TransitionPanel() { + super(); + gridbag = new GridBagLayout(); + setLayout(gridbag); + c = new GridBagConstraints(); + c.gridx=0; c.gridy=0; + c.weightx=1; c.weighty=0; + c.fill=GridBagConstraints.HORIZONTAL; + + JLabel title = new JLabel("Available Transitions"); + title.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(title, c); + add(title); + + c.gridy++; + gridbag.setConstraints(status, c); + add(status); + c.gridy++; + + transBox = Box.createHorizontalBox(); + gridbag.setConstraints(transBox, c); + add(transBox); + + c.weightx=0; c.gridx++; + executors = MainFrame.getExecutionPlugins(); + if (executors.getItemCount() > 1) { + gridbag.setConstraints(executors, c); + add(executors); + } + + + + if (MainFrame.isAdmin) { + c.gridx=0; c.gridy++; + title = new JLabel("State Hacking"); + title.setFont(EntityTabPane.titleFont); + gridbag.setConstraints(title, c); + add(title); + Box hackBox = Box.createHorizontalBox(); + hackBox.add(states); + hackBox.add(Box.createHorizontalGlue()); + hackBox.add(new JLabel("Active:")); + hackBox.add(active); + c.gridy++; + gridbag.setConstraints(hackBox, c); + add(hackBox); + states.addActionListener(this); + active.addActionListener(this); + } + + clear(); + + } + /** + * + */ + @Override + public void select(Vertex vert) { + clear(); + if (!(vert instanceof Activity)) return; + mCurrentAct = (Activity)vert; + states.setSelectedIndex(mCurrentAct.getCurrentState()); + states.setEnabled(true); + active.setSelected(mCurrentAct.active); + active.setEnabled(true); + Logger.msg("Retrieving possible transitions for activity "+mCurrentAct.getName()); + int[] transitions = mCurrentAct.getMachine().possibleTransition(); + if (transitions.length == 0) { + status.setText("None"); + return; + } + for (int i = 0; i < transitions.length; i++) { + String trans= Transitions.getTransitionName(transitions[i]); + if (!(transitions[i]==Transitions.DONE) && !(transitions[i]==Transitions.COMPLETE)) { + String buttonLabel = trans.substring(0,1).toUpperCase()+trans.substring(1); + JButton thisTrans = new JButton(buttonLabel); + thisTrans.setActionCommand("Trans:"+String.valueOf(transitions[i])); + thisTrans.addActionListener(this); + transBox.add(thisTrans); + transBox.add(Box.createHorizontalGlue()); + } + status.setText(transitions.length+" transitions possible."); + } + revalidate(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == active && mCurrentAct != null) { + mCurrentAct.active = active.isSelected(); + return; + } + if (e.getSource() == states && mCurrentAct != null) { + mCurrentAct.getMachine().state = states.getSelectedIndex(); + return; + } + if (!e.getActionCommand().startsWith("Trans:")) return; + int transition = Integer.parseInt(e.getActionCommand().substring(6)); + Logger.msg("Requesting transition "+transition); + Job thisJob = new Job(mItem.getSystemKey(), + mCurrentAct.getPath(), + transition, + new StateMachine(mCurrentAct).simulate(transition), + mCurrentAct.getCurrentState(), + mCurrentAct.getName(), + mCurrentAct.getProperties(), + mCurrentAct.getType(), + MainFrame.userAgent.getName()); + try { + Executor selectedExecutor = (Executor)executors.getSelectedItem(); + selectedExecutor.execute(thisJob, status); + } catch (Exception ex) { + String className = ex.getClass().getName(); + className = className.substring(className.lastIndexOf('.')+1); + Logger.error(ex); + JOptionPane.showMessageDialog(null, ex.getMessage(), className, JOptionPane.ERROR_MESSAGE); + } + + } + + @Override + public void clear() { + mCurrentAct = null; + transBox.removeAll(); + status.setText("No activity selected"); + states.setSelectedIndex(0); + states.setEnabled(false); + active.setSelected(false); + active.setEnabled(false); + revalidate(); + } + + + /** + * @param item The mItem to set. + */ + public void setItem(ItemProxy item) { + mItem = item; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfDirectedEdgeRenderer.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfDirectedEdgeRenderer.java new file mode 100644 index 0000000..f39d9a6 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfDirectedEdgeRenderer.java @@ -0,0 +1,130 @@ +package com.c2kernel.lifecycle.instance.gui.view; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; + +import com.c2kernel.graph.model.DirectedEdge; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.graph.view.DirectedEdgeRenderer; +import com.c2kernel.lifecycle.instance.Next; +public class WfDirectedEdgeRenderer implements DirectedEdgeRenderer +{ + private GeneralPath mArrowTemplate = new GeneralPath(); + public WfDirectedEdgeRenderer() + { + mArrowTemplate.moveTo(-5, 5); + mArrowTemplate.lineTo(0, 0); + mArrowTemplate.lineTo(5, 5); + } + @Override + public void draw(Graphics2D g2d, DirectedEdge directedEdge) + { + GraphPoint originPoint = directedEdge.getOriginPoint(); + GraphPoint terminusPoint = directedEdge.getTerminusPoint(); + GraphPoint midPoint = new GraphPoint(); + AffineTransform transform = new AffineTransform(); + Shape arrow = null; + Next next = (Next) directedEdge; + String text = (String) next.getProperties().get("Alias"); + g2d.setPaint(Color.black); + if (("Broken +".equals(next.getProperties().get("Type")))) + { + g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, (originPoint.y + terminusPoint.y) / 2); + g2d.drawLine(originPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, (originPoint.y + terminusPoint.y) / 2); + g2d.drawLine(terminusPoint.x, (originPoint.y + terminusPoint.y) / 2, terminusPoint.x, terminusPoint.y); + midPoint.x = (originPoint.x + terminusPoint.x) / 2; + midPoint.y = (originPoint.y + terminusPoint.y) / 2; + transform.translate(midPoint.x, midPoint.y); + transform.rotate( + calcArrowAngle( + originPoint.x, + originPoint.x - terminusPoint.x > -5 + && originPoint.x - terminusPoint.x < 5 ? originPoint.y : (originPoint.y + terminusPoint.y) / 2, + terminusPoint.x, + originPoint.x - terminusPoint.x > -5 + && originPoint.x - terminusPoint.x < 5 ? terminusPoint.y : (originPoint.y + terminusPoint.y) / 2)); + } + else if (("Broken -".equals(next.getProperties().get("Type")))) + { + g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, originPoint.y); + g2d.drawLine(terminusPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y); + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? terminusPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : originPoint.y; + transform.translate(midPoint.x, midPoint.y); + transform.rotate( + calcArrowAngle( + arrowOnY ? terminusPoint.x : originPoint.x, + arrowOnY ? originPoint.y : originPoint.y, + arrowOnY ? terminusPoint.x : terminusPoint.x, + arrowOnY ? terminusPoint.y : originPoint.y)); + } + else if (("Broken |".equals(next.getProperties().get("Type")))) + { + g2d.drawLine(originPoint.x, originPoint.y, originPoint.x, terminusPoint.y); + g2d.drawLine(originPoint.x, terminusPoint.y, terminusPoint.x, terminusPoint.y); + boolean arrowOnY = !(originPoint.y - terminusPoint.y < 60 && originPoint.y - terminusPoint.y > -60); + midPoint.x = arrowOnY ? originPoint.x : (originPoint.x + terminusPoint.x) / 2; + midPoint.y = arrowOnY ? (originPoint.y + terminusPoint.y) / 2 : terminusPoint.y; + transform.translate(midPoint.x, midPoint.y); + transform.rotate( + calcArrowAngle( + arrowOnY ? terminusPoint.x : originPoint.x, + arrowOnY ? originPoint.y : originPoint.y, + arrowOnY ? terminusPoint.x : terminusPoint.x, + arrowOnY ? terminusPoint.y : originPoint.y)); + } + else + { + g2d.drawLine(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y); + midPoint.x = originPoint.x + (terminusPoint.x - originPoint.x) / 2; + midPoint.y = originPoint.y + (terminusPoint.y - originPoint.y) / 2; + transform.translate(midPoint.x, midPoint.y); + transform.rotate(calcArrowAngle(originPoint.x, originPoint.y, terminusPoint.x, terminusPoint.y)); + } + arrow = mArrowTemplate.createTransformedShape(transform); + g2d.draw(arrow); + if (text != null) + g2d.drawString(text, midPoint.x + 10, midPoint.y); + } + private static double calcArrowAngle(int originX, int originY, int terminusX, int terminusY) + { + double width = terminusX - originX; + double height = terminusY - originY; + if ((width == 0) && (height > 0)) + { + return Math.PI; + } + if ((width == 0) && (height < 0)) + { + return 0; + } + if ((width > 0) && (height == 0)) + { + return Math.PI / 2.0; + } + if ((width < 0) && (height == 0)) + { + return -1.0 * Math.PI / 2.0; + } + if ((width > 0) && (height > 0)) + { + return Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width)); + } + if ((width > 0) && (height < 0)) + { + return Math.atan(Math.abs(width) / Math.abs(height)); + } + if ((width < 0) && (height < 0)) + { + return -1.0 * Math.atan(Math.abs(width) / Math.abs(height)); + } + if ((width < 0) && (height > 0)) + { + return -1.0 * (Math.PI / 2.0 + Math.atan(Math.abs(height) / Math.abs(width))); + } + return 0.0; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfVertexRenderer.java b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfVertexRenderer.java new file mode 100644 index 0000000..92a1021 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/gui/view/WfVertexRenderer.java @@ -0,0 +1,23 @@ +package com.c2kernel.lifecycle.instance.gui.view; + +import java.awt.Graphics2D; + +import com.c2kernel.graph.model.Vertex; +import com.c2kernel.graph.view.VertexRenderer; +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.lifecycle.instance.Join; +import com.c2kernel.lifecycle.instance.Split; + +public class WfVertexRenderer implements VertexRenderer +{ + protected ActivityRenderer mActivityRenderer = new ActivityRenderer(); + protected SplitJoinRenderer mSplitJoinRenderer = new SplitJoinRenderer(); + + @Override + public void draw( Graphics2D g2d, Vertex vertex) + { + if ( vertex instanceof Activity ) { mActivityRenderer.draw( g2d, vertex); } + else if ( ( vertex instanceof Split ) || ( vertex instanceof Join ) ) { mSplitJoinRenderer.draw( g2d, vertex ); } + } +} + diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddC2KObject.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddC2KObject.java new file mode 100644 index 0000000..b61187c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddC2KObject.java @@ -0,0 +1,75 @@ +/************************************************************************** + * AddC2KObject + * + * $Workfile$ + * $Revision: 1.31 $ + * $Date: 2004/10/21 08:02:19 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2004/10/21 08:02:19 $ + * @version $Revision: 1.31 $ + **************************************************************************/ +public class AddC2KObject extends PredefinedStep +{ + /************************************************************************** + * Constructor for Castror + **************************************************************************/ + public AddC2KObject() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + + Logger.msg(1, "AddC2KObject::request() - Starting."); + + checkAccessRights(agent); + EntityPath entityPath = getItemEntityPath(); + + if (entityPath!=null) + { + try + { + + Logger.msg(5, "AddC2KObject::request() - data:" + getDataList(requestData)[0]); + + C2KLocalObject obj = (C2KLocalObject)CastorXMLUtility.unmarshall(getDataList(requestData)[0]); + Gateway.getStorage().put(entityPath.getSysKey(), obj, null ); + sendEventStoreOutcome(transitionID, requestData, agent); + } + catch( Exception ex ) + { + Logger.error("AddC2KObject::request() - during unmarshall."); + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + Logger.msg(1, "AddC2KObject::request() - DONE."); + } + else + throw new InvalidDataException("EntityPath is null.", ""); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddDomainPath.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddDomainPath.java new file mode 100644 index 0000000..2cf619e --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddDomainPath.java @@ -0,0 +1,67 @@ +/************************************************************************** + * AddDomainPath + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + + + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + +public class AddDomainPath extends PredefinedStep +{ + public AddDomainPath() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + Logger.msg(8,"AddAlias::request()"); + LDAPLookup lookupManager = Gateway.getLDAPLookup(); + + Logger.msg(1,"AddAlias::request() - Starting."); + + checkAccessRights(agent); + + try + { + EntityPath entityPath = getItemEntityPath(); + DomainPath domainPath = new DomainPath(getDataList(requestData)[0], entityPath); + lookupManager.add(domainPath); + Logger.msg(8,"AddDomainPath::request() - systemKey:" + entityPath.getSysKey() + + ". Adding dompath. DONE."); + } + catch (InvalidEntityPathException ex) + { + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + catch( Exception ex ) + { + Logger.error("AddDomainPath::request() - during anyHelper.extract."); + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + sendEventStoreOutcome(transitionID, requestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddStepsFromDescription.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddStepsFromDescription.java new file mode 100644 index 0000000..f70c053 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AddStepsFromDescription.java @@ -0,0 +1,56 @@ +package com.c2kernel.lifecycle.instance.predefined; + +//Java +import java.awt.Point; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +public class AddStepsFromDescription extends PredefinedStep +{ + public AddStepsFromDescription() + { + super(); + } + + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, InvalidTransitionException, InvalidDataException + { + Workflow lifeCycle = getWf(); + + Logger.msg(1, "AddStepsFromDescription::request() - Starting "); + + checkAccessRights(agent); + + try + { + + Logger.msg(8, "AddStepsFromDescription::request() - data:" + getDataList(requestData)[0]); + lifeCycle.getChildGraphModel().removeVertex(lifeCycle.search("workflow/domain")); + CompositeActivityDef actDef = (CompositeActivityDef) CastorXMLUtility.unmarshall(getDataList(requestData)[0]); + CompositeActivity domain = (CompositeActivity)actDef.instantiate(); + lifeCycle.initChild(domain, true, new Point(150, 100)); + domain.setName("domain"); + domain.setType(actDef.getName()); + lifeCycle.run(agent); + Gateway.getStorage().put(getItemEntityPath().getSysKey(), lifeCycle, null); + Logger.msg(1, "AddStepsFromDescription::request() - DONE."); + sendEventStoreOutcome(transitionID, requestData, agent); + } + catch (Exception ex) + { + Logger.error("AddStepsFromDescription::request() - during unmarshall."); + Logger.error(ex); + throw new InvalidDataException("AddStepsFromDescription::request() - during unmarshall.", ""); + } + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/AssignItemToSlot.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AssignItemToSlot.java new file mode 100644 index 0000000..0ad5adc --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/AssignItemToSlot.java @@ -0,0 +1,116 @@ +/************************************************************************** + * AssignItemToSlot + * + * $Workfile$ + * $Revision: 1.8 $ + * $Date: 2004/10/21 08:02:19 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + + +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.collection.MembershipException; +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2004/10/21 08:02:19 $ + * @version $Revision: 1.8 $ + **************************************************************************/ +public class AssignItemToSlot extends PredefinedStep +{ + /************************************************************************** + * Constructor for Castor + **************************************************************************/ + public AssignItemToSlot() + { + super(); + } + + + /** + * Params: + * 0 - collection name + * 1 - slot number + * 2 - target entity key + */ + @Override + public void request(AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + EntityPath entityPath = getItemEntityPath(); + String collName; + int slotNo; + int entityKey; + Collection coll; + + Logger.msg(1, "AssignItemToSlot::request() - Starting."); + + checkAccessRights(agent); + + // extract parameters + try { + entityPath = getItemEntityPath(); + String[] params = getDataList(requestData); + collName = params[0]; + slotNo = Integer.parseInt(params[1]); + entityKey = Integer.parseInt(params[2]); + } catch (Exception e) { + throw new InvalidDataException("Invalid parameters", ""); + } + + // load collection + try { + coll = (Collection)Gateway.getStorage().get(entityPath.getSysKey(), ClusterStorage.COLLECTION+"/"+collName, null); + } catch (Exception e) { + Logger.error(e); + throw new InvalidDataException("Error loading collection "+collName, ""); + } + + // find member and assign entity + boolean stored = false; + for (Object name : coll.getMembers().list) { + CollectionMember member = (CollectionMember)name; + if (member.getID() == slotNo) { + if (member.getEntityKey() > -1) + throw new InvalidDataException("Member slot not empty", ""); + try { + member.assignEntity(entityKey); + } catch (MembershipException e) { + throw new InvalidDataException("Entity "+entityKey+" does not fit in this slot", ""); + } + stored = true; + break; + } + } + if (!stored) { + throw new InvalidDataException("Member slot "+slotNo+" not found.", ""); + } + + + try { + Gateway.getStorage().put(entityPath.getSysKey(), coll, null); + } catch (ClusterStorageException e) { + Logger.error(e); + throw new InvalidDataException("Error storing collection", ""); + } + sendEventStoreOutcome(transitionID, requestData, agent); + + Logger.msg(1, "AssignItemToSlot::request() - DONE."); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/CreateItemFromDescription.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/CreateItemFromDescription.java new file mode 100644 index 0000000..8c55f3a --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/CreateItemFromDescription.java @@ -0,0 +1,183 @@ +/************************************************************************** + * CreateItemFromDescription + * + * $Workfile$ + * $Revision: 1.47 $ + * $Date: 2005/10/13 08:13:58 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.c2kernel.collection.Collection; +import com.c2kernel.collection.CollectionDescription; +import com.c2kernel.collection.CollectionMember; +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.CorbaServer; +import com.c2kernel.entity.TraceableEntity; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.TransactionManager; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.property.PropertyDescriptionList; +import com.c2kernel.property.PropertyUtility; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2005/10/13 08:13:58 $ + * @version $Revision: 1.47 $ + **************************************************************************/ +public class CreateItemFromDescription extends PredefinedStep +{ + public CreateItemFromDescription() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request(AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, InvalidTransitionException, InvalidDataException,ObjectAlreadyExistsException + { + String[] input = getDataList(requestData); + String newName = input[0]; + String domPath = input[1]; + CompositeActivityDef wfDef; + String wfDefName = null; + if (input.length > 2) // override wf + wfDefName = input[2]; + + PropertyArrayList props = new PropertyArrayList(); + Logger.msg(1, "AddNewItem::request() - Starting."); + TransactionManager storage = Gateway.getStorage(); + LDAPLookup lookup = Gateway.getLDAPLookup(); + EntityPath myPath = getItemEntityPath(); + checkAccessRights(agent); + + try { + // check if the path is already taken + DomainPath context = new DomainPath(new DomainPath(domPath), newName); + Logger.debug(8,"context "+context.getSysKey()+" "+context.getPath()+" "+context.getString()); + if (context.getSysKey()!=-1) + throw new ObjectAlreadyExistsException("The item name " +newName+ " exists already."); + + // get init objects + String[] collNames = storage.getClusterContents(myPath.getSysKey(), ClusterStorage.COLLECTION); + ArrayList collections = new ArrayList(); + + + // loop through collections to instantiate + for (String collName : collNames) { + Collection thisCol = (Collection)storage.get(myPath.getSysKey(), ClusterStorage.COLLECTION+"/"+collName, null); + if (thisCol instanceof CollectionDescription) { + CollectionDescription thisDesc = (CollectionDescription)thisCol; + collections.add(CastorXMLUtility.marshall(thisDesc.newInstance())); + } + else if (thisCol.getName().equalsIgnoreCase("workflow") && wfDefName == null) { + ArrayList members = thisCol.getMembers().list; + // get the first member from the wf collection + CollectionMember wfMember = members.get(0); + wfDefName = wfMember.resolveEntity().getName(); + } + } + + // load workflow def + if (wfDefName == null) + throw new InvalidDataException("No workflow given or defined", ""); + + try { + wfDef = (CompositeActivityDef)LocalObjectLoader.getActDef(wfDefName, "last"); + } catch (ObjectNotFoundException ex) { + throw new InvalidDataException("Workflow def '"+wfDefName+"' item not found", ""); + } catch (ClassCastException ex) { + throw new InvalidDataException("Activity def '"+wfDefName+"' was not Composite", ""); + } + + + // copy properties -- intend to create from propdesc + PropertyDescriptionList pdList = PropertyUtility.getPropertyDescriptionOutcome(myPath.getSysKey()); + props = pdList.instanciate(); + // set Name prop or create if not present + boolean foundName = false; + for (Property prop : props.list) { + if (prop.getName().equals("Name")) { + foundName = true; + prop.setValue(newName); + } + } + if (!foundName) props.list.add(new Property("Name", newName)); + props.list.add( new Property("Creator", agent.getAgentName())); + + /* ITEM CREATION */ + + // generate new entity key + Logger.msg(6, "CreateItemFromDescription - Requesting new sysKey"); + EntityPath entityPath = lookup.getNextKeyManager().generateNextEntityKey(); + + // resolve the item factory + Logger.msg(6, "CreateItemFromDescription - Resolving item factory"); + + // create the Item object + Logger.msg(3, "CreateItemFromDescription - Creating Item"); + CorbaServer factory = Gateway.getCorbaServer(); + if (factory == null) throw new AccessRightsException("This process cannot create new Items", ""); + TraceableEntity newItem = (TraceableEntity)factory.createEntity(entityPath); + Gateway.getLDAPLookup().add(entityPath); + + + // initialise it with its properties and workflow + + Logger.msg(3, "CreateItemFromDescription - Initializing Item"); + + newItem.initialise( + agent.getSysKey(), + CastorXMLUtility.marshall(props), + CastorXMLUtility.marshall(wfDef.instantiate())); + + // add collections + if (collections.size() > 0) { + Logger.msg(6, "CreateItemFromDescription - Adding Collections"); + String[] colls = new String[1]; + for (Iterator iter = collections.iterator(); iter.hasNext();) { + colls[0] = iter.next(); + newItem.requestAction(agent.getSysKey(), "workflow/predefined/AddC2KObject", Transitions.COMPLETE, PredefinedStep.bundleData(colls)); + } + } + + // add its domain path + Logger.msg(3, "CreateItemFromDescription - Creating "+context); + context.setEntity(entityPath); + Gateway.getLDAPLookup().add(context); + } catch (ObjectAlreadyExistsException e) { + Logger.error(e); + throw e; + } catch (AccessRightsException e) { + Logger.error(e); + throw e; + } catch (Exception e) { + Logger.error(e); + throw new InvalidDataException(e.getMessage(), ""); + } + + sendEventStoreOutcome(transitionID, requestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/Erase.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/Erase.java new file mode 100644 index 0000000..ffdb07c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/Erase.java @@ -0,0 +1,85 @@ +/************************************************************************** + * RemoveC2KObject + * + * $Workfile$ + * $Revision: 1.10 $ + * $Date: 2005/11/15 15:56:38 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + + + +import java.util.Enumeration; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; + + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2005/11/15 15:56:38 $ + * @version $Revision: 1.10 $ + **************************************************************************/ +public class Erase extends PredefinedStep +{ + public Erase() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request(AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + Logger.msg(1, "Erase::request() - Starting."); + + checkAccessRights(agent); + try + { + EntityPath entityPath = getItemEntityPath(); + + // find entity name + Property name = (Property)Gateway.getStorage().get(entityPath.getSysKey(), ClusterStorage.PROPERTY+"/Name", null); + + // get all domain paths + Enumeration domPaths = Gateway.getLDAPLookup().search(new DomainPath(), name.getValue()); + while (domPaths.hasMoreElements()) { + DomainPath path = (DomainPath)domPaths.nextElement(); + // delete them + if (path.getSysKey() == entityPath.getSysKey()) + Gateway.getLDAPLookup().delete(path); + } + + //clear out all storages + Gateway.getStorage().removeCluster(entityPath.getSysKey(), "", null); + + //remove domain path + Gateway.getLDAPLookup().delete(entityPath); + } + catch( Exception ex ) + { + + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + Logger.msg(1, "Erase::request() - DONE."); + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/Import.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/Import.java new file mode 100644 index 0000000..2f99937 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/Import.java @@ -0,0 +1,71 @@ +/************************************************************************** + * AddDomainPath + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.21 $ + * $Date: 2005/06/02 12:17:22 $ + * + * Params: Schemaname_version:Viewpoint (optional), Outcome + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class Import extends PredefinedStep +{ + public Import() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + Logger.msg(8,"Import::request()"); + + Logger.msg(1,"Import::request() - Starting."); + + checkAccessRights(agent); + + String[] params = getDataList(requestData); + + + int split1 = params[0].indexOf('_'); + int split2 = params[0].indexOf(':'); + + String schemaName = params[0].substring(0, split1); + String viewpoint = "last"; + int schemaVersion; + if (split2 > -1) { + schemaVersion = Integer.parseInt(params[0].substring(split1+1, split2)); + viewpoint = params[0].substring(split2+1); + } + else + schemaVersion = Integer.parseInt(params[0].substring(split1+1)); + + // set type & ver + getProperties().put("SchemaType", schemaName); + getProperties().put("SchemaVersion", String.valueOf(schemaVersion)); + getProperties().put("Viewpoint", viewpoint); + + requestData = params[1]; + + sendEventStoreOutcome(transitionID, requestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStep.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStep.java new file mode 100644 index 0000000..8aec993 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStep.java @@ -0,0 +1,156 @@ +package com.c2kernel.lifecycle.instance.predefined; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.xml.serialize.Method; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.utils.Logger; +/*********************************************************************************************************************************************************************************************************************************************************************************************************** + * @author $Author: sgaspard $ $Date: 2004/09/21 10:32:17 $ + * @version $Revision: 1.14 $ + **********************************************************************************************************************************************************************************************************************************************************************************************************/ +public class PredefinedStep extends Activity +{ + /******************************************************************************************************************************************************************************************************************************************************************************************************* + * predefined Steps are always Active, and have only one transition subclasses could override this method (if necessary) + ******************************************************************************************************************************************************************************************************************************************************************************************************/ + private boolean isPredefined = false; + @Override + public boolean getActive() + { + if (isPredefined) + return true; + else + return super.getActive(); + } + @Override + public String getTransitions() + { + if (isPredefined) + return "done"; + else + return super.getTransitions(); + } + @Override + public String getErrors() + { + if (isPredefined) + return getName(); + else + return super.getErrors(); + } + @Override + public boolean verify() + { + if (isPredefined) + return true; + else + return super.verify(); + } + /** + * Returns the isPredefined. + * + * @return boolean + */ + public boolean getIsPredefined() + { + return isPredefined; + } + /** + * Sets the isPredefined. + * + * @param isPredefined + * The isPredefined to set + */ + public void setIsPredefined(boolean isPredefined) + { + this.isPredefined = isPredefined; + } + @Override + public String getType() + { + return getName(); + } + // generic bundling of parameters + static public String bundleData(String[] data) + { + try + { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document dom = builder.newDocument(); + Element root = dom.createElement("PredefinedStepOutcome"); + dom.appendChild(root); + for (String element : data) { + Element param = dom.createElement("param"); + Text t = dom.createTextNode(element); + param.appendChild(t); + root.appendChild(param); + } + // xalan method - use internal xerces one instead +// TransformerFactory transFactory = TransformerFactory.newInstance(); +// Transformer transformer = transFactory.newTransformer(); +// StringWriter stringOut = new StringWriter(); +// transformer.transform(new DOMSource(dom), new StreamResult(stringOut)); +// return stringOut.toString(); + + OutputFormat format = new OutputFormat(Method.XML, null, false); + StringWriter stringOut = new StringWriter(); + XMLSerializer serial = new XMLSerializer(stringOut, format); + serial.asDOMSerializer(); + serial.serialize(dom); + return stringOut.toString(); + } + catch (Exception e) + { + Logger.error(e); + StringBuffer xmlData = new StringBuffer().append(""); + for (String element : data) + xmlData.append(""); + xmlData.append(""); + return xmlData.toString(); + } + } + // generic bundling of single parameter + static public String bundleData(String data) + { + return ""; + } + static public String[] getDataList(String xmlData) + { + try + { + Document scriptDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(xmlData))); + NodeList nodeList = scriptDoc.getElementsByTagName("param"); + String[] result = new String[nodeList.getLength()]; + for (int i = 0; i < nodeList.getLength(); i++) + { + Node n = nodeList.item(i).getFirstChild(); + if (n instanceof CDATASection) + result[i] = ((CDATASection) n).getData(); + else if (n instanceof Text) + result[i] = ((Text) n).getData(); + } + return result; + } + catch (Exception ex) + { + Logger.error("Exception::PredefinedStep::getDataList()"); + Logger.error(ex); + } + return null; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStepContainer.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStepContainer.java new file mode 100644 index 0000000..d065afb --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/PredefinedStepContainer.java @@ -0,0 +1,61 @@ +package com.c2kernel.lifecycle.instance.predefined; +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.lifecycle.instance.CompositeActivity; +public class PredefinedStepContainer extends CompositeActivity +{ + protected int num = 0; + + public PredefinedStepContainer() + { + super(); + setName("predefined"); + getProperties().put("Description", "Contains all predefined Steps"); + createChildren(); + } + public void createChildren() + { + predInit("CreateItemFromDescription", "Create a new item using this item as its description", new CreateItemFromDescription()); + predInit("AddDomainPath", "Adds a new path to this entity in the LDAP domain tree", new AddDomainPath()); + predInit("RemoveDomainPath", "Removes an existing path to this Entity from the LDAP domain tree", new RemoveDomainPath()); + predInit("AddStepsFromDescription", "Creates the domain-specific LifeCycle from a description", new AddStepsFromDescription()); + predInit("ReplaceDomainWorkflow", "Replaces the domain CA with the supplied one. Used by the GUI to save new Wf layout", new ReplaceDomainWorkflow()); + predInit("AddC2KObject", "Adds a new named C2Kernel object to this Item", new AddC2KObject()); + predInit("WriteProperty", "Writes a property to the Item", new WriteProperty()); + predInit("RemoveC2KObject", "Removes the named C2Kernel object from this Item.", new RemoveC2KObject()); + predInit("AssignItemToSlot", "Assigns the referenced entity to a pre-existing slot in a collection of this one", new AssignItemToSlot()); + predInit("Erase", "Deletes all objects and domain paths for this item.", new Erase()); + predInit("Import", "Imports an outcome into the Item, with a given schema and viewpoint", new Import()); + } + + public void predInit(String alias, String Description, PredefinedStep act) + { + act.setName(alias); + act.setType(alias); + act.getProperties().put("Description", Description); + act.getProperties().put("SchemaType", "PredefinedStepOutcome"); + act.getProperties().put("SchemaVersion", "0"); + act.setCentrePoint(new GraphPoint()); + act.setIsPredefined(true); + addChild(act, new GraphPoint(100, 75 * ++num)); + } + @Override + public boolean verify() + { + return true; + } + @Override + public String getErrors() + { + return "predefined"; + } + @Override + public boolean getActive() + { + return true; + } + @Override + public String getTransitions() + { + return ""; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveC2KObject.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveC2KObject.java new file mode 100644 index 0000000..c9513a8 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveC2KObject.java @@ -0,0 +1,67 @@ +/************************************************************************** + * RemoveC2KObject + * + * $Workfile$ + * $Revision: 1.28 $ + * $Date: 2005/11/15 15:56:38 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2005/11/15 15:56:38 $ + * @version $Revision: 1.28 $ + **************************************************************************/ +public class RemoveC2KObject extends PredefinedStep +{ + public RemoveC2KObject() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request(AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + Logger.msg(1, "RemoveC2KObject::request() - Starting."); + + checkAccessRights(agent); + String path = null; + try + { + path = getDataList(requestData)[0]; + EntityPath entityPath = getItemEntityPath(); + + Logger.msg(5, "RemoveC2KObject::request() - path:"+path); + + Gateway.getStorage().remove( entityPath.getSysKey(), path, null ); + sendEventStoreOutcome(transitionID, requestData, agent); + } + catch( Exception ex ) + { + Logger.error("RemoveC2KObject::request() - invalid data - path:"+path); + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + Logger.msg(1, "RemoveC2KObject::request() - DONE."); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveDomainPath.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveDomainPath.java new file mode 100644 index 0000000..19ff7c6 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/RemoveDomainPath.java @@ -0,0 +1,59 @@ +/************************************************************************** + * AddDomainPath + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + + + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; + +public class RemoveDomainPath extends PredefinedStep +{ + public RemoveDomainPath() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + Logger.msg(8,"RemoveDomainPath::request()"); + LDAPLookup lookupManager = Gateway.getLDAPLookup(); + + Logger.msg(1,"RemoveDomainPath::request() - Starting."); + + checkAccessRights(agent); + + try + { + DomainPath domainPath = new DomainPath(getDataList(requestData)[0]); + lookupManager.delete(domainPath); + Logger.msg(8,"AddAlias::request() - context:" + domainPath.toString() + " DONE."); + + } + catch( Exception ex ) + { + Logger.error("AddAlias::request() - during anyHelper.extract."); + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + sendEventStoreOutcome(transitionID, requestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/ReplaceDomainWorkflow.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/ReplaceDomainWorkflow.java new file mode 100644 index 0000000..ba3e6c6 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/ReplaceDomainWorkflow.java @@ -0,0 +1,53 @@ +package com.c2kernel.lifecycle.instance.predefined; + +//Java +import java.awt.Point; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +public class ReplaceDomainWorkflow extends PredefinedStep +{ + public ReplaceDomainWorkflow() + { + super(); + } + + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, InvalidTransitionException, InvalidDataException + { + Workflow lifeCycle = getWf(); + + Logger.msg(1, "ReplaceDomainWorkflow::request() - Starting "); + + checkAccessRights(agent); + + try + { + + Logger.msg(8, "ReplaceDomainWorkflow::request() - data:" + getDataList(requestData)[0]); + lifeCycle.getChildGraphModel().removeVertex(lifeCycle.search("workflow/domain")); + CompositeActivity domain = (CompositeActivity) CastorXMLUtility.unmarshall(getDataList(requestData)[0]); + lifeCycle.initChild(domain, true, new Point(150, 100)); + Gateway.getStorage().put(getItemEntityPath().getSysKey(), lifeCycle, null); + Logger.msg(1, "ReplaceDomainWorkflow::request() - DONE."); + sendEventStoreOutcome(transitionID, requestData, agent); + // refresh jobs + lifeCycle.refreshJobs(); + } + catch (Exception ex) + { + Logger.error("ReplaceDomainWorkflow::request() - during unmarshall."); + Logger.error(ex); + throw new InvalidDataException("ReplaceDomainWorkflow::request() - during unmarshall.", null); + } + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/ServerPredefinedStepContainer.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/ServerPredefinedStepContainer.java new file mode 100644 index 0000000..21eacda --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/ServerPredefinedStepContainer.java @@ -0,0 +1,41 @@ +package com.c2kernel.lifecycle.instance.predefined; + +import com.c2kernel.graph.model.GraphPoint; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.CreateNewAgent; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.CreateNewItem; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2005/06/02 10:19:33 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +// public static final String codeRevision = "$Revision: 1.2 $ $Date: 2005/06/02 10:19:33 $ $Author: abranson $"; +public class ServerPredefinedStepContainer extends PredefinedStepContainer { + + + @Override + public void createChildren() + { + super.createChildren(); + serverPredInit("CreateNewItem", "Creates a new Item in this Server without description.", new CreateNewItem(), "NewItem"); + serverPredInit("CreateNewAgent", "Creates a new Item in this Server without description.", new CreateNewAgent(), "NewAgent"); + } + + public void serverPredInit(String alias, String Description, PredefinedStep act, String schema) + { + act.setName(alias); + act.setType(alias); + act.getProperties().put("Description", Description); + act.getProperties().put("SchemaType", schema); + act.getProperties().put("SchemaVersion", "0"); + act.getProperties().put("AgentRole", "Admin"); + act.setCentrePoint(new GraphPoint()); + act.setIsPredefined(true); + addChild(act, new GraphPoint(100, 75 * ++num)); + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/WriteProperty.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/WriteProperty.java new file mode 100644 index 0000000..77a0b43 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/WriteProperty.java @@ -0,0 +1,77 @@ +/************************************************************************** + * WriteProperty + * + * $Workfile$ + * $Revision: 1.3 $ + * $Date: 2004/10/21 08:02:19 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined; + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2004/10/21 08:02:19 $ + * @version $Revision: 1.3 $ + **************************************************************************/ +public class WriteProperty extends PredefinedStep +{ + /************************************************************************** + * Constructor for Castror + **************************************************************************/ + public WriteProperty() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + + Logger.msg(1, "WriteProperty::request() - Starting."); + + checkAccessRights(agent); + EntityPath entityPath = getItemEntityPath(); + + if (entityPath!=null) + { + String[] params = getDataList(requestData); + if (params.length != 2) + throw new InvalidDataException("WriteProperty::request() - need 2 params - name and value", ""); + try + { + + Logger.msg(5, "WriteProperty::request() - name:" + params[0] +" val:"+params[1]); + + Property newProp = new Property(params[0], params[1]); + Gateway.getStorage().put(entityPath.getSysKey(), newProp, null ); + sendEventStoreOutcome(transitionID, requestData, agent); + } + catch( Exception ex ) + { + Logger.error("WriteProperty::request() - during unmarshall."); + Logger.error(ex); + throw new InvalidDataException(ex.toString(), ""); + } + + Logger.msg(1, "WriteProperty::request() - DONE."); + } + else + throw new InvalidDataException("EntityPath is null.", ""); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Aggregation.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Aggregation.java new file mode 100644 index 0000000..2de12e0 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Aggregation.java @@ -0,0 +1,25 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + +import java.util.ArrayList; + +public class Aggregation implements java.io.Serializable { + + public boolean isDescription; + public ArrayList aggregationMemberList; + public String name; + + public Aggregation() { + super(); + aggregationMemberList = new ArrayList(); + } + + public Aggregation(String name, boolean isDescription) { + this(); + this.name = name; + this.isDescription = isDescription; + } + + public com.c2kernel.collection.Aggregation create() { + return new com.c2kernel.collection.AggregationInstance(); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/AggregationMember.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/AggregationMember.java new file mode 100644 index 0000000..29d3cf9 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/AggregationMember.java @@ -0,0 +1,21 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + +public class AggregationMember implements java.io.Serializable { + + public int slotNo; + public String itemDescriptionPath; + public String itemPath; + public Geometry geometry; + + + public AggregationMember() { + super(); + } + + public AggregationMember(int slotNo, String itemDescPath, String itemPath, Geometry geometry) { + this.slotNo = slotNo; + this.itemDescriptionPath = itemDescPath; + this.itemPath = itemPath; + this.geometry = geometry; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewAgent.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewAgent.java new file mode 100644 index 0000000..aa30677 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewAgent.java @@ -0,0 +1,49 @@ +/************************************************************************** + * AddDomainPath + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + + + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStep; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +public class CreateNewAgent extends PredefinedStep +{ + public CreateNewAgent() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + checkAccessRights(agent); + String redactedRequestData; + try { + NewAgent newAgent = (NewAgent)CastorXMLUtility.unmarshall(requestData); + newAgent.create(agent.getSysKey()); + newAgent.password = "REDACTED"; + redactedRequestData = CastorXMLUtility.marshall(newAgent); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidDataException("Error creating agent", ""); + } + + sendEventStoreOutcome(transitionID, redactedRequestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewItem.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewItem.java new file mode 100644 index 0000000..a66b062 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/CreateNewItem.java @@ -0,0 +1,46 @@ +/************************************************************************** + * CreateNewItem + * + * Copyright (C) 2005 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + + + + +import com.c2kernel.common.AccessRightsException; +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStep; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +public class CreateNewItem extends PredefinedStep +{ + public CreateNewItem() + { + super(); + } + + //requestdata is xmlstring + @Override + public void request( AgentPath agent, int transitionID, String requestData) + throws AccessRightsException, + InvalidTransitionException, + InvalidDataException + { + checkAccessRights(agent); + + try { + NewItem item = (NewItem)CastorXMLUtility.unmarshall(requestData); + item.create(agent.getSysKey()); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidDataException("Error creating item", ""); + } + sendEventStoreOutcome(transitionID, requestData, agent); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Dependency.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Dependency.java new file mode 100644 index 0000000..1124ede --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Dependency.java @@ -0,0 +1,44 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + +import java.util.ArrayList; + +import com.c2kernel.collection.MembershipException; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.property.PropertyUtility; + +public class Dependency implements java.io.Serializable { + + public String name; + public boolean isDescription; + public String itemDescriptionPath; + public ArrayList dependencyMemberList; + + public Dependency() { + super(); + dependencyMemberList = new ArrayList(); + } + + public Dependency(String itemDesc) { + this(); + this.itemDescriptionPath = itemDesc; + } + + /** + * @return + */ + public com.c2kernel.collection.Dependency create() throws MembershipException{ + com.c2kernel.collection.Dependency newDep = isDescription?new com.c2kernel.collection.DependencyDescription(name):new com.c2kernel.collection.Dependency(name); + if (itemDescriptionPath != null && itemDescriptionPath.length()>0) { + PropertyUtility.getPropertyDescriptionOutcome(new DomainPath(itemDescriptionPath).getSysKey()); + //TODO: set props and class identifiers + } + for (DependencyMember thisMem : dependencyMemberList) { + int syskey = new DomainPath(thisMem.itemPath).getSysKey(); + if (syskey == -1) + throw new MembershipException("Cannot find "+thisMem.itemPath+" specified for collection."); + newDep.addMember(syskey); + } + return newDep; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/DependencyMember.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/DependencyMember.java new file mode 100644 index 0000000..b70619f --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/DependencyMember.java @@ -0,0 +1,18 @@ + +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + +public class DependencyMember implements java.io.Serializable { + + + public String itemPath; + + public DependencyMember() { + super(); + } + + public DependencyMember(String itemPath) { + this.itemPath = itemPath; + + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Geometry.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Geometry.java new file mode 100644 index 0000000..f18b6d4 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Geometry.java @@ -0,0 +1,29 @@ + + +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + + + +public class Geometry implements java.io.Serializable { + + + public int x; + + public int y; + + public int width; + + public int height; + + public Geometry() { + super(); + } + + public Geometry(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java new file mode 100644 index 0000000..540a6fc --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewAgent.java @@ -0,0 +1,63 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; + +import com.c2kernel.common.CannotManageException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.ActiveEntity; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.RolePath; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +public class NewAgent implements java.io.Serializable { + + public String name; + + public String password; + + public ArrayList roles; + + public NewAgent() { + super(); + roles = new ArrayList(); + } + + public NewAgent(String name, String password) { + this.name = name; + this.password = password; + } + + protected void create(int agentId) throws ObjectNotFoundException, ObjectCannotBeUpdated, NoSuchAlgorithmException, CannotManageException, ObjectAlreadyExistsException { + AgentPath newAgent = Gateway.getLDAPLookup().getNextKeyManager().generateNextAgentKey(); + newAgent.setAgentName(name); + newAgent.setPassword(password); + ActiveEntity newAgentEnt = (ActiveEntity)Gateway.getCorbaServer().createEntity(newAgent); + Gateway.getLDAPLookup().add(newAgent); + // assemble properties + PropertyArrayList propList = new PropertyArrayList(); + propList.list.add(new com.c2kernel.property.Property("Name", name)); + propList.list.add(new com.c2kernel.property.Property("Type", "Agent")); + try { + newAgentEnt.initialise(CastorXMLUtility.marshall(propList)); + } catch (Exception ex) { + Logger.error(ex); + throw new CannotManageException("Error initialising new agent"); + } + for (String role : roles) { + RolePath thisRole; + try { + thisRole = Gateway.getLDAPLookup().getRoleManager().getRolePath(role); + } catch (ObjectNotFoundException ex) { + thisRole = Gateway.getLDAPLookup().getRoleManager().createRole(role, false); + } + thisRole.addAgent(newAgent); + } + + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java new file mode 100644 index 0000000..f155ced --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/NewItem.java @@ -0,0 +1,141 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; + + +import java.util.ArrayList; + +import com.c2kernel.collection.MembershipException; +import com.c2kernel.common.CannotManageException; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.TraceableEntity; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +/** + * Complete Structure for new item + * + * @version $Revision: 1.8 $ $Date: 2006/03/03 13:52:21 $ + */ + +public class NewItem { + + public String name; + + /** + * The initial Domain Path to be created for this Item. + */ + public String initialPath; + + /** + * The name of the Composite Activity Definition to be + * instantiated for the workflow of this Item + */ + public String workflow; + + /** + * New Properties for the item + */ + public ArrayList propertyList; + + /** + * Field _aggregationList + */ + public ArrayList aggregationList; + + /** + * Field _dependencyList + */ + public ArrayList dependencyList; + + + public NewItem() { + super(); + propertyList = new ArrayList(); + aggregationList = new ArrayList(); + dependencyList = new ArrayList(); + } + + public NewItem(String name, String initialPath, String wf) { + this(); + this.name = name; + this.initialPath = initialPath; + this.workflow = wf; + } + + public void setProperty(String name, String value) { + for (Property prop : propertyList) { + if (prop.name.equals(name)) { + prop.value = value; + return; + } + } + propertyList.add(new Property(name, value)); + } + + protected void create(int agentId) throws ObjectCannotBeUpdated, ObjectNotFoundException, CannotManageException, ObjectAlreadyExistsException { + DomainPath domPath = new DomainPath(new DomainPath(initialPath), name); + if (domPath.exists()) + throw new ObjectAlreadyExistsException(domPath+" already exists!", ""); + + // create item + EntityPath entPath = Gateway.getLDAPLookup().getNextKeyManager().generateNextEntityKey(); + TraceableEntity newItem = (TraceableEntity)Gateway.getCorbaServer().createEntity(entPath); + Gateway.getLDAPLookup().add(entPath); + + // assemble properties + PropertyArrayList propList = new PropertyArrayList(); + propList.list.add(new com.c2kernel.property.Property("Name", name)); + for (Property element : propertyList) { + propList.list.add(new com.c2kernel.property.Property(element.name, element.value)); + } + // init the new item + try { + + // find workflow def + CompositeActivityDef compact = (CompositeActivityDef)LocalObjectLoader.getActDef(workflow, "last"); + + newItem.initialise( + agentId, + CastorXMLUtility.marshall(propList), + CastorXMLUtility.marshall(compact.instantiate())); + } catch (Exception ex) { + Logger.error("Error initialising new item"); + Logger.error(ex); + throw new CannotManageException("Problem initialising new item. See server log.", ""); + } + + // create collections + + for (Dependency element: dependencyList) { + try { + Gateway.getStorage().put(entPath.getSysKey(), element.create(), null); + } catch (ClusterStorageException ex) { + Logger.error(ex); + throw new CannotManageException("Could not create Dependency "+element.name, ""); + } catch (MembershipException ex) { + Logger.error(ex); + throw new CannotManageException("A specified member is not of the correct type in "+element.name, ""); + } + } + + for (Aggregation element : aggregationList) { + try { + Gateway.getStorage().put(entPath.getSysKey(), element.create(), null); + } catch (ClusterStorageException ex) { + Logger.error(ex); + throw new CannotManageException("Could not create Aggregation "+element.name, ""); + } + } + // register domain path + domPath.setEntity(entPath); + Gateway.getLDAPLookup().add(domPath); + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Property.java b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Property.java new file mode 100644 index 0000000..e2d214c --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/predefined/entitycreation/Property.java @@ -0,0 +1,26 @@ +package com.c2kernel.lifecycle.instance.predefined.entitycreation; +/** + * New Properties for the item + * + * @version $Revision: 1.1 $ $Date: 2005/04/28 13:48:26 $ + */ +public class Property implements java.io.Serializable { + + public String name; + public String value; + + + //----------------/ + //- Constructors -/ + //----------------/ + + public Property() { + super(); + } + + public Property(String name, String value) { + super(); + this.name = name; + this.value = value; + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java new file mode 100644 index 0000000..8159106 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/StateMachine.java @@ -0,0 +1,142 @@ + +package com.c2kernel.lifecycle.instance.stateMachine; + +import java.io.Serializable; + +import com.c2kernel.lifecycle.instance.Activity; +import com.c2kernel.utils.Logger; + +/** + * @version $Revision: 1.30 $ $Date: 2004/06/04 09:39:19 $ + * @author $Author: sgaspard $ + */ +/** this class represents the link between 2 successive activities */ +public class StateMachine implements Serializable +{ + public int state = 0; + private Activity activity; + + public static final String SKIPPABLE = "Skippable"; + public static final String REPEATABLE = "Repeatable"; + public static final String IGNORABLE = "Ignorable"; + public static final String AUTOSTART = "Autostart"; + + + /** + * Method StateMachine. + * @param act + */ + public StateMachine(Activity act) + { + activity = act; + } + + /** row : States from (WAITING,RESERVED,STARTED,SUSPENDED,FINISHED,RWAITING,RRESERVED,RSTARTED,RSUSPENDED) + * collumn : transition (RESERVE,START,SKIP,DONE,COMPLETE,SUSPEND,REASIGN,RESUME,REPEAT,IGNORE,PROCEED) + * cell : State that is reached (-1 if transition not allowed) + */ + private int[][] getCurrentMachine() + { + int [][] returnArray = + { /*RESERVE, START, SKIP, DONE,COMPLETE,SUSPEND,REASIGN,RESUME, REPEAT, IGNORE, PROCEED*/ + /*0 WAITING*/ { 1,getActive()?2:-1,getSkippable()?4:-1,getActive()?4:-1, -1, -1, -1, -1, -1, -1, -1},/*0 WAITING*/ + /*1 RESERVED*/ { -1,getActive()?2:-1,getSkippable()?4:-1,getActive()?4:-1, -1, -1, -1, -1, -1, 0, -1},/*1 RESERVED*/ + /*2 STARTED*/ { -1, -1, -1, -1, 4, 3, -1, -1, -1,getIgnorable()?0:-1, -1},/*2 STARTED*/ + /*3 SUSPENDED*/ { -1, -1, -1, -1, -1, -1, 2, 2, -1,getIgnorable()?0:-1, -1},/*3 SUSPENDED*/ + /*4 FINISHED*/ { -1, -1, -1, -1, -1, -1, -1, -1,getRepeatable()?!getAutoStart()?5:7:-1, -1,getActive()?4:-1},/*4 FINISHED*/ + /*5 RWAITING*/ { 6,getActive()?7:-1,getSkippable()?4:-1,getActive()?4:-1, -1, -1, -1, -1, -1, -1, -1},/*5 RWAITING*/ + /*6 RRESERVED*/ { -1,getActive()?7:-1,getSkippable()?4:-1,getActive()?4:-1, -1, -1, -1, -1, -1, -1, -1},/*6 RRESERVED*/ + /*7 RSTARTED*/ { -1, -1, -1, -1, 4, 8, -1, -1, -1,getIgnorable()?5:-1, -1},/*7 RSTARTED*/ + /*8 RSUSPENDED*/ { -1, -1, -1, -1, -1, -1, 8, 7, -1, -1, -1} /*8 RSUSPENDED*/ + }; + return returnArray; + } + + /** + * @see java.lang.Object#Object() + */ + public StateMachine() + { + } + + /** + * Method getCurrentState. + * @return String + */ + public int getCurrentState() + { + return state; + } + + /** + * Method possibleTransition. + * @return String[] + */ + public int[] possibleTransition() + { + int[] trans = new int[9]; + int cmpt = 0; + for (int i=0; i< getCurrentMachine()[state].length;i++) + if (getCurrentMachine()[state][i]!=-1) trans[cmpt++]=i; + + int [] result = new int[cmpt]; + for (int i=0;i -1) { + state=newState; + return true; + } + Logger.msg("StateMachine.traverse() - Illegal transition "+Transitions.getTransitionName(transition)+" from "+States.getStateName(state)); + return false; + } + public int simulate(int transition) + { + return getCurrentMachine()[state][transition]; + } + /** + * Returns the ignorable. + * @return boolean + */ + public boolean getIgnorable() + { + return ((Boolean)activity.getProperties().get(IGNORABLE)).booleanValue(); + } + + /** + * Returns the repeatable. + * @return boolean + */ + public boolean getRepeatable() + { + return ((Boolean)activity.getProperties().get(REPEATABLE)).booleanValue(); + } + + /** + * Returns the skippable. + * @return boolean + */ + public boolean getSkippable() + { + return ((Boolean)activity.getProperties().get(SKIPPABLE)).booleanValue(); + } + + public boolean getAutoStart() + { + return ((Boolean)activity.getProperties().get(AUTOSTART)).booleanValue(); + } + public boolean getActive() + { + return activity.getActive(); + } + +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/States.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/States.java new file mode 100644 index 0000000..b142e35 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/States.java @@ -0,0 +1,40 @@ +package com.c2kernel.lifecycle.instance.stateMachine; + + +/** + * @author XSeb74 + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class States +{ + public final static int WAITING = 0; + public final static int RESERVED = 1; + public final static int STARTED = 2; + public final static int SUSPENDED = 3; + public final static int FINISHED = 4; + public final static int RWAITING = 5; + public final static int RRESERVED = 6; + public final static int RSTARTED = 7; + public final static int RSUSPENDED = 8; + + //everything less that this constant is NOT a repeating state + public final static int REPEATSTATESTART = 5; + + public static final String[] states = { "Waiting", "Reserved", "Started", "Suspended", "Finished", "Waiting(R)", "Reserved(R)", "Started(R)", "Suspended(R)" }; + + public static String getStateName(int state) + { + try + { + return states[state]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + return "Invalid State: " + state; + } + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transitions.java b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transitions.java new file mode 100644 index 0000000..4239baa --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/instance/stateMachine/Transitions.java @@ -0,0 +1,41 @@ +package com.c2kernel.lifecycle.instance.stateMachine; + +import com.c2kernel.utils.Language; + +/** + * @author XSeb74 + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class Transitions +{ + public final static int RESERVE = 0; + public final static int START = 1; + public final static int SKIP = 2; + public final static int DONE = 3; + public final static int COMPLETE = 4; + public final static int SUSPEND = 5; + public final static int REASSIGN = 6; + public final static int RESUME = 7; + public final static int REPEAT = 8; + public final static int IGNORE = 9; + public final static int PROCEED = 10; + public final static int ACTIVATION = 11; + + private static String[] transitions = { "reserve", "start", "skip", "done", "complete", "suspend", "reassign", "resume", "repeat","ignore","proceed","activation" }; + + public static String getTransitionName(int trans) + { + try + { + return Language.translate(transitions[trans]); + } + catch (ArrayIndexOutOfBoundsException ex) + { + return "Invalid Transition: " + trans; + } + } +} diff --git a/src/main/java/com/c2kernel/lifecycle/routingHelpers/ViewpointDataHelper.java b/src/main/java/com/c2kernel/lifecycle/routingHelpers/ViewpointDataHelper.java new file mode 100644 index 0000000..0258347 --- /dev/null +++ b/src/main/java/com/c2kernel/lifecycle/routingHelpers/ViewpointDataHelper.java @@ -0,0 +1,79 @@ +package com.c2kernel.lifecycle.routingHelpers; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.XmlElementParser; + +/** + * @author XSeb74 + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ViewpointDataHelper +{ + static Object[] errArr = { "" }; + /** + * Method get. + * @param value + * @return String[] + * @throws Exception + */ + /**@param value : EntityPath:ActivityPath:XPathInOutcome*/ + public static Object [] get(String value) throws Exception + { + //Syntax of search : /: + String entityPath; + String viewpoint; + String xpath; + Object[] retArr; + + // find syskey, viewname, xpath + int firstSlash = value.indexOf("/"); + if (firstSlash > 0) { + entityPath = value.substring(0, firstSlash); + int startXPath = value.indexOf(":"); + if (startXPath==-1) { + viewpoint = value.substring(firstSlash + 1); + xpath = null; + } else { + viewpoint = value.substring(firstSlash + 1, startXPath); + xpath = value.substring(startXPath+1); + } + } + else return errArr; + + // find entity + EntityPath sourcePath; + try + { + sourcePath = new EntityPath(Integer.parseInt(entityPath)); + } catch (Exception e) { + sourcePath = new EntityPath(entityPath); + } + + try { + // load viewpoint + ItemProxy dataSource = (ItemProxy)Gateway.getProxyManager().getProxy(sourcePath); + Viewpoint view = (Viewpoint)dataSource.getObject(ClusterStorage.VIEWPOINT + "/" + viewpoint); + Outcome outcome = view.getOutcome(); + if (xpath == null) { + retArr = new Object[1]; + retArr[0] = outcome; + } + else + retArr = XmlElementParser.parse(outcome.getData(), xpath); + return retArr; + + } catch (ObjectNotFoundException e) { + return errArr; + } + } +} diff --git a/src/main/java/com/c2kernel/lookup/AgentPath.java b/src/main/java/com/c2kernel/lookup/AgentPath.java new file mode 100644 index 0000000..5ff6988 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/AgentPath.java @@ -0,0 +1,154 @@ +/************************************************************************** + * EntityPath.java + * + * $Revision: 1.12 $ + * $Date: 2005/10/13 08:15:00 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lookup; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.xerces.impl.dv.util.Base64; + +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.process.Gateway; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; +import com.novell.ldap.LDAPEntry; + + +/** +* Extends Path to enforce SystemKey structure and support int form +* +* @version $Revision: 1.12 $ $Date: 2005/10/13 08:15:00 $ +* @author $Author: abranson $ +**/ +public class AgentPath extends EntityPath +{ + + private String mAgentName=null; + private String mPassword=null; + + public AgentPath(int syskey, String agentName) + throws InvalidAgentPathException,InvalidEntityPathException + { + super(syskey); + if (agentName!=null && agentName.length()>0) + setAgentName(agentName); + else + throw new InvalidAgentPathException(); + } + + public AgentPath(int syskey) + throws InvalidEntityPathException + { + super(syskey); + } + + public AgentPath(EntityPath entity) { + super(); + try { + setSysKey(entity.getSysKey()); + } catch (InvalidEntityPathException ex) { + //won't happen as the entity path was valid + } + } + + public void setAgentName(String agentID) + { + mAgentName = agentID; + } + + public String getAgentName() + { + if (mAgentName==null) + { + try { + LDAPEntry agentEntry = LDAPLookupUtils.getEntry(Gateway.getLDAPLookup().getConnection(), this.getDN() + mLocalPath); + mAgentName = LDAPLookupUtils.getFirstAttributeValue(agentEntry,"uid"); + } catch (ObjectNotFoundException e) { + mAgentName = ""; + } + } + return mAgentName; + } + + public RolePath[] getRoles() + { + return Gateway.getLDAPLookup().getRoleManager().getRoles(this); + } + + public boolean hasRole(RolePath role) { + return Gateway.getLDAPLookup().getRoleManager().hasRole(this, role); + } + + public boolean hasRole(String role) { + try { + return hasRole(Gateway.getLDAPLookup().getRoleManager().getRolePath(role)); + } catch (ObjectNotFoundException ex) { + return false; + } + } + + public void setPassword(String passwd) + { + mPassword = passwd; + } + + public String getPassword() + { + return mPassword; + } + + @Override + public String dump() { + return super.dump()+ + "\n agentID="+ + mAgentName; + } + + static String generateUserPassword(String pass, String algo) throws NoSuchAlgorithmException { + MessageDigest sha = MessageDigest.getInstance(algo); + sha.reset(); + sha.update(pass.getBytes()); + byte hash[] = sha.digest(); + StringBuffer digest = new StringBuffer("{").append(algo).append("}"); + digest.append(Base64.encode(hash)); + return digest.toString(); + } + + @Override + public LDAPAttributeSet createAttributeSet() throws ObjectCannotBeUpdated + { + LDAPAttributeSet attrs = new LDAPAttributeSet(); + attrs.add(new LDAPAttribute("objectclass","cristalagent")); + attrs.add(new LDAPAttribute("intsyskey",Integer.toString(mSysKey))); + attrs.add(new LDAPAttribute("cn", getPath()[getPath().length-1])); + if (mIOR != null) + attrs.add(new LDAPAttribute("ior", Gateway.getORB().object_to_string(mIOR))); + + if (mAgentName!=null && mAgentName.length()>0) + attrs.add(new LDAPAttribute("uid",mAgentName)); + else + throw new ObjectCannotBeUpdated("Cannot create agent. No userId specified", ""); + + if (mPassword!=null && mPassword.length()>0) + try { + attrs.add(new LDAPAttribute("userPassword",generateUserPassword(mPassword, "SHA"))); + } catch (NoSuchAlgorithmException ex) { + throw new ObjectCannotBeUpdated("Cryptographic libraries for password hashing not found.", ""); + } + else + throw new ObjectCannotBeUpdated("Cannot create agent. No password given", ""); + + return attrs; + } + +} + diff --git a/src/main/java/com/c2kernel/lookup/DomainPath.java b/src/main/java/com/c2kernel/lookup/DomainPath.java new file mode 100644 index 0000000..ce849ce --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/DomainPath.java @@ -0,0 +1,158 @@ +/************************************************************************** + * DomainPath.java + * + * $Revision: 1.22 $ + * $Date: 2005/10/13 08:15:00 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lookup; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; + + +/** +* @version $Revision: 1.22 $ $Date: 2005/10/13 08:15:00 $ +* @author $Author: abranson $ +**/ +public class DomainPath extends Path +{ + private EntityPath target = null; + protected static String mTypeRoot; + +/* Very simple extension to Path. Only copies constructors and defines root */ + + public DomainPath() + { + super(Path.UNKNOWN); + } + + public DomainPath(short type) + { + super(); + mType = type; + } + + public DomainPath(String[] path) + { + super(path, Path.UNKNOWN); + } + + public DomainPath(String path) + { + super(path, Path.UNKNOWN); + } + + public DomainPath(String path, EntityPath entity) throws InvalidEntityPathException + { + super(path, Path.UNKNOWN); + setEntity(entity); + } + + public DomainPath(DomainPath parent, String child) { + super(parent, child); + } + + /* the root of domain paths is /domain + * clearly + */ + @Override + public String getRoot() { + return "domain"; + } + + public DomainPath getParent() { + if (mPath.length == 0) + return null; + + String[] parentPath = new String[mPath.length-1]; + System.arraycopy(mPath, 0, parentPath, 0, parentPath.length); + return new DomainPath(parentPath); + } + + public void setEntity(EntityPath newTarget) { + if (newTarget == null) { // clear + target = null; + mType = Path.CONTEXT; + return; + } + + target = newTarget; + mType = Path.ENTITY; + } + + @Override + public EntityPath getEntity() throws ObjectNotFoundException { + if (mType == UNKNOWN) { // must decide + checkType(); + } + + if (target == null) + throw new ObjectNotFoundException("Path is a context", ""); + return target; + } + + @Override + public short getType() { + if (mType == UNKNOWN) { // must decide + checkType(); + } + return mType; + } + + public void checkType() { + try { + setEntity(Gateway.getLDAPLookup().resolvePath(this)); + } catch (InvalidEntityPathException ex) { + Logger.error(ex); + mType = CONTEXT; + } catch (ObjectNotFoundException ex) { + mType = CONTEXT; + } + + } + + /** + * Retrieves the domkey of the path + * @return the last path component; + */ + public String getName() { + return mPath[mPath.length-1]; + } + + @Override + public int getSysKey() { + if (mType == UNKNOWN) { // must decide + checkType(); + } + + if (mType == ENTITY) { + return target.getSysKey(); + } + else return INVALID; + } + + @Override + public LDAPAttributeSet createAttributeSet() { + LDAPAttributeSet attrs = new LDAPAttributeSet(); + attrs.add(new LDAPAttribute("cn",getName())); + if (getType() == ENTITY) { + String objectclass_values[] = { "alias", "aliasObject" }; + attrs.add(new LDAPAttribute("objectclass",objectclass_values)); + attrs.add(new LDAPAttribute("aliasedObjectName",target.getFullDN())); + } + + else + { + attrs.add(new LDAPAttribute("objectclass","cristalcontext")); + } + return attrs; + } +} + diff --git a/src/main/java/com/c2kernel/lookup/EntityPath.java b/src/main/java/com/c2kernel/lookup/EntityPath.java new file mode 100644 index 0000000..4f9b771 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/EntityPath.java @@ -0,0 +1,175 @@ +/************************************************************************** + * EntityPath.java + * + * $Revision: 1.14 $ + * $Date: 2006/03/03 13:52:21 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lookup; + +import java.util.ArrayList; + +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.process.Gateway; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; + + +/** +* Extends Path to enforce SystemKey structure and support int form +* +* @version $Revision: 1.14 $ $Date: 2006/03/03 13:52:21 $ +* @author $Author: abranson $ +**/ +public class EntityPath extends Path +{ + // no of components in a syskey + public static final int elementNo = 3; + // no of digits in a syskey component + public static final int elementLen = 3; + // maximum possible int syskey + public static final int maxSysKey = (int)Math.pow(10, elementNo*elementLen)-1; + protected static String mTypeRoot; + /* + * From syskey int + * Note no EntityPath constructors allow setting of CONTEXT or ENTITY: + * The object decides that for itself from the number of components + */ + + public EntityPath(int syskey) throws InvalidEntityPathException { + super(); + setSysKey(syskey); + } + + /* + */ + public EntityPath() + { + super(); + } + + + /* + */ + public EntityPath(String[] path) throws InvalidEntityPathException + { + super(path, Path.CONTEXT); // dummy - it will get replaced in checkSysPath() + checkSysPath(); + } + + /* + */ + public EntityPath(String path) throws InvalidEntityPathException + { + super(path, Path.CONTEXT); + checkSysPath(); + } + + /* + */ + public EntityPath(EntityPath parent, String child) throws InvalidEntityPathException { + super(parent, child); + checkSysPath(); + } + + // EntityPaths root in /entity + @Override + public String getRoot() { + return "entity"; + } + + @Override + public EntityPath getEntity() throws ObjectNotFoundException { + return this; + } + + public byte[] getOID() { + if (mSysKey == Path.INVALID) return null; + return String.valueOf(mSysKey).getBytes(); + } + + /*************************************************************************/ + + /** Returns int form of syskey (if possible) + */ + @Override + public int getSysKey() { + if (mSysKey == Path.INVALID && mType == Path.ENTITY) + try { + if (mPath.length != elementNo) + throw new InvalidEntityPathException("Incorrect number of components for a system key"); + mSysKey = 0; + for (String keypart : mPath) { + if (keypart.length()!=elementLen+1) + throw new InvalidEntityPathException("Component '"+keypart+"' is not the correct size for a system key"); + for(int j=1; j= '0') && (c <='9')) + mSysKey = mSysKey*10 + c - '0'; + else + throw new InvalidEntityPathException("Component '"+keypart+"' contained a non-numeric char (excluding first char 'd')."); + + } + } + } catch (InvalidEntityPathException ex) { + mSysKey = Path.INVALID; + } + return mSysKey; + } + + /** Sets path from int syskey + */ + public void setSysKey(int sysKey) throws InvalidEntityPathException + { + if (sysKey < 0 || sysKey > maxSysKey) + throw new InvalidEntityPathException("System key "+sysKey+" out of range"); + String stringPath = Integer.toString(sysKey); + ArrayList newKey = new ArrayList(); + for (int i=0; i elementNo) + throw new InvalidEntityPathException("EntityPath cannot have more than "+elementNo+" components: "+toString()); + if (mPath.length == elementNo) + mType = Path.ENTITY; + else + mType = Path.CONTEXT; + } + + @Override + public LDAPAttributeSet createAttributeSet() throws ObjectCannotBeUpdated { + LDAPAttributeSet attrs = new LDAPAttributeSet(); + attrs.add(new LDAPAttribute("objectclass","cristalentity")); + attrs.add(new LDAPAttribute("intsyskey",Integer.toString(mSysKey))); + attrs.add(new LDAPAttribute("cn", getPath()[getPath().length-1])); + if (mIOR != null) + attrs.add(new LDAPAttribute("ior", Gateway.getORB().object_to_string(mIOR))); + return attrs; + } +} + diff --git a/src/main/java/com/c2kernel/lookup/InvalidAgentPathException.java b/src/main/java/com/c2kernel/lookup/InvalidAgentPathException.java new file mode 100644 index 0000000..be4d952 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/InvalidAgentPathException.java @@ -0,0 +1,13 @@ +package com.c2kernel.lookup; + +public class InvalidAgentPathException extends InvalidEntityPathException { + + public InvalidAgentPathException() { + super(); + } + + public InvalidAgentPathException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/c2kernel/lookup/InvalidEntityPathException.java b/src/main/java/com/c2kernel/lookup/InvalidEntityPathException.java new file mode 100644 index 0000000..27c754d --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/InvalidEntityPathException.java @@ -0,0 +1,13 @@ +package com.c2kernel.lookup; + +public class InvalidEntityPathException extends Exception { + + public InvalidEntityPathException() { + super(); + } + + public InvalidEntityPathException(String msg) { + super(msg); + } + +} diff --git a/src/main/java/com/c2kernel/lookup/LDAPLookup.java b/src/main/java/com/c2kernel/lookup/LDAPLookup.java new file mode 100644 index 0000000..39744ac --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPLookup.java @@ -0,0 +1,464 @@ +/* + * Directory Lookup Service * + * author: Florida Estrella +*/ + +package com.c2kernel.lookup; + +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.TraceableEntity; +import com.c2kernel.entity.agent.ActiveEntity; +import com.c2kernel.entity.proxy.EntityProxyManager; +import com.c2kernel.entity.proxy.ProxyMessage; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +import com.novell.ldap.LDAPAttributeSet; +import com.novell.ldap.LDAPConnection; +import com.novell.ldap.LDAPDN; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; +import com.novell.ldap.LDAPSearchConstraints; +import com.novell.ldap.LDAPSearchResults; + +/** + * The LDAPLookup object, statically accessible through the Gateway, manages + * the LDAP connection for the cristal process. It provides: + *
    + *
  • Authentication - returning an AgentProxy object if a user has logged in + *
  • System key generation - through the NextKeyManager + *
  • Agent and Role lookup/modification - through the RoleManager + *
  • + * @version $Revision: 1.113 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ + +public class LDAPLookup + +{ + private LDAPConnection mLDAPConn; + private final LDAPProperties mLDAPProps; + private final NextKeyManager mNextKeyManager; + private LDAPPropertyManager mPropManager; + private final LDAPRoleManager mRoleManager; + + + + /** + * Creates a new LDAPLookup manager with the properties supplied. + * This should be only done by the Gateway during initialisation. + * + * @param props The LDAP properties object that extracts LDAP connection properties from the global c2kprops + */ + public LDAPLookup(LDAPProperties props) throws LDAPException + { + Logger.msg(8,"LDAPLookup - initialising."); + + mLDAPProps = props; + + mLDAPConn = createConnection(mLDAPProps); + + Path.mGlobalPath=props.mGlobalPath; + Path.mRootPath=props.mRootPath; + Path.mLocalPath=props.mLocalPath; + + EntityPath.mTypeRoot = "cn=entity,"+props.mLocalPath; + DomainPath.mTypeRoot = "cn=domain,"+props.mLocalPath; + + mNextKeyManager = new NextKeyManager(this, "cn=last,"+EntityPath.mTypeRoot); + Logger.debug("LDAP.useOldProps="+Gateway.getProperty("LDAP.useOldProps", "false")); + if (Gateway.getProperty("LDAP.useOldProps", "false").equals("true")) { + Logger.debug("Using Kernel 2.1 LDAP Property Format"); + mPropManager = new LegacyLDAPPropertyManager(this); + } + else { + Logger.debug("Using Kernel 2.2 LDAP Property Format"); + mPropManager = new LDAPPropertyManager(this); + } + mRoleManager = new LDAPRoleManager(this, "cn=agent,"+DomainPath.mTypeRoot, EntityPath.mTypeRoot); + + } + + /** + * Utility method to connect to an LDAP server + * @param lp LDAP properties to connect with + * @return a novell LDAPConnection object + * @throws LDAPException when the connection was unsuccessful + */ + public static LDAPConnection createConnection(LDAPProperties lp) throws LDAPException { + LDAPConnection ld = new LDAPConnection(); + + Logger.msg(3, "LDAPLookup - connecting to " + lp.mHost); + ld.connect(lp.mHost, Integer.valueOf(lp.mPort).intValue()); + + Logger.msg(3, "LDAPLookup - authenticating user:" + lp.mUser); + ld.bind( LDAPConnection.LDAP_V3, lp.mUser, + String.valueOf(lp.mPassword).getBytes()); + + Logger.msg(3, "LDAPLookup - authentication successful"); + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setMaxResults(0); + ld.setConstraints(searchCons); + + return ld; + } + + /** + * Gets the entity key generator, used to get a unique system key for new entities. + * @return the global NextKeyManager + */ + public NextKeyManager getNextKeyManager() + { + return mNextKeyManager; + } + + /** + * Gets the property manager, that is used to read and write cristal properties to the LDAP store. + * @return Returns the global LDAPPropertyManager. + */ + public LDAPPropertyManager getPropManager() { + return mPropManager; + } + /** + * Gets the role manager, that is used to add and remove roles and agents. + * @return Returns the mRoleManager. + */ + public LDAPRoleManager getRoleManager() { + return mRoleManager; + } + + /** + * Returns the current LDAP connection, and attempts to reconnect if it has been closed. + * @return + */ + protected LDAPConnection getConnection() + { + if (!mLDAPConn.isConnected()) { + Logger.warning("LDAPLookup - lost connection to LDAP server. Attempting to reconnect."); + try { + mLDAPConn = createConnection(mLDAPProps); + } catch (LDAPException ex) { } + } + return mLDAPConn; + } + + /** + * Disconnects the connection with the LDAP server during shutdown + */ + public void disconnect() { + Logger.msg(1, "LDAP Lookup: Shutting down LDAP connection."); + if (mLDAPConn != null) { + try { + mLDAPConn.disconnect(); + } catch (LDAPException e) { + Logger.error(e); + } + mLDAPConn = null; + } + } + + /** + * Attempts to resolve the CORBA object for a Path, either directly or through an alias. + * @param path the path to resolve + * @return the CORBA object + * @throws ObjectNotFoundException When the path does not exist + */ + public org.omg.CORBA.Object getIOR(Path path) + throws ObjectNotFoundException + { + return resolveObject(path.getFullDN()); + } + + /** + * Attempts to resolve the CORBA object from the IOR attribute of a DN, either directly or through an alias + * @param dn The String dn + * @throws ObjectNotFoundException when the dn or aliased dn does not exist + */ + private org.omg.CORBA.Object resolveObject(String dn) + throws ObjectNotFoundException + { + Logger.msg(8,"LDAPLookup.resolveObject("+dn+")"); + LDAPEntry anEntry = LDAPLookupUtils.getEntry(getConnection(),dn,LDAPSearchConstraints.DEREF_NEVER); + if (anEntry != null) + { + String iorString; + try { + iorString = LDAPLookupUtils.getFirstAttributeValue(anEntry, "ior"); + org.omg.CORBA.Object ior=Gateway.getORB().string_to_object(iorString); + if (ior!=null) + return ior; + else + throw new ObjectNotFoundException("LDAPLookup.resolveObject() - " + dn + " has no IOR", ""); + } catch (ObjectNotFoundException ex) { + return resolveObject(LDAPLookupUtils.getFirstAttributeValue(anEntry,"aliasedObjectName")); + } + } + else + throw new ObjectNotFoundException("LDAPLookup.resolveObject() LDAP node " + dn + " is not in LDAP or has no IOR.", ""); + } + + /** + * + * @param domPath + * @return + * @throws InvalidEntityPathException + * @throws ObjectNotFoundException + */ + protected EntityPath resolvePath(DomainPath domPath) + throws InvalidEntityPathException, ObjectNotFoundException { + EntityPath referencedPath = null; + LDAPEntry domEntry = LDAPLookupUtils.getEntry(getConnection(), domPath + .getFullDN(), LDAPSearchConstraints.DEREF_ALWAYS); + String entityKey = LDAPLookupUtils.getFirstAttributeValue(domEntry, + "intsyskey"); + Logger.msg(7, "DomainPath " + domPath + " is a reference to " + + entityKey); + String objClass = LDAPLookupUtils.getFirstAttributeValue(domEntry, + "objectClass"); + if (objClass.equals("cristalagent")) + referencedPath = new AgentPath(Integer.parseInt(entityKey)); + else + referencedPath = new EntityPath(Integer.parseInt(entityKey)); + + return referencedPath; + } + + + public LDAPEntry add(Path path) + throws ObjectCannotBeUpdated, ObjectAlreadyExistsException + { + try { + checkLDAPContext(path); + LDAPAttributeSet attrSet = path.createAttributeSet(); + LDAPEntry newEntry = new LDAPEntry(path.getFullDN(),attrSet); + LDAPLookupUtils.addEntry(getConnection(),newEntry); + if (path instanceof DomainPath) + EntityProxyManager.sendProxyEvent(new ProxyMessage(ProxyMessage.NA, path.toString(), ProxyMessage.ADDED)); + return newEntry; + } catch (LDAPException ex) { + if (ex.getResultCode() == LDAPException.ENTRY_ALREADY_EXISTS) + throw new ObjectAlreadyExistsException(ex.getLDAPErrorMessage(), ""); + else + throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage(), ""); + } + } + + //deletes a node + //throws LDAPexception if node cannot be deleted (eg node is not a leaf) + public void delete(Path path) throws ObjectCannotBeUpdated + { + try { + LDAPLookupUtils.delete(getConnection(),path.getDN()+Path.mLocalPath); + } catch (LDAPException ex) { + throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage(), ""); + } + if (path instanceof DomainPath) { + EntityProxyManager.sendProxyEvent(new ProxyMessage(ProxyMessage.NA, path.toString(), ProxyMessage.DELETED)); + } + } + + //change specs, add boolean alias leaf context + protected void checkLDAPContext(Path path) + { + String dn = path.getFullDN(); + if (!LDAPLookupUtils.exists(getConnection(),dn)) + { + String listDN[] = path.getPath(); + String name = "cn="+ path.getRoot() + "," + Path.mLocalPath; + int i=0; + while (i getEntityClass(Path path) throws ObjectNotFoundException { + String[] attr = { LDAPConnection.ALL_USER_ATTRS }; + try { + LDAPEntry anEntry=getConnection().read(path.getDN()+Path.mLocalPath,attr); + String type = LDAPLookupUtils.getFirstAttributeValue(anEntry, "objectClass"); + if (type.equals("cristalentity")) + return TraceableEntity.class; + else if (type.equals("cristalagent")) + return ActiveEntity.class; + else + throw new ObjectNotFoundException("Not an entity", ""); + + } catch (LDAPException ex) { + if (ex.getResultCode() == LDAPException.NO_SUCH_OBJECT) + throw new ObjectNotFoundException("Entity does not exist", ""); + Logger.error(ex); + throw new ObjectNotFoundException("Error getting entity class", ""); + } + } + + /** converts an LDAPentry to a Path object + * Note that the search producing the entry should have retrieved the attrs + * 'ior' and 'uniquemember' + * @throws ObjectNotFoundException + * @throws ObjectNotFoundException + */ + protected Path nodeToPath(LDAPEntry entry) throws InvalidEntityPathException, ObjectNotFoundException + { + String dn = entry.getDN(); + + // extract syskey + int entityKey = -1; + try { + String entityKeyStr = LDAPLookupUtils.getFirstAttributeValue(entry,"intsyskey"); + entityKey = Integer.parseInt(entityKeyStr); + } catch (Exception e) { } + + // extract IOR + org.omg.CORBA.Object ior = null; + try { + String stringIOR = LDAPLookupUtils.getFirstAttributeValue(entry,"ior"); + ior = Gateway.getORB().string_to_object(stringIOR); + } catch (ObjectNotFoundException e2) { } + + /* Find the right path class */ + Path thisPath; + if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalagent")) + { //cristalagent + String agentID = LDAPLookupUtils.getFirstAttributeValue(entry,"uid"); + thisPath = new AgentPath(entityKey, agentID); + } + + else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalrole")) + { //cristalrole + thisPath = new RolePath(LDAPDN.explodeDN(dn,true)[0], + LDAPLookupUtils.getFirstAttributeValue(entry, "jobList").equals("TRUE")); + } + else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","aliasObject") || + (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(DomainPath.mTypeRoot))) + { + DomainPath domainPath = new DomainPath(); + domainPath.setDN(dn); + thisPath = domainPath; + } + else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalentity") || + (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(EntityPath.mTypeRoot))) + { + if(dn.endsWith(EntityPath.mTypeRoot)) { + EntityPath entityPath; + if (entityKey != -1) + entityPath = new EntityPath(entityKey); + else { + entityPath = new EntityPath(); + entityPath.setDN(dn); + } + thisPath = entityPath; + } + else + throw new ObjectNotFoundException("Entity found outside entity tree"); + } + else + { + throw new ObjectNotFoundException("Unrecognised LDAP entry. Not a cristal entry"); + } + + //set IOR if we have one + if (ior!=null) thisPath.setIOR(ior); + return thisPath; + } +} diff --git a/src/main/java/com/c2kernel/lookup/LDAPLookupUtils.java b/src/main/java/com/c2kernel/lookup/LDAPLookupUtils.java new file mode 100644 index 0000000..8df365b --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPLookupUtils.java @@ -0,0 +1,317 @@ +/* + * Lookup helper class. + */ + +package com.c2kernel.lookup; + +//import netscape.ldap.*; +//import netscape.ldap.util.*; +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; +import com.novell.ldap.LDAPConnection; +import com.novell.ldap.LDAPDN; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; +import com.novell.ldap.LDAPModification; +import com.novell.ldap.LDAPSearchConstraints; +import com.novell.ldap.LDAPSearchResults; + +/** + * @version $Revision: 1.74 $ $Date: 2006/03/03 13:52:21 $ + * @author $Author: abranson $ + */ + +final public class LDAPLookupUtils +{ + static public LDAPEntry getEntry(LDAPConnection ld, String dn,int dereference) + throws ObjectNotFoundException + { + try { + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(0); + searchCons.setDereference(dereference); + LDAPEntry thisEntry = ld.read(dn,searchCons); + if (thisEntry != null) return thisEntry; + } catch (LDAPException ex) { + throw new ObjectNotFoundException("LDAP Exception: "+ex.getMessage(), ""); + } + throw new ObjectNotFoundException(dn+" does not exist", ""); + + } + + //Given a DN, return an LDAP Entry + static public LDAPEntry getEntry(LDAPConnection ld, String dn) + throws ObjectNotFoundException + { + return getEntry(ld, dn, LDAPSearchConstraints.DEREF_NEVER); + } + + static public String getFirstAttributeValue(LDAPEntry anEntry, String attribute) throws ObjectNotFoundException + { + LDAPAttribute attr = anEntry.getAttribute(attribute); + if (attr==null) + throw new ObjectNotFoundException("No attributes named '"+attribute+"'", ""); + return (String)attr.getStringValues().nextElement(); + } + + static public String[] getAllAttributeValues(LDAPEntry anEntry, String attribute) throws ObjectNotFoundException + { + LDAPAttribute attr = anEntry.getAttribute(attribute); + if (attr!=null) + return attr.getStringValueArray(); + + throw new ObjectNotFoundException("No attributes named '"+attribute+"'", ""); + + } + + static public boolean existsAttributeValue(LDAPEntry anEntry, String attribute, String value) + { + LDAPAttribute attr = anEntry.getAttribute(attribute); + if (attr!=null) + { + String[] attrValues = new String[attr.size()]; + attrValues = attr.getStringValueArray(); + for (int i=0;i', ';', '/'}; + String escapedStr = new String(name); + + //Backslash is both a Java and an LDAP escape character, so escape it first + escapedStr = escapedStr.replaceAll("\\\\","\\\\"); + + //Positional characters - see RFC 2253 + escapedStr = escapedStr.replaceAll("^#","\\\\#"); + escapedStr = escapedStr.replaceAll("^ | $","\\\\ "); + + for (char element : META_CHARS) { + escapedStr = escapedStr.replaceAll("\\"+element,"\\\\" + element); + } + Logger.msg(6, "LDAP DN "+name+" escaped to "+escapedStr); + return escapedStr; + } + + public static String escapeSearchFilter (String filter) { + //From RFC 2254 + String escapedStr = new String(filter); + + escapedStr = escapedStr.replaceAll("\\\\","\\\\5c"); + //escapedStr = escapedStr.replaceAll("\\*","\\\\2a"); // we need stars for searching + escapedStr = escapedStr.replaceAll("\\(","\\\\28"); + escapedStr = escapedStr.replaceAll("\\)","\\\\29"); + Logger.msg(6, "LDAP Search Filter "+filter+" escaped to "+escapedStr); + return escapedStr; + } +} diff --git a/src/main/java/com/c2kernel/lookup/LDAPPathSet.java b/src/main/java/com/c2kernel/lookup/LDAPPathSet.java new file mode 100644 index 0000000..d3cf7d9 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPPathSet.java @@ -0,0 +1,72 @@ +package com.c2kernel.lookup; + +import java.util.Enumeration; + +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; +import com.novell.ldap.LDAPSearchResults; + +/************************************************************************** + * + * $Revision: 1.6 $ + * $Date: 2005/12/01 14:23:14 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + + +public class LDAPPathSet implements Enumeration { + LDAPSearchResults results; + LDAPEntry nextEntry; + + public LDAPPathSet() { // empty + results = null; + } + + public LDAPPathSet(LDAPSearchResults results) { + this.results = results; + } + + @Override + public boolean hasMoreElements() { + if (results == null) return false; + if (nextEntry != null) return true; + if (results.hasMore()) + try { + nextEntry = results.next(); + return true; + } catch (LDAPException ex) { + if (ex.getResultCode()!=32) {// no results + Logger.error(ex); + Logger.error("Error loading LDAP result set: "+ex.getMessage()); + } + } + return false; + } + + @Override + public Path nextElement() { + if (results == null) return null; + try { + if (nextEntry == null) + nextEntry = results.next(); + Path nextPath = Gateway.getLDAPLookup().nodeToPath(nextEntry); + nextEntry = null; + return nextPath; + } catch (Exception ex) { + Logger.error("Error loading next path"); + Logger.error(ex); + nextEntry = null; + if (hasMoreElements()) { + Logger.error("Skipping to next entry"); + return nextElement(); + } + else + return null; + } + } +} diff --git a/src/main/java/com/c2kernel/lookup/LDAPProperties.java b/src/main/java/com/c2kernel/lookup/LDAPProperties.java new file mode 100644 index 0000000..e884a54 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPProperties.java @@ -0,0 +1,38 @@ +/* + * Directory Lookup Service +*/ + +package com.c2kernel.lookup; + +import com.c2kernel.process.Gateway; + +/** + * @version $Revision: 1.16 $ $Date: 2005/10/12 12:51:54 $ + * @author $Author: abranson $ + */ +public class LDAPProperties +{ + public String mGlobalPath = null; //o=cern.ch + public String mRootPath = null; //cn=cristal2 + public String mLocalPath = null; //cn=lab27 + public String mPort = null; + public String mHost = null; + public String mUser = null; + public String mPassword = null; + + public LDAPProperties() + { + mGlobalPath = Gateway.getProperty( "LDAP.GlobalPath" ); + mRootPath = Gateway.getProperty( "LDAP.RootPath" ); + mLocalPath = Gateway.getProperty( "LDAP.LocalPath" ); + mPort = Gateway.getProperty( "LDAP.port" ); + mHost = Gateway.getProperty( "LDAP.host" ); + mUser = Gateway.getProperty( "LDAP.user" ); + mPassword = Gateway.getProperty( "LDAP.password" ); + + mRootPath += "," + mGlobalPath; + mLocalPath += "," + mRootPath; + + } +} + diff --git a/src/main/java/com/c2kernel/lookup/LDAPPropertyManager.java b/src/main/java/com/c2kernel/lookup/LDAPPropertyManager.java new file mode 100644 index 0000000..57ed17d --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPPropertyManager.java @@ -0,0 +1,118 @@ +package com.c2kernel.lookup; + +import java.util.ArrayList; +import java.util.Enumeration; + +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPEntry; + +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2006/03/03 13:52:21 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +public class LDAPPropertyManager { + /** + * + */ + protected LDAPLookup ldap; + + public LDAPPropertyManager(LDAPLookup ldap) { + super(); + this.ldap = ldap; + } + + /** + * @param thisEntity - EntityPath of the subject entity + * @return + * @throws ObjectNotFoundException + */ + public boolean hasProperties(EntityPath thisEntity) throws ObjectNotFoundException { + LDAPEntry entityEntry = LDAPLookupUtils.getEntry(ldap.getConnection(), thisEntity.getFullDN()); + return entityEntry.getAttribute("cristalprop") != null; + } + + /** + * @param thisEntity - EntityPath of the subject entity + * @return array of Property + * @throws ObjectNotFoundException + */ + public String[] getPropertyNames(EntityPath thisEntity) throws ObjectNotFoundException { + LDAPEntry entityEntry = LDAPLookupUtils.getEntry(ldap.getConnection(), thisEntity.getFullDN()); + ArrayList propbag = new ArrayList(); + LDAPAttribute props = entityEntry.getAttribute("cristalprop"); + for (Enumeration e = props.getStringValues(); e.hasMoreElements();) { + String thisProp = (String)e.nextElement(); + propbag.add(thisProp.substring(0, thisProp.indexOf(':'))); + } + + String[] retArr = new String[props.size()]; + return propbag.toArray(retArr); + } + + /** + * @param thisEntity - EntityPath of the subject entity + * @param propName - the name of the property to retrieve + * @return String the property value + * @throws ObjectNotFoundException + */ + public String getPropertyValue(EntityPath thisEntity, String name) throws ObjectNotFoundException { + LDAPEntry entityEntry = LDAPLookupUtils.getEntry(ldap.getConnection(), thisEntity.getFullDN()); + return getPropertyAttr(entityEntry, name); + } + + /** + * @param thisEntity - EntityPath of the subject entity + * @param name - the property name to delete + * @throws ObjectNotFoundException + * @throws ObjectCannotBeUpdated + */ + public void deleteProperty(EntityPath thisEntity, String name) throws ObjectNotFoundException, ObjectCannotBeUpdated { + LDAPEntry entityEntry = LDAPLookupUtils.getEntry(ldap.getConnection(), thisEntity.getFullDN()); + String propVal = getPropertyAttr(entityEntry, name); + Logger.msg(6, "LDAPLookupUtils.deleteProperty("+name+") - Deleting property"); + LDAPLookupUtils.removeAttributeValue(ldap.getConnection(), entityEntry, "cristalprop", name+":"+propVal); + } + + /** + * @param thisEntity - EntityPath of the subject entity + * @param prop - the property to store + * @throws ObjectNotFoundException + * @throws ObjectCannotBeUpdated + */ + public void setProperty(EntityPath thisEntity, Property prop) throws ObjectNotFoundException, ObjectCannotBeUpdated { + LDAPEntry entityEntry = LDAPLookupUtils.getEntry(ldap.getConnection(), thisEntity.getFullDN()); + try { + String propVal = getPropertyAttr(entityEntry, prop.getName()); + Logger.msg(6, "LDAPLookupUtils.setProperty("+prop.getName()+") - Removing old value '"+propVal+"'"); + LDAPLookupUtils.removeAttributeValue(ldap.getConnection(), entityEntry, "cristalprop", prop.getName()+":"+propVal); + } catch (ObjectNotFoundException ex) { + Logger.msg(6, "LDAPLookupUtils.setProperty("+prop.getName()+") - creating new property."); + } + Logger.msg(6, "LDAPLookupUtils.setProperty("+prop.getName()+") - setting to '"+prop.getValue()+"'"); + LDAPLookupUtils.addAttributeValue(ldap.getConnection(), entityEntry, "cristalprop", prop.getName()+":"+prop.getValue()); + } + + private static String getPropertyAttr(LDAPEntry myEntry, String propName) throws ObjectNotFoundException { + // delete existing props + LDAPAttribute props = myEntry.getAttribute("cristalprop"); + if (props == null) + throw new ObjectNotFoundException("Property "+propName+" does not exist", ""); + String propPrefix = propName+":"; + for (Enumeration e = props.getStringValues(); e.hasMoreElements();) { + String val = (String)e.nextElement(); + if (val.toLowerCase().startsWith(propPrefix.toLowerCase())) + return val.substring(propPrefix.length()); + } + throw new ObjectNotFoundException("Property "+propName+" does not exist", ""); + } + +} diff --git a/src/main/java/com/c2kernel/lookup/LDAPRoleManager.java b/src/main/java/com/c2kernel/lookup/LDAPRoleManager.java new file mode 100644 index 0000000..0536d6c --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LDAPRoleManager.java @@ -0,0 +1,199 @@ +package com.c2kernel.lookup; + +import java.util.ArrayList; +import java.util.Enumeration; + +import com.c2kernel.common.ObjectAlreadyExistsException; +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPConnection; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; +import com.novell.ldap.LDAPSearchConstraints; + +/************************************************************************** + * + * $Revision: 1.1 $ + * $Date: 2005/04/26 06:48:12 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +// public static final String codeRevision = "$Revision: 1.1 $ $Date: 2005/04/26 06:48:12 $ $Author: abranson $"; +public class LDAPRoleManager { + + /** + * + */ + LDAPLookup mLdap; + private final String mRolePath; + private final String mEntityPath; + + public LDAPRoleManager(LDAPLookup ldap, String rolePath, String entityPath) { + super(); + this.mLdap = ldap; + this.mRolePath = rolePath; + this.mEntityPath = entityPath; + } + + //NOTE: A role must have at LEAST 1 userDN, cannot be empty... + //Creates a cristalRole + //CristalRole is-a specialized CristalContext which contains multi-valued uniqueMember attribute pointing to cristalagents + public RolePath createRole(String roleName, boolean jobList) + throws ObjectAlreadyExistsException, ObjectCannotBeUpdated + { + + // create the role + RolePath rolePath = new RolePath(roleName, jobList); + String roleDN = rolePath.getFullDN(); + LDAPEntry roleNode; + try + { + roleNode = LDAPLookupUtils.getEntry(mLdap.getConnection(), rolePath.getFullDN()); + throw new ObjectAlreadyExistsException(); + } catch (ObjectNotFoundException ex) { } + + //create CristalRole if it does not exist + roleNode = new LDAPEntry(roleDN, rolePath.createAttributeSet()); + try { + LDAPLookupUtils.addEntry(mLdap.getConnection(),roleNode); + } catch (LDAPException e) { + throw new ObjectCannotBeUpdated(e.getLDAPErrorMessage(), ""); + } + return rolePath; + + + } + public void deleteRole(RolePath role) throws ObjectNotFoundException, ObjectCannotBeUpdated { + try { + LDAPLookupUtils.delete(mLdap.getConnection(), role.getFullDN()); + } catch (LDAPException ex) { + throw new ObjectCannotBeUpdated("Could not remove role"); + } + } + + protected void addRole(AgentPath agent, RolePath role) + throws ObjectCannotBeUpdated, ObjectNotFoundException + { + LDAPEntry roleEntry = LDAPLookupUtils.getEntry(mLdap.getConnection(), role.getFullDN()); + //add memberDN to uniqueMember if it is not yet a member + if (!LDAPLookupUtils.existsAttributeValue(roleEntry, "uniqueMember", agent.getFullDN())) + LDAPLookupUtils.addAttributeValue(mLdap.getConnection(), roleEntry, "uniqueMember", agent.getFullDN()); + else + throw new ObjectCannotBeUpdated("Agent " + agent.getAgentName() + " already has role " + role.getName()); + } + + protected void removeRole(AgentPath agent, RolePath role) + throws ObjectCannotBeUpdated, ObjectNotFoundException + { + LDAPEntry roleEntry = LDAPLookupUtils.getEntry(mLdap.getConnection(), role.getFullDN()); + if (LDAPLookupUtils.existsAttributeValue(roleEntry, "uniqueMember", agent.getFullDN())) + LDAPLookupUtils.removeAttributeValue(mLdap.getConnection(), roleEntry, "uniqueMember", agent.getFullDN()); + else + throw new ObjectCannotBeUpdated("Agent did not have that role"); + } + + protected boolean hasRole(AgentPath agent, RolePath role) { + String filter = "(&(objectclass=cristalrole)(uniqueMember="+agent.getFullDN()+")(cn="+role.getName()+"))"; + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(0); + searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER ); + return mLdap.search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons).hasMoreElements(); + } + + protected AgentPath[] getAgents(RolePath role) + throws ObjectNotFoundException + { + //get the roleDN entry, and its uniqueMember entry pointing to + LDAPEntry roleEntry; + try { + roleEntry = LDAPLookupUtils.getEntry(mLdap.getConnection(), role.getFullDN()); + } catch (ObjectNotFoundException e) { + throw new ObjectNotFoundException("Role does not exist", ""); + } + + String[] res = LDAPLookupUtils.getAllAttributeValues(roleEntry,"uniqueMember"); + ArrayList agents = new ArrayList(); + for (String userDN : res) { + try { + LDAPEntry userEntry = LDAPLookupUtils.getEntry(mLdap.getConnection(), userDN); + AgentPath path = (AgentPath)mLdap.nodeToPath(userEntry); + agents.add(path); + } catch (ObjectNotFoundException ex) { + Logger.error("Agent "+userDN+" does not exist"); + } catch (InvalidEntityPathException ex) { + Logger.error("Agent "+userDN+" is not a valid entity"); + } + } + AgentPath[] usersList = new AgentPath[0]; + usersList = agents.toArray(usersList); + return usersList; + } + + //returns the role/s of a user + protected RolePath[] getRoles(AgentPath agentPath) + { + //search the mDomainPath tree uniqueMember=userDN + //filter = objectclass=cristalrole AND uniqueMember=userDN + String filter = "(&(objectclass=cristalrole)(uniqueMember="+agentPath.getFullDN()+"))"; + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(0); + searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER ); + Enumeration roles = mLdap.search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons); + ArrayList roleList = new ArrayList(); + + while(roles.hasMoreElements()) + { + RolePath path = (RolePath) roles.nextElement(); + roleList.add(path); + } + RolePath[] roleArr = new RolePath[roleList.size()]; + roleArr = roleList.toArray(roleArr); + return roleArr; + } + + /** + * Utility for looking up a login name + * + * @param ld + * @param agentName + * @param baseDN + * @return + * @throws ObjectNotFoundException + */ + public AgentPath getAgentPath(String agentName) throws ObjectNotFoundException + { + //search to get the userDN equivalent of the userID + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(0); + searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER ); + String filter = "(&(objectclass=cristalagent)(uid="+agentName+"))"; + Enumeration res = mLdap.search(mEntityPath,LDAPConnection.SCOPE_SUB,filter,searchCons); + if (!res.hasMoreElements()) + throw new ObjectNotFoundException("Agent not found"); + Path result = res.nextElement(); + if (result instanceof AgentPath) + return (AgentPath)result; + else + throw new ObjectNotFoundException("Entry was not an Agent"); + } + + public RolePath getRolePath(String roleName) throws ObjectNotFoundException + { + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(0); + searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER ); + String filter = "(&(objectclass=cristalrole)(cn="+roleName+"))"; + Enumeration res = mLdap.search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons); + if (!res.hasMoreElements()) + throw new ObjectNotFoundException("Role not found"); + Path result = res.nextElement(); + if (result instanceof RolePath) + return (RolePath)result; + else + throw new ObjectNotFoundException("Entry was not a Role"); + } + +} diff --git a/src/main/java/com/c2kernel/lookup/LegacyLDAPPropertyManager.java b/src/main/java/com/c2kernel/lookup/LegacyLDAPPropertyManager.java new file mode 100644 index 0000000..638c694 --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/LegacyLDAPPropertyManager.java @@ -0,0 +1,75 @@ +package com.c2kernel.lookup; + +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; +import com.novell.ldap.LDAPDN; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; + +public class LegacyLDAPPropertyManager extends LDAPPropertyManager { + + public LegacyLDAPPropertyManager(LDAPLookup ldap) { + super(ldap); + } + + @Override + public void deleteProperty(EntityPath thisEntity, String name) throws ObjectNotFoundException, ObjectCannotBeUpdated { + try { + LDAPLookupUtils.delete(ldap.getConnection(), "cn="+name+","+thisEntity.getFullDN()); + } catch (LDAPException ex) { + Logger.error("Error deleting prop "+name+" from "+thisEntity.getSysKey()); + Logger.error(ex); + } + } + + @Override + public String[] getPropertyNames(EntityPath thisEntity) throws ObjectNotFoundException { + String props[]= LDAPLookupUtils.getChildrenDNs(ldap.getConnection(), thisEntity.getFullDN(), "objectclass=cristalproperty"); + String names[] = new String[props.length]; + for (int i=0; i newPath = new ArrayList(); + StringTokenizer tok = new StringTokenizer(path, delim); + if (tok.hasMoreTokens()) { + String first = tok.nextToken(); + if (!first.equals(getRoot())) + newPath.add(first); + while (tok.hasMoreTokens()) + newPath.add(tok.nextToken()); + } + + mPath = (newPath.toArray(mPath)); + mStringPath = null; + mDN = null; + mSysKey = INVALID; + } + + // lookup sets the IOR + public void setIOR(org.omg.CORBA.Object IOR) { + mIOR = IOR; + if (IOR == null) mType = Path.CONTEXT; + else mType = Path.ENTITY; + } + + /* clone another path object + */ + public void setPath(Path path) + { + mStringPath = null; + mDN = null; + mPath = (path.getPath().clone()); + mSysKey = INVALID; + } + + /* LDAP dn e.g. cn=6L,cn=Barrel,cn=Crystal,cn=Product,cn=domain, + * system/domain node PRESENT + * trailing comma + */ + public void setDN(String dn) + { + // strip off root path components + String root = "cn="+getRoot()+","; + if (dn.endsWith(mLocalPath)) + dn = dn.substring(0, dn.lastIndexOf(mLocalPath)); + + if (dn.endsWith(root)) + dn = dn.substring(0, dn.lastIndexOf(root)); + + ArrayList newPath = new ArrayList(); + StringTokenizer tok = new StringTokenizer(dn, ","); + while (tok.hasMoreTokens()) { + String nextPath = tok.nextToken(); + if (nextPath.indexOf("cn=") == 0) + newPath.add(0, nextPath.substring(3)); + else + break; + } + mPath = (newPath.toArray(mPath)); + mSysKey = INVALID; + mStringPath = null; + mDN = dn+root; + } + + /*************************************************************************/ + + /* + * Getter Methods + */ + + // root is defined as 'domain', 'entity' or 'system' in subclasses + public abstract String getRoot(); + + public String[] getPath() + { + return mPath; + } + + public String getString() + { + if (mStringPath == null) { + StringBuffer stringPathBuffer = new StringBuffer("/").append(getRoot()); + for (String element : mPath) + stringPathBuffer.append(delim).append(element); + mStringPath = stringPathBuffer.toString(); + } + return mStringPath; + } + + public String getDN() { + if (mDN == null) { + StringBuffer dnBuffer = new StringBuffer(); + for (int i=mPath.length-1; i>=0; i--) + dnBuffer.append("cn=").append(mPath[i]).append(","); + dnBuffer.append("cn="+getRoot()+","); + mDN = dnBuffer.toString(); + } + return mDN; + } + + public String getFullDN() { + return getDN()+mLocalPath; + } + + public boolean exists() { + return Gateway.getLDAPLookup().exists(this); + } + + /** Queries the lookup for the IOR + */ + + public org.omg.CORBA.Object getIOR() { + org.omg.CORBA.Object newIOR = null; + if (mIOR==null) { // if not cached try to resolve + LDAPLookup myLookup = Gateway.getLDAPLookup(); + try { + newIOR = myLookup.getIOR(this); + } catch (ObjectNotFoundException ex) { + } + setIOR(newIOR); + } + return mIOR; + } + + @Override + public String toString() { + return getString(); + } + + public short getType() { + return mType; + } + + public int getSysKey() { + return mSysKey; + } + + public Enumeration getChildren() { + String filter = "objectclass=*"; + LDAPSearchConstraints searchCons = new LDAPSearchConstraints(); + searchCons.setBatchSize(10); + searchCons.setDereference(LDAPSearchConstraints.DEREF_FINDING ); + return Gateway.getLDAPLookup().search(getFullDN(), LDAPConnection.SCOPE_ONE,filter,searchCons); + } + + public Path find(String name) throws ObjectNotFoundException { + Enumeration e = Gateway.getLDAPLookup().search(this, name); + if (e.hasMoreElements()) { + Path thisPath = e.nextElement(); + if (e.hasMoreElements()) + throw new ObjectNotFoundException("More than one match for "+name, ""); + return thisPath; + } + throw new ObjectNotFoundException("No match for "+name, ""); + } + + public abstract EntityPath getEntity() throws ObjectNotFoundException; + + public abstract LDAPAttributeSet createAttributeSet() throws ObjectCannotBeUpdated; + + @Override + public boolean equals( Object path ) + { + return toString().equals(path.toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + public String dump() { + StringBuffer comp = new StringBuffer("Components: { "); + for (String element : mPath) + comp.append("'").append(element).append("' "); + return "Path - dump(): "+comp.toString()+"}\n dn="+getDN()+"\n string="+toString()+"\n int="+getSysKey()+"\n type="+mType; + } +} + diff --git a/src/main/java/com/c2kernel/lookup/RolePath.java b/src/main/java/com/c2kernel/lookup/RolePath.java new file mode 100644 index 0000000..e6593ea --- /dev/null +++ b/src/main/java/com/c2kernel/lookup/RolePath.java @@ -0,0 +1,121 @@ +/************************************************************************** + * DomainPath.java + * + * $Revision: 1.7 $ + * $Date: 2005/04/26 06:48:12 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.lookup; + +import java.util.Enumeration; +import java.util.Vector; + +import com.c2kernel.common.ObjectCannotBeUpdated; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; + + + +/** +* @version $Revision: 1.7 $ $Date: 2005/04/26 06:48:12 $ +* @author $Author: abranson $ +**/ +public class RolePath extends DomainPath +{ + /** + * + */ + + private boolean hasJobList = false; + + public RolePath(String roleName) { + super(new DomainPath("agent"), roleName); + } + + public RolePath(String roleName, boolean jobList) { + this(roleName); + hasJobList = jobList; + } + + /** + * @return Returns the hasJobList. + */ + public boolean hasJobList() { + return hasJobList; + } + /** + * @param hasJobList The hasJobList to set. + */ + public void setHasJobList(boolean hasJobList) { + this.hasJobList = hasJobList; + } + + + @Override + public void checkType() { + mType = CONTEXT; + } + + @Override + public Enumeration getChildren() { + AgentPath[] agents = getAgentsWithRole(); + Vector children = new Vector(agents.length); + for (int i = 0; i < agents.length; i++) + children.add(i, agents[i]); + return children.elements(); + } + + public AgentPath[] getAgentsWithRole() { + try { + return Gateway.getLDAPLookup().getRoleManager().getAgents(this); + } catch (ObjectNotFoundException ex) { + Logger.error("Cannot retrieve agent list. Role "+getName()+" does not exist in LDAP"); + return new AgentPath[0]; + } + } + + public void addAgent(AgentPath agent) throws ObjectCannotBeUpdated, ObjectNotFoundException { + Gateway.getLDAPLookup().getRoleManager().addRole(agent, this); + } + + public void removeAgent(AgentPath agent) throws ObjectCannotBeUpdated, ObjectNotFoundException { + Gateway.getLDAPLookup().getRoleManager().removeRole(agent, this); + } + + @Override + public String dump() { + StringBuffer comp = new StringBuffer("Components: { "); + for (String element : mPath) + comp.append("'").append(element).append("' "); + + return "Path - dump(): "+ + comp.toString()+ + "}\n dn="+ + getDN()+ + "\n string="+ + toString()+ + "\n type="+ + mType+ + "\n name="+ + getName()+ + "\n "; + } + + @Override + public LDAPAttributeSet createAttributeSet() + { + LDAPAttributeSet attrs = new LDAPAttributeSet(); + attrs.add(new LDAPAttribute("objectclass","cristalrole")); + String jobListString = hasJobList?"TRUE":"FALSE"; + attrs.add(new LDAPAttribute("jobList",jobListString)); + attrs.add(new LDAPAttribute("cn", getName())); + return attrs; + } +} + diff --git a/src/main/java/com/c2kernel/persistency/ClusterStorage.java b/src/main/java/com/c2kernel/persistency/ClusterStorage.java new file mode 100644 index 0000000..80fd86d --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/ClusterStorage.java @@ -0,0 +1,104 @@ + +package com.c2kernel.persistency; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.utils.Logger; + +/** Interface for persistency managers of entities. + A Cluster is defined as a path under the item + Each ClusterStorage must support get() and getClusterContents() for clusters they return READ and READWRITE from queryClusterSupport + and put() and delete() for clusters they return WRITE and READWRITE from queryClusterSupport(). + Unsupported operations should throw a ClusterStorageException. + If a cluster does not exist, get should return null, and delete should return + @version $Revision: 1.22 $ $Date: 2006/02/01 13:27:47 $ + @author $Author: abranson $ +*/ +public abstract class ClusterStorage { + + public static final short NONE = 0; + public static final short READ = 1; + public static final short WRITE = 2; + public static final short READWRITE = 3; + + // Cluster types + public static final String ROOT = ""; + public static final String PROPERTY = "Property"; + public static final String COLLECTION = "Collection"; + public static final String LIFECYCLE = "LifeCycle"; + public static final String OUTCOME = "Outcome"; + public static final String HISTORY = "AuditTrail"; + public static final String VIEWPOINT = "ViewPoint"; + public static final String JOB = "Job"; + + // connection maintenance + public abstract void open() + throws ClusterStorageException; + public abstract void close() + throws ClusterStorageException; + + // introspection + public abstract short queryClusterSupport(String clusterType); + public abstract String getName(); + // for addressing queries + public abstract String getId(); + + + /** Quickly gets the first string of the slashed path */ + public static String getClusterType(String path) { + try { + if (path == null || path.length() == 0) return ClusterStorage.ROOT; + int start = path.charAt(0) == '/' ? 1 : 0; + int end = path.indexOf('/', start + 1); + if (end == -1) end = path.length(); + return path.substring(start, end); + } catch (Exception ex) { + Logger.error(ex); + return ClusterStorage.ROOT; + } + } + + public static String getPath(C2KLocalObject obj) { + String root = obj.getClusterType(); + if (root == null) return null; // no storage allowed + if (obj instanceof Outcome) { + Outcome oc = (Outcome)obj; + return root+"/"+oc.getSchemaType()+"/"+oc.getSchemaVersion()+"/"+oc.getName(); + } + else if (obj instanceof Viewpoint) { + Viewpoint vp = (Viewpoint)obj; + return root+"/"+vp.getSchemaName()+"/"+vp.getName(); + } + else + return root+"/"+obj.getName(); + } + + /* object manipulation */ + + // retrieve object by path + public abstract C2KLocalObject get(Integer sysKey, String path) + throws ClusterStorageException; + // store object by path + public abstract void put(Integer sysKey, C2KLocalObject obj) + throws ClusterStorageException; + // delete cluster + public abstract void delete(Integer sysKey, String path) + throws ClusterStorageException; + + // db specific queries + public Object query(Object query) + throws ClusterStorageException { + throw new ClusterStorageException("Query not supported on this storage"); + } + + public String queryToXML(String query, boolean genericFormat) + throws ClusterStorageException { + throw new ClusterStorageException("Query not supported on this storage"); + } + + + // directory listing + public abstract String[] getClusterContents(Integer sysKey, String path) + throws ClusterStorageException; + +} diff --git a/src/main/java/com/c2kernel/persistency/ClusterStorageException.java b/src/main/java/com/c2kernel/persistency/ClusterStorageException.java new file mode 100644 index 0000000..b51982c --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/ClusterStorageException.java @@ -0,0 +1,17 @@ +package com.c2kernel.persistency; + +/** + * + * @version $Revision: 1.2 $ $Date: 2003/07/14 07:57:06 $ + * @author $Author: abranson $ + */ + +public class ClusterStorageException extends Exception { + public ClusterStorageException() { + super(); + } + public ClusterStorageException(String s) { + super(s); + } + +} diff --git a/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java b/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java new file mode 100644 index 0000000..756ac4d --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/ClusterStorageManager.java @@ -0,0 +1,379 @@ +package com.c2kernel.persistency; + +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.agent.JobList; +import com.c2kernel.entity.proxy.EntityProxyManager; +import com.c2kernel.entity.proxy.ProxyMessage; +import com.c2kernel.events.History; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.SoftCache; + +/** + * instantiates ClusterStorages listed in properties file All read/write requests to storage pass through this object, which + * can query the capabilities of each declared storage, and channel requests accordingly. Transaction based. + * + * * @version $Revision: 1.62 $ $Date: 2006/02/01 13:27:46 $ + * @author $Author: abranson $ + */ +public class ClusterStorageManager { + HashMap allStores = new HashMap(); + String[] clusterPriority; + HashMap> clusterWriters = new HashMap>(); + HashMap> clusterReaders = new HashMap>(); + // we don't need a soft cache for the top level cache - the proxies and entities clear that when reaped + HashMap> memoryCache = new HashMap>(); + boolean ready = false; + + /** + * Initialises all ClusterStorage handlers listed by class name in the property "ClusterStorages" + * This property is usually process specific, and so should be in the server/client.conf and not the connect file. + */ + public ClusterStorageManager() throws ClusterStorageException { + String allClusters = Gateway.getProperty("ClusterStorage"); + if (allClusters == null || allClusters.equals("")) { + Logger.warning("ClusterStorageManager.init() - no ClusterStorages defined. No persistency!"); + return; + } + StringTokenizer tok = new StringTokenizer(allClusters, ","); + clusterPriority = new String[tok.countTokens()]; + int clusterNo = 0; + ArrayList rootStores = new ArrayList(); + while (tok.hasMoreTokens()) { + ClusterStorage newStorage = null; + String newStorageClass = tok.nextToken(); + try { + try { + newStorage = (ClusterStorage)(Class.forName(newStorageClass).newInstance()); + } catch (ClassNotFoundException ex2) { + newStorage = (ClusterStorage)(Class.forName("com.c2kernel.persistency."+newStorageClass).newInstance()); + } + newStorage.open(); + Logger.msg(5, "ClusterStorageManager.init() - Cluster storage " + newStorageClass + + " initialised successfully."); + allStores.put(newStorage.getId(), newStorage); + rootStores.add(newStorage); + clusterPriority[clusterNo++] = newStorage.getId(); + + } catch (ClusterStorageException ex) { + Logger.error(ex); + throw new ClusterStorageException("ClusterStorageManager.init() - Error initialising storage handler " + newStorageClass + + ": " + ex.getMessage()); + } catch (ClassNotFoundException ex) { + throw new ClusterStorageException("ClusterStorageManager.init() - The cluster storage handler class " + newStorageClass + + " could not be found."); + } catch (InstantiationException ex) { + throw new ClusterStorageException("ClusterStorageManager.init() - The cluster storage handler class " + newStorageClass + + " could not be instantiated."); + } catch (IllegalAccessException ex) { + throw new ClusterStorageException("ClusterStorageManager.init() - The cluster storage handler class " + newStorageClass + + " was not allowed to be instantiated."); + } + } + clusterReaders.put(ClusterStorage.ROOT, rootStores); // all storages are queried for clusters at the root level + ready = true; + } + + public void close() { + for (ClusterStorage thisStorage : allStores.values()) { + try { + thisStorage.close(); + } catch (ClusterStorageException ex) { + Logger.error(ex); + } + } + ready = false; + } + + /** + * Returns the loaded storage that declare that they can handle writing or reading the specified cluster name (e.g. + * Collection, Property) Must specify if the request is a read or a write. + */ + private ArrayList findStorages(String clusterType, boolean forWrite) { + + if (!ready) { + Logger.error("ClusterStorageManager.findStorages() - called before init!"); + return null; + } + + // choose the right cache for readers or writers + HashMap> cache; + if (forWrite) + cache = clusterWriters; + else + cache = clusterReaders; + + // check to see if we've been asked to do this before + if (cache.containsKey(clusterType)) + return cache.get(clusterType); + + // not done yet, we'll have to query them all + Logger.msg(7, "ClusterStorageManager.findStorages() - finding storage for "+clusterType+" forWrite:"+forWrite); + ArrayList useableStorages = new ArrayList(); + for (String element : clusterPriority) { + ClusterStorage thisStorage = allStores.get(element); + short requiredSupport = forWrite ? ClusterStorage.WRITE : ClusterStorage.READ; + if ((thisStorage.queryClusterSupport(clusterType) & requiredSupport) == requiredSupport) { + Logger.msg(7, "ClusterStorageManager.findStorages() - Got "+thisStorage.getName()); + useableStorages.add(thisStorage); + } + } + cache.put(clusterType, useableStorages); + return useableStorages; + } + + /** + * Retrieves the ids of the next level of a cluster + * Does not look in any currently open transactions. + */ + public String[] getClusterContents(Integer sysKey, String path) throws ClusterStorageException { + //String[] retArr = new String[0]; + ArrayList contents = new ArrayList(); + // get all readers + Logger.msg(8, "ClusterStorageManager.getClusterContents() - Finding contents of "+path); + ArrayList readers = findStorages(ClusterStorage.getClusterType(path), false); + // try each in turn until we get a result + for (ClusterStorage thisReader : readers) { + try { + String[] thisArr = thisReader.getClusterContents(sysKey, path); + if (thisArr != null) { + for (int j = 0; j < thisArr.length; j++) + if (!contents.contains(thisArr[j])) { + Logger.msg(9, "ClusterStorageManager.getClusterContents() - "+thisReader.getName()+" reports "+thisArr[j]); + contents.add(thisArr[j]); + } + } + } catch (ClusterStorageException e) { + Logger.error("ClusterStorageManager.getClusterContents() - reader " + thisReader.getName() + + " could not retrieve contents of " + sysKey + "/" + path + ": " + e.getMessage()); + } + } + + String[] retArr = new String[0]; + retArr = contents.toArray(retArr); + return retArr; + } + + /** Internal get method. Retrieves clusters from ClusterStorages & maintains the memory cache */ + public C2KLocalObject get(Integer sysKeyIntObj, String path) throws ClusterStorageException, ObjectNotFoundException { + C2KLocalObject result = null; + // check cache first + SoftCache sysKeyMemCache = null; + if (memoryCache.containsKey(sysKeyIntObj)) { + sysKeyMemCache = memoryCache.get(sysKeyIntObj); + synchronized(sysKeyMemCache) { + C2KLocalObject obj = sysKeyMemCache.get(path); + if (obj != null) { + Logger.msg(7, "ClusterStorageManager.get() - found "+sysKeyIntObj+"/"+path+" in memcache"); + return obj; + } + } + } + + // special case - loading viewpoint contents + if (path.startsWith(ClusterStorage.VIEWPOINT) && + path.endsWith("/data")) { + StringTokenizer tok = new StringTokenizer(path,"/"); + if (tok.countTokens() == 4) { // to not catch viewpoints called 'data' + Outcome data = null; + Viewpoint view = (Viewpoint)get(sysKeyIntObj, path.substring(0, path.lastIndexOf("/"))); + if (view != null) + data = view.getOutcome(); + return data; + } + } + + // deal out top level remote maps + if (path.indexOf('/') == -1) { + if (path.equals(ClusterStorage.HISTORY)) + result = new History(sysKeyIntObj, null); + if (path.equals(ClusterStorage.JOB)) + result = new JobList(sysKeyIntObj, null); + if (result!=null) { + synchronized(sysKeyMemCache) { + sysKeyMemCache.put(path, result); + } + return result; + } + + } + + // else try each reader in turn until we find it + ArrayList readers = findStorages(ClusterStorage.getClusterType(path), false); + for (ClusterStorage thisReader : readers) { + try { + result = thisReader.get(sysKeyIntObj, path); + Logger.msg(7, "ClusterStorageManager.get() - reading "+path+" from "+thisReader.getName() + " for intkey=" + sysKeyIntObj); + if (result != null) { // got it! + // store it in the cache + if (sysKeyMemCache == null) { // create cache if needed + sysKeyMemCache = new SoftCache(0); + synchronized (memoryCache) { + memoryCache.put(sysKeyIntObj, sysKeyMemCache); + } + } + synchronized(sysKeyMemCache) { + sysKeyMemCache.put(path, result); + } + // then return it + return result; + } + } catch (ClusterStorageException e) { + Logger.msg(7, "ClusterStorageManager.get() - reader " + thisReader.getName() + " could not retrieve " + sysKeyIntObj + + "/" + path + ": " + e.getMessage()); + } + } + throw new ObjectNotFoundException("ClusterStorageManager.get() - Path " + path + " not found in " + sysKeyIntObj, ""); + } + + /** Internal put method. Creates or overwrites a cluster in all writers. Used when committing transactions. */ + public void put(Integer sysKeyIntObj, C2KLocalObject obj) throws ClusterStorageException { + String path = ClusterStorage.getPath(obj); + ArrayList writers = findStorages(ClusterStorage.getClusterType(path), true); + for (ClusterStorage thisWriter : writers) { + try { + Logger.msg(7, "ClusterStorageManager.put() - writing "+path+" to "+thisWriter.getName()); + thisWriter.put(sysKeyIntObj, obj); + } catch (ClusterStorageException e) { + Logger.error("ClusterStorageManager.put() - writer " + thisWriter.getName() + " could not store " + + sysKeyIntObj + "/" + path + ": " + e.getMessage()); + throw e; + } + } + // put in mem cache if that worked + SoftCache sysKeyMemCache; + if (memoryCache.containsKey(sysKeyIntObj)) + sysKeyMemCache = memoryCache.get(sysKeyIntObj); + else { + sysKeyMemCache = new SoftCache(); + synchronized (memoryCache) { + memoryCache.put(sysKeyIntObj, sysKeyMemCache); + } + } + + synchronized(sysKeyMemCache) { + sysKeyMemCache.put(path, obj); + } + + if (Logger.doLog(9)) dumpCacheContents(9); + + // transmit proxy event + EntityProxyManager.sendProxyEvent( new ProxyMessage(sysKeyIntObj.intValue(), path, ProxyMessage.ADDED)); + } + + /** Deletes a cluster from all writers */ + public void remove(Integer sysKeyIntObj, String path) throws ClusterStorageException { + ArrayList writers = findStorages(ClusterStorage.getClusterType(path), true); + for (ClusterStorage thisWriter : writers) { + try { + Logger.msg(7, "ClusterStorageManager.delete() - removing "+path+" from "+thisWriter.getName()); + thisWriter.delete(sysKeyIntObj, path); + } catch (ClusterStorageException e) { + Logger.error("ClusterStorageManager.delete() - writer " + thisWriter.getName() + " could not delete " + sysKeyIntObj + + "/" + path + ": " + e.getMessage()); + throw e; + } + } + + if (memoryCache.containsKey(sysKeyIntObj)) { + SoftCache sysKeyMemCache = memoryCache.get(sysKeyIntObj); + synchronized (sysKeyMemCache) { + sysKeyMemCache.remove(path); + } + } + + + // transmit proxy event + EntityProxyManager.sendProxyEvent( new ProxyMessage(sysKeyIntObj.intValue(), path, ProxyMessage.DELETED)); + } + + public void clearCache(Integer sysKeyIntObj, String path) { + Logger.msg(7, "CSM.clearCache() - removing "+sysKeyIntObj+"/"+path); + + if (memoryCache.containsKey(sysKeyIntObj)) { + SoftCache sysKeyMemCache = memoryCache.get(sysKeyIntObj); + synchronized(sysKeyMemCache) { + for (Iterator iter = sysKeyMemCache.keySet().iterator(); iter.hasNext();) { + String thisPath = iter.next(); + if (thisPath.startsWith(path)) { + Logger.msg(7, "CSM.clearCache() - removing "+sysKeyIntObj+"/"+thisPath); + iter.remove(); + } + } + } + } + } + + public void clearCache(Integer sysKeyIntObj) { + + Logger.msg(5, "CSM.clearCache() - removing entire cache of "+sysKeyIntObj); + + if (memoryCache.containsKey(sysKeyIntObj)) { + synchronized (memoryCache) { + if (Logger.doLog(6)) { + SoftCache sysKeyMemCache = memoryCache.get(sysKeyIntObj); + int size = sysKeyMemCache.size(); + Logger.msg(6, "CSM.clearCache() - "+size+" objects to remove."); + } + memoryCache.remove(sysKeyIntObj); + } + } + else + Logger.msg(6, "CSM.clearCache() - No objects cached"); + } + + public void clearCache() { + synchronized (memoryCache) { + memoryCache.clear(); + } + Logger.msg(5, "CSM.clearCache() - cleared entire cache, "+memoryCache.size()+" entities."); + } + + public void dumpCacheContents(int logLevel) { + if (!Logger.doLog(logLevel)) return; + synchronized(memoryCache) { + for (Integer sysKey : memoryCache.keySet()) { + Logger.msg(logLevel, "Cached Objects of Entity "+sysKey); + SoftCache sysKeyMemCache = memoryCache.get(sysKey); + try { + synchronized(sysKeyMemCache) { + for (Object name : sysKeyMemCache.keySet()) { + String path = (String) name; + try { + Logger.msg(logLevel, " Path "+path+": "+sysKeyMemCache.get(path).getClass().getName()); + } catch (NullPointerException e) { + Logger.msg(logLevel, " Path "+path+": reaped"); + } + } + } + } catch (ConcurrentModificationException ex) { + Logger.msg(logLevel, "Cache modified - aborting"); + } + } + Logger.msg(logLevel, "Total number of cached entities: "+memoryCache.size()); + } + } + + public Object query(String id, Object query) throws ClusterStorageException { + ClusterStorage requiredStorage = allStores.get(id); + if (requiredStorage == null) + throw new ClusterStorageException("Storage "+id+" not found."); + return requiredStorage.query(query); + } + + public String queryToXML(String id, String query, boolean genericFormat) throws ClusterStorageException { + ClusterStorage requiredStorage = allStores.get(id); + if (requiredStorage == null) + throw new ClusterStorageException("Storage "+id+" not found."); + return requiredStorage.queryToXML(query, genericFormat); + } +} diff --git a/src/main/java/com/c2kernel/persistency/LDAPClientReader.java b/src/main/java/com/c2kernel/persistency/LDAPClientReader.java new file mode 100644 index 0000000..ac9215c --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/LDAPClientReader.java @@ -0,0 +1,43 @@ +package com.c2kernel.persistency; + +import com.c2kernel.entity.C2KLocalObject; + +/** Allows clients to directly load properties and collections from the LDAP +* so no CORBA calls need to be made during normal browsing +*/ + +public class LDAPClientReader extends LDAPClusterStorage { + // return all readwrite support as readonly + @Override + public short queryClusterSupport(String clusterType) { + return (short)(super.queryClusterSupport(clusterType) & READ); + } + + + /** + * @see com.c2kernel.persistency.ClusterStorage#delete(Integer, String) + */ + @Override + public void delete(Integer sysKey, String path) + throws ClusterStorageException { + throw new ClusterStorageException("Writing not supported in ClientReader"); + } + + /** + * @see com.c2kernel.persistency.ClusterStorage#getName() + */ + @Override + public String getName() { + return "LDAP Client Cluster Reader"; + } + + /** + * @see com.c2kernel.persistency.ClusterStorage#put(Integer, String, C2KLocalObject) + */ + + public void put(Integer sysKey, String path, C2KLocalObject obj) + throws ClusterStorageException { + throw new ClusterStorageException("Writing not supported in ClientReader"); + } + +} diff --git a/src/main/java/com/c2kernel/persistency/LDAPClusterStorage.java b/src/main/java/com/c2kernel/persistency/LDAPClusterStorage.java new file mode 100644 index 0000000..16ac7a0 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/LDAPClusterStorage.java @@ -0,0 +1,172 @@ +package com.c2kernel.persistency; +import java.util.ArrayList; +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.lookup.LDAPPropertyManager; +import com.c2kernel.process.Gateway; +import com.c2kernel.property.Property; +import com.c2kernel.utils.Logger; + +public class LDAPClusterStorage extends ClusterStorage { + LDAPPropertyManager ldapStore; + + @Override + public void open() throws ClusterStorageException { + ldapStore = Gateway.getLDAPLookup().getPropManager(); + + } + + @Override + public void close() throws ClusterStorageException { + } + + // introspection + @Override + public short queryClusterSupport(String clusterType) { + if (clusterType.equals(PROPERTY)) + return READWRITE; + else + return NONE; + } + + @Override + public String getName() { + return "LDAP Cluster Storage"; + } + + @Override + public String getId() { + return "LDAP"; + } + + // retrieve object by path + @Override + public C2KLocalObject get(Integer sysKey, String path) throws ClusterStorageException { + Logger.msg(6, "LDAPClusterStorage.get() - "+sysKey+"/"+path); + StringTokenizer tok = new StringTokenizer(path, "/"); + int pathLength = tok.countTokens(); + if (pathLength != 2) + throw new ClusterStorageException("Path length was invalid: "+path); + String type = tok.nextToken(); + + EntityPath thisEntity; + try { + thisEntity = new EntityPath(sysKey.intValue()); + } catch (InvalidEntityPathException e) { + throw new ClusterStorageException("Invalid Syskey:"+sysKey); + } + + String objName = tok.nextToken(); + C2KLocalObject newObj; + + if (type.equals(PROPERTY)) { + try { + String value = ldapStore.getPropertyValue(thisEntity, objName); + Property newProperty = new Property(); + newProperty.setName(objName); + newProperty.setValue(value); + newObj = newProperty; + } catch (ObjectNotFoundException ex) { + throw new ClusterStorageException("Property "+objName+" not found in "+sysKey); + } + + } + else + throw new ClusterStorageException("Cluster type "+type+" not supported."); + + return newObj; + } + // store object by path + @Override + public void put(Integer sysKey, C2KLocalObject obj) throws ClusterStorageException { + Logger.msg(6, "LDAPClusterStorage.put() - "+sysKey+"/"+ClusterStorage.getPath(obj)); + + String type = obj.getClusterType(); + + EntityPath thisEntity; + try { + thisEntity = new EntityPath(sysKey.intValue()); + } catch (InvalidEntityPathException e) { + throw new ClusterStorageException("Invalid Syskey:"+sysKey); + } + + if (type.equals(PROPERTY)) { + try { + ldapStore.setProperty(thisEntity, (Property)obj); + } catch (Exception e1) { + Logger.error(e1); + throw new ClusterStorageException("LDAPClusterStorage - could not write property"); + } + } + else + throw new ClusterStorageException("Cluster type "+type+" not supported."); + + } + // delete cluster + @Override + public void delete(Integer sysKey, String path) throws ClusterStorageException { + StringTokenizer tok = new StringTokenizer(path, "/"); + int pathLength = tok.countTokens(); + if (pathLength != 2) + throw new ClusterStorageException("Path length was invalid: "+path); + String type = tok.nextToken(); + + EntityPath thisEntity; + try { + thisEntity = new EntityPath(sysKey.intValue()); + } catch (InvalidEntityPathException e) { + throw new ClusterStorageException("Invalid Syskey:"+sysKey); + } + + if (type.equals(PROPERTY)) { + try { + ldapStore.deleteProperty(thisEntity, tok.nextToken()); + } catch (Exception e1) { + Logger.error(e1); + throw new ClusterStorageException("LDAPClusterStorage - could not delete property"); + } + } + else + throw new ClusterStorageException("Cluster type "+type+" not supported."); + + } + + /* navigation */ + + // directory listing + @Override + public String[] getClusterContents(Integer sysKey, String path) throws ClusterStorageException { + Logger.msg(6, "LDAPClusterStorage.getClusterContents() - "+sysKey+"/"+path); + StringTokenizer tok = new StringTokenizer(path, "/"); + int pathLength = tok.countTokens(); + if (pathLength > 1) + return new String[0]; + + String type = getClusterType(path); + try + { + EntityPath thisEntity = new EntityPath(sysKey.intValue()); + if (type.equals(PROPERTY)) + return ldapStore.getPropertyNames(thisEntity); + else + if (type.equals("")) { // root query + String[] allClusters = new String[0]; + ArrayList clusterList = new ArrayList(); + if (ldapStore.hasProperties(thisEntity)) + clusterList.add(PROPERTY); + allClusters = clusterList.toArray(allClusters); + return allClusters; + } + else + throw new ClusterStorageException("Cluster type "+type+" not supported."); + } catch (InvalidEntityPathException e) { + throw new ClusterStorageException("Invalid Syskey:"+sysKey); + } catch (ObjectNotFoundException e) { + throw new ClusterStorageException("Entity "+sysKey+" does not exist"); + } + } +} diff --git a/src/main/java/com/c2kernel/persistency/ProxyLoader.java b/src/main/java/com/c2kernel/persistency/ProxyLoader.java new file mode 100644 index 0000000..e614b0d --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/ProxyLoader.java @@ -0,0 +1,133 @@ +package com.c2kernel.persistency; +import java.util.HashMap; +import java.util.StringTokenizer; + +import com.c2kernel.entity.AgentHelper; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.ItemHelper; +import com.c2kernel.entity.ManageableEntity; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + +/** Used by proxies to load clusters by queryData from the Entity. +* Last client storage - only used if not cached elsewhere +*/ + +public class ProxyLoader extends ClusterStorage { + HashMap entities = new HashMap(); + LDAPLookup lookup; + + @Override + public void open() throws ClusterStorageException { + lookup = Gateway.getLDAPLookup(); + } + + @Override + public void close() throws ClusterStorageException { + } + // introspection + @Override + public short queryClusterSupport(String clusterType) { + return READ; + } + + @Override + public String getName() { + return "Proxy Cluster Loader"; + } + + @Override + public String getId() { + return "CORBA"; + } + + // retrieve object by path + @Override + public C2KLocalObject get(Integer sysKey, String path) throws ClusterStorageException { + try { + ManageableEntity thisEntity = getIOR(sysKey); + String type = getClusterType(path); + + // fetch the xml from the item + String queryData = thisEntity.queryData(path); + + if (queryData != null) { + if (type.equals(OUTCOME)) + return new Outcome(path, queryData); + else + return (C2KLocalObject)CastorXMLUtility.unmarshall(queryData); + } + } catch (Exception e) { + //Logger.error(e); + throw new ClusterStorageException(e.getMessage()); + } + return null; + } + + // store object by path + @Override + public void put(Integer sysKey, C2KLocalObject obj) throws ClusterStorageException { + // not supported + throw new ClusterStorageException("Cannot write to items through the ProxyLoader"); + } + // delete cluster + @Override + public void delete(Integer sysKey, String path) throws ClusterStorageException { + // not supported + throw new ClusterStorageException("Cannot write to items through the ProxyLoader"); + } + + /* navigation */ + + // directory listing + @Override + public String[] getClusterContents(Integer sysKey, String path) throws ClusterStorageException { + try { + ManageableEntity thisEntity = getIOR(sysKey); + String contents = thisEntity.queryData(path+"/all"); + StringTokenizer tok = new StringTokenizer(contents, ","); + String[] result = new String[tok.countTokens()]; + for (int i=0; i extends TreeMap implements C2KLocalObject { + + private int mID=-1; + private String mName; + protected int mSysKey; + private String mPath = ""; + Object keyLock = null; + TransactionManager storage; + EntityProxyObserver listener; + Comparator comp; + EntityProxy source; + Object mLocker; // if this remote map will participate in a transaction + + public RemoteMap(int sysKey, String path, Object locker) { + + super(new Comparator() { + @Override + public int compare(String o1, String o2) { + Integer i1 = null, i2 = null; + try { + i1 = Integer.valueOf(o1); + i2 = Integer.valueOf(o2); + return i1.compareTo(i2); + } catch (NumberFormatException ex) { } + return o1.compareTo(o2); + } + }); + + mSysKey = sysKey; + mLocker = locker; + + // split the path into path/name + int lastSlash = path.lastIndexOf("/"); + mName = path.substring(lastSlash+1); + if (lastSlash>0) mPath = path.substring(0,lastSlash); + + // see if the name is also a suitable id + try { + mID = Integer.parseInt(mName); + } catch (NumberFormatException e) {} + storage = Gateway.getStorage(); + + listener = new EntityProxyObserver() { + @Override + public void add(V obj) { + synchronized (this) { + putLocal(obj.getName(), obj); + } + } + + @Override + public void remove(String id) { + synchronized (this) { + removeLocal(id); + } + } + + @Override + public void control(String control, String msg) { } + }; + + try { + source = Gateway.getProxyManager().getProxy(new EntityPath(sysKey)); + source.subscribe(new MemberSubscription(listener, path, false)); + } catch (Exception ex) { + Logger.error("Error subscribing to remote map. Changes will not be received"); + Logger.error(ex); + } + } + + protected void loadKeys() { + if (keyLock != null) return; + clear(); + keyLock = new Object(); + synchronized(this) { + String[] keys; + try { + keys = storage.getClusterContents(mSysKey, mPath+mName); + for (String key : keys) super.put(key, null); + } catch (ClusterStorageException e) { + Logger.error(e); + } + + } + } + + public synchronized int getLastId() { + loadKeys(); + if (size() == 0) return -1; + try { + return Integer.parseInt(lastKey()); + } catch (NumberFormatException ex) { + return -1; + } + } + + + // c2kLocalObject methods + public void setID(int id) { mID = id; } + + public int getID() { return mID; } + + @Override + public void setName(String name) { mName = name; } + + @Override + public String getName() { return mName; } + + /** + * Cannot be stored + */ + @Override + public String getClusterType() { + return null; + } + /** + * @see java.util.Map#clear() + */ + @Override + public synchronized void clear() { + synchronized (this) { + super.clear(); + } + keyLock = null; + } + + + + /** + * @see java.util.Map#containsKey(Object) + */ + @Override + public synchronized boolean containsKey(Object key) { + if (keyLock == null) loadKeys(); + return super.containsKey(key); + } + + /** + * This must retrieve all the values until a match is made. + * Very expensive, but if you must, you must. + * @see java.util.Map#containsValue(Object) + */ + @Override + public synchronized boolean containsValue(Object value) { + loadKeys(); + synchronized(this) { + for (String key: keySet()) { + if (get(key).equals(value)) return true; + } + } + return false; + } + + + /** + * @see java.util.Map#get(Object) + */ + @Override + public synchronized V get(Object objKey) { + loadKeys(); + String key; + if (objKey instanceof Integer) + key = ((Integer)objKey).toString(); + else if (objKey instanceof String) + key = (String)objKey; + else + return null; + + synchronized(this) { + try { + V value = super.get(key); + if (value == null) { + value = (V)storage.get(mSysKey, mPath+mName+"/"+key, mLocker); + super.put(key, value); + } + return value; + } catch (ClusterStorageException e) { + Logger.error(e); + } catch (ObjectNotFoundException e) { + Logger.error(e); + } + } + return null; + } + + /** + * @see java.util.Map#isEmpty() + */ + @Override + public synchronized boolean isEmpty() { + loadKeys(); + return super.isEmpty(); + } + + /** + * @see java.util.Map#keySet() + */ + @Override + public synchronized Set keySet() { + loadKeys(); + return super.keySet(); + } + + /** + * Inserts the given object into the storage + * the key is ignored - it can be fetched from the value. + * @see java.util.Map#put(Object, Object) + */ + @Override + public synchronized V put(String key, V value) { + try { + synchronized(this) { + storage.put(mSysKey, value, mLocker); + return putLocal(key, value); + } + } catch (ClusterStorageException e) { + Logger.error(e); + return null; + } + } + + protected synchronized V putLocal(String key, V value) { + return super.put(key, value); + } + + /** + * @see java.util.Map#remove(Object) + */ + @Override + public synchronized V remove(Object key) { + loadKeys(); + if (containsKey(key)) try { + synchronized(keyLock) { + storage.remove(mSysKey, mPath+mName+"/"+key, mLocker); + return super.remove(key); + } + } catch (ClusterStorageException e) { + Logger.error(e); + } + return null; + } + + protected synchronized V removeLocal(Object key) { + return super.remove(key); + } + + /** + * @see java.util.Map#size() + */ + @Override + public synchronized int size() { + loadKeys(); + return super.size(); + } + + /** + * @see java.util.Map#values() + */ + @Override + public synchronized Collection values() { + return new RemoteSet(this); + } + + /** + * Basic implementation of Set and Collection to bridge to the Iterator + * Disallows all writes. + */ + + private class RemoteSet extends AbstractSet { + RemoteMap mParent; + + public RemoteSet(RemoteMap parent) { + mParent = parent; + } + + // no modifications allowed + @Override + public boolean add(E o) { + throw new UnsupportedOperationException(); + } + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + @Override + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + return new RemoteIterator(mParent); + } + + @Override + public int size() { + return mParent.size(); + } + + } + /** + * Iterator view on RemoteMap data. Doesn't preload anything. + * REVISIT: Will go strange if the RemoteMap is modified. Detect this and throw ConcurrentMod ex + */ + private class RemoteIterator implements Iterator { + RemoteMap mParent; + Iterator iter; + + public RemoteIterator(RemoteMap parent) { + mParent = parent; + iter = mParent.keySet().iterator(); + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public C next() { + return mParent.get(iter.next()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + } + + + + +} diff --git a/src/main/java/com/c2kernel/persistency/TransactionManager.java b/src/main/java/com/c2kernel/persistency/TransactionManager.java new file mode 100644 index 0000000..d2679a8 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/TransactionManager.java @@ -0,0 +1,324 @@ +package com.c2kernel.persistency; + +import java.util.ArrayList; +import java.util.HashMap; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.agent.JobList; +import com.c2kernel.events.History; +import com.c2kernel.utils.Logger; + +public class TransactionManager { + + HashMap locks; + HashMap> pendingTransactions; + ClusterStorageManager storage; + + public TransactionManager() throws ClusterStorageException { + storage = new ClusterStorageManager(); + locks = new HashMap(); + pendingTransactions = new HashMap>(); + } + + public boolean hasPendingTransactions() + { + return pendingTransactions.size() > 0; + } + + public ClusterStorageManager getDb() { + return storage; + } + + public void close() { + if (pendingTransactions.size() != 0) { + Logger.error("There were pending transactions on shutdown. All changes were lost."); + dumpPendingTransactions(0); + } + Logger.msg("Transaction Manager: Closing storages"); + storage.close(); + } + + public String[] getClusterContents(int sysKey, String path) throws ClusterStorageException { + if (path.startsWith("/") && path.length() > 1) path = path.substring(1); + return storage.getClusterContents(new Integer(sysKey), path); + } + + /** + * Public get method. Required a 'locker' object for a transaction key. + * Checks the transaction table first to see if the caller has uncommitted changes + */ + public C2KLocalObject get(int sysKey, String path, Object locker) + throws ClusterStorageException, + ObjectNotFoundException { + if (path.startsWith("/") && path.length() > 1) path = path.substring(1); + + // deal out top level remote maps, if transactions aren't needed + if (path.indexOf('/') == -1) { + if (path.equals(ClusterStorage.HISTORY) && locker != null) + return new History(sysKey, locker); + if (path.equals(ClusterStorage.JOB) && locker != null) + return new JobList(sysKey, locker); + } + + Integer sysKeyIntObj = new Integer(sysKey); + // check to see if the locker has been modifying this cluster + synchronized(locks) { + if (locks.containsKey(sysKeyIntObj) && locks.get(sysKeyIntObj).equals(locker)) { + ArrayList lockerTransaction = pendingTransactions.get(locker); + for (TransactionEntry thisEntry : lockerTransaction) { + if (sysKey == thisEntry.sysKey.intValue() && path.equals(thisEntry.getPath())) { + if (thisEntry.obj == null) + throw new ClusterStorageException("ClusterStorageManager.get() - Cluster " + path + " has been deleted in " + sysKey + + " but not yet committed"); + return thisEntry.obj; + } + } + } + } + return storage.get(sysKeyIntObj, path); + } + + /** + * Public put method. Manages the transaction table keyed by the object 'locker'. + * If this object is null, transaction support is bypassed (so long as no lock exists on that object). + */ + public void put(int sysKey, C2KLocalObject obj, Object locker) throws ClusterStorageException { + Integer sysKeyIntObj = new Integer(sysKey); + ArrayList lockerTransaction; + String path = ClusterStorage.getPath(obj); + + synchronized(locks) { + // look to see if this object is already locked + if (locks.containsKey(sysKeyIntObj)) { + // if it's this locker, get the transaction list + Object thisLocker = locks.get(sysKeyIntObj); + if (thisLocker.equals(locker)) // retrieve the transaction list + lockerTransaction = pendingTransactions.get(locker); + else // locked by someone else + throw new ClusterStorageException("ClusterStorageManager.get() - Access denied: Object " + sysKeyIntObj + + " has been locked for writing by " + thisLocker); + } + else { // either we are the locker, or there is no locker + if (locker == null) { // non-locking put/delete + storage.put(sysKeyIntObj, obj); + return; + } + else {// initialise the transaction + locks.put(sysKeyIntObj, locker); + lockerTransaction = new ArrayList(); + pendingTransactions.put(locker, lockerTransaction); + } + } + + // create the new entry in the transaction table + TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, obj); + /* equals() in TransactionEntry only compares sysKey and path, so we can use + * contains() in ArrayList to looks for preexisting entries for this cluster + * and overwrite them. + */ + if (lockerTransaction.contains(newEntry)) + lockerTransaction.remove(newEntry); + lockerTransaction.add(newEntry); + } + } + + /** Public delete method. Uses the put method, with null as the object value. + */ + public void remove(int sysKey, String path, Object locker) throws ClusterStorageException { + Integer sysKeyIntObj = new Integer(sysKey); + ArrayList lockerTransaction; + synchronized(locks) { + // look to see if this object is already locked + if (locks.containsKey(sysKeyIntObj)) { + // if it's this locker, get the transaction list + Object thisLocker = locks.get(sysKeyIntObj); + if (thisLocker.equals(locker)) // retrieve the transaction list + lockerTransaction = pendingTransactions.get(locker); + else // locked by someone else + throw new ClusterStorageException("ClusterStorageManager.get() - Access denied: Object " + sysKeyIntObj + + " has been locked for writing by " + thisLocker); + } + else { // either we are the locker, or there is no locker + if (locker == null) { // non-locking put/delete + storage.remove(sysKeyIntObj, path); + return; + } + else {// initialise the transaction + locks.put(sysKeyIntObj, locker); + lockerTransaction = new ArrayList(); + pendingTransactions.put(locker, lockerTransaction); + } + } + + // create the new entry in the transaction table + TransactionEntry newEntry = new TransactionEntry(sysKeyIntObj, path, null); + /* equals() in TransactionEntry only compares sysKey and path, so we can use + * contains() in ArrayList to looks for preexisting entries for this cluster + * and overwrite them. + */ + if (lockerTransaction.contains(newEntry)) + lockerTransaction.remove(newEntry); + lockerTransaction.add(newEntry); + } + } + + /** + * Removes all child objects from the given path + * + * @param sysKey - entity to delete from + * @param path - root path to delete + * @param locker - locking object + * + * @throws ClusterStorageException - when deleting fails + */ + public void removeCluster(int sysKey, String path, Object locker) throws ClusterStorageException { + + String[] children = getClusterContents(sysKey, path); + for (String element : children) + removeCluster(sysKey, path+(path.length()>0?"/":"")+element, locker); + if (children.length==0 && path.indexOf("/") > -1) + remove(sysKey, path, locker); + + } + /** + * Writes all pending changes to the backends. + */ + public void commit(Object locker) { + synchronized(locks) { + ArrayList lockerTransactions = pendingTransactions.get(locker); + HashMap exceptions = new HashMap(); + // quit if no transactions are present; + if (lockerTransactions == null) return; + for (TransactionEntry thisEntry : lockerTransactions) { + try { + if (thisEntry.obj == null) + storage.remove(thisEntry.sysKey, thisEntry.path); + else + storage.put(thisEntry.sysKey, thisEntry.obj); + locks.remove(thisEntry.sysKey); + } catch (Exception e) { + exceptions.put(thisEntry, e); + } + } + pendingTransactions.remove(locker); + if (exceptions.size() > 0) { // oh dear + Logger.error("TransactionManager.commit() - Problems during transaction commit of locker "+locker.toString()+". Database may be in an inconsistent state."); + for (TransactionEntry entry : exceptions.keySet()) { + Exception ex = exceptions.get(entry); + Logger.msg(entry.toString()); + Logger.error(ex); + } + dumpPendingTransactions(0); + Logger.die("Database failure"); + } + + } + } + + /** + * Rolls back all changes sent in the name of 'locker' and unlocks the sysKeys + */ + public void abort(Object locker) { + synchronized(locks) { + if (locks.containsValue(locker)) { + for (Integer thisKey : locks.keySet()) { + if (locks.get(thisKey).equals(locker)) + locks.remove(thisKey); + } + } + pendingTransactions.remove(locker); + } + } + + public void clearCache(int sysKey, String path) { + if (sysKey == -1) + storage.clearCache(); + else if (path == null) + storage.clearCache(new Integer(sysKey)); + else + storage.clearCache(new Integer(sysKey), path); + + } + + public void dumpPendingTransactions(int logLevel) { + Logger.msg(logLevel, "================"); + Logger.msg(logLevel, "Transaction dump"); + Logger.msg(logLevel, "Locked Items:"); + if (locks.size() == 0) + Logger.msg(logLevel, " None"); + else + for (Integer thisKey : locks.keySet()) { + Object locker = locks.get(thisKey); + Logger.msg(logLevel, " "+thisKey+" locked by "+locker); + } + + Logger.msg(logLevel, "Open transactions:"); + if (pendingTransactions.size() == 0) + Logger.msg(logLevel, " None"); + else + for (Object thisLocker : pendingTransactions.keySet()) { + Logger.msg(logLevel, " Transaction owner:"+thisLocker); + ArrayList entries = pendingTransactions.get(thisLocker); + for (TransactionEntry thisEntry : entries) { + Logger.msg(logLevel, " "+thisEntry.toString()); + } + } + } + + /** Used in the transaction table to store details of a put until commit + */ + class TransactionEntry { + public Integer sysKey; + public String path; + public C2KLocalObject obj; + public TransactionEntry(Integer sysKey, String path, C2KLocalObject obj) { + this.sysKey = sysKey; + this.path = path; + this.obj = obj; + } + + public String getPath() { + return ClusterStorage.getPath(obj); + } + + @Override + public String toString() { + StringBuffer report = new StringBuffer(); + if (obj == null) + report.append("Delete"); + else + report.append("Put "+obj.getClass().getName()); + report.append(" at ").append(path).append(" in ").append(sysKey); + return report.toString(); + + } + /** + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return sysKey.hashCode()*getPath().hashCode(); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) { + if (other instanceof TransactionEntry) + return hashCode() == ((TransactionEntry)other).hashCode(); + return false; + } + + } + + public Object query(String id, Object query) throws ClusterStorageException { + return storage.query(id, query); + } + + public String queryToXML(String id, String query, boolean genericFormat) throws ClusterStorageException { + return storage.queryToXML(id, query, genericFormat); + } + +} diff --git a/src/main/java/com/c2kernel/persistency/XMLClusterStorage.java b/src/main/java/com/c2kernel/persistency/XMLClusterStorage.java new file mode 100644 index 0000000..5909fac --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/XMLClusterStorage.java @@ -0,0 +1,154 @@ +package com.c2kernel.persistency; +import java.io.File; +import java.util.ArrayList; + +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.InvalidEntityPathException; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +public class XMLClusterStorage extends ClusterStorage { + String rootDir=null; + + public XMLClusterStorage() { + } + + @Override + public void open() throws ClusterStorageException { + String rootProp = Gateway.getProperty("XMLStorage.root"); + if (rootProp == null) + throw new ClusterStorageException("XMLClusterStorage.open() - Root path not given in config file."); + + rootDir = new File(rootProp).getAbsolutePath(); + + if( !FileStringUtility.checkDir( rootDir ) ) { + Logger.error("XMLClusterStorage.open() - Path " + rootDir + "' does not exist. Attempting to create."); + boolean success = FileStringUtility.createNewDir(rootDir); + if (!success) throw new ClusterStorageException("XMLClusterStorage.open() - Could not create dir "+ rootDir +". Cannot continue."); + } + } + + @Override + public void close() { + rootDir = null; + } + + // introspection + @Override + public short queryClusterSupport(String clusterType) { + return ClusterStorage.READWRITE; + } + + @Override + public String getName() { + return "XML File Cluster Storage"; + } + + @Override + public String getId() { + return "XML"; + } + + /* object manipulation */ + + // retrieve object by path + @Override + public C2KLocalObject get(Integer sysKey, String path) throws ClusterStorageException { + try { + String type = ClusterStorage.getClusterType(path); + String filePath = getFilePath(sysKey, path)+".xml"; + String objString = FileStringUtility.file2String(filePath); + if (objString.length() == 0) return null; + + if (type.equals("Outcome")) + return new Outcome(path, objString); + else + return (C2KLocalObject)CastorXMLUtility.unmarshall(objString); + + } catch (Exception e) { + Logger.msg(3,"XMLClusterStorage.get() - The path "+path+" from "+sysKey+" does not exist.: "+e.getMessage()); + } + return null; + } + + // store object by path + @Override + public void put(Integer sysKey, C2KLocalObject obj) throws ClusterStorageException { + try { + String filePath = getFilePath(sysKey, getPath(obj)+".xml"); + Logger.msg(7, "Writing "+filePath); + String data = CastorXMLUtility.marshall(obj); + + String dir = filePath.substring(0, filePath.lastIndexOf('/')); + if( !FileStringUtility.checkDir( dir ) ) { + boolean success = FileStringUtility.createNewDir(dir); + if (!success) throw new ClusterStorageException("XMLClusterStorage.put() - Could not create dir "+ dir +". Cannot continue."); + } + FileStringUtility.string2File(filePath, data); + } catch (Exception e) { + Logger.error(e); + throw new ClusterStorageException("XMLClusterStorage.put() - Could not write "+getPath(obj)+" to "+sysKey); + } + } + + // delete cluster + @Override + public void delete(Integer sysKey, String path) throws ClusterStorageException { + try { + String filePath = getFilePath(sysKey, path+".xml"); + boolean success = FileStringUtility.deleteDir(filePath, true, true); + if (success) return; + filePath = getFilePath(sysKey, path); + success = FileStringUtility.deleteDir(filePath, true, true); + if (success) return; + } catch(Exception e) { } + throw new ClusterStorageException("XMLClusterStorage.delete() - Failure deleting path "+path+" in "+sysKey); + } + + /* navigation */ + + // directory listing + @Override + public String[] getClusterContents(Integer sysKey, String path) throws ClusterStorageException { + String[] result = new String[0]; + try { + String filePath = getFilePath(sysKey, path); + ArrayList paths = FileStringUtility.listDir( filePath, true, false ); + if (paths == null) return result; // dir doesn't exist yet + ArrayList contents = new ArrayList(); + String previous = null; + for (int i=0; i -1) next = next.substring(next.lastIndexOf('/')+1); + contents.add(next); + } + + result = contents.toArray(result); + return result; + } catch (Exception e) { + Logger.error(e); + throw new ClusterStorageException("XMLClusterStorage.getClusterContents() - Could not get contents of "+path+" from "+sysKey+": "+e.getMessage()); + } + } + + protected String getFilePath(Integer sysKey, String path) throws InvalidEntityPathException { + EntityPath thisEntity = new EntityPath(sysKey.intValue()); + if (path.length() == 0 || path.charAt(0) != '/') path = "/"+path; + String filePath = rootDir+thisEntity.toString()+path; + Logger.msg(8, "XMLClusterStorage.getFilePath() - "+filePath); + return filePath; + } +} diff --git a/src/main/java/com/c2kernel/persistency/outcome/Outcome.java b/src/main/java/com/c2kernel/persistency/outcome/Outcome.java new file mode 100644 index 0000000..d321f69 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/outcome/Outcome.java @@ -0,0 +1,177 @@ +package com.c2kernel.persistency.outcome; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.StringTokenizer; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.xml.serialize.Method; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.c2kernel.common.PersistencyException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Logger; + +public class Outcome implements C2KLocalObject { + int mID = -1; + String mData; + String mSchemaType; + int mSchemaVersion; + Document dom; + static DocumentBuilder parser; + + static { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setValidating(false); + dbf.setNamespaceAware(false); + try { + parser = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + Logger.error(e); + } + } + + //id is the eventID + public Outcome(int id, String data, String schemaType, int schemaVersion) { + mID = id; + mData = data; + mSchemaType = schemaType; + mSchemaVersion = schemaVersion; + } + + public Outcome(String path, String data) throws PersistencyException { + // derive all the meta data from the path + StringTokenizer tok = new StringTokenizer(path,"/"); + if (tok.countTokens() != 3 && !(tok.nextToken().equals("Outcome"))) + throw new PersistencyException("Outcome() - Outcome path must have three components: "+path, null); + mSchemaType = tok.nextToken(); + String verstring = tok.nextToken(); + String objId = tok.nextToken(); + try { + mSchemaVersion = Integer.parseInt(verstring); + } catch (NumberFormatException ex) { + throw new PersistencyException("Outcome() - Outcome version was an invalid number: "+verstring, null); + } + try { + mID = Integer.parseInt(objId); + } catch (NumberFormatException ex) { + mID = -1; + } + mData = data; + } + + public void setID(int ID) { + mID = ID; + } + + public int getID() { + return mID; + } + + @Override + public void setName(String name) { + try { + mID = Integer.parseInt(name); + } catch (NumberFormatException e) { + Logger.error("Invalid id set on Outcome:"+name); + } + } + + @Override + public String getName() { + return String.valueOf(mID); + } + + public void setData(String data) { + mData = data; + dom = null; + } + + public void setData(Document data) { + mData = serialize(data, false); + dom = data; + } + + public String getData() { + return mData; + } + + public void setSchemaType(String schemaType) { + mSchemaType = schemaType; + } + + public String getSchemaType() { + return mSchemaType; + } + + public void setSchemaURL(int schemaVersion) { + mSchemaVersion = schemaVersion; + } + + public int getSchemaVersion() { + return mSchemaVersion; + } + + public void setSchemaVersion(int schVer) { + mSchemaVersion = schVer; + } + + @Override + public String getClusterType() { + return ClusterStorage.OUTCOME; + } + + // special script API methods + + /** + * Parses the outcome into a DOM tree + * @return a DOM Document + */ + public Document getDOM() { + if (dom == null) + try { + synchronized (parser) { + dom = parser.parse(new InputSource(new StringReader(mData))); + } + } catch (Exception e) { + Logger.error(e); + return null; + } + return dom; + } + + public String getField(String name) { + NodeList elements = getDOM().getDocumentElement().getElementsByTagName(name); + if (elements.getLength() == 1 && elements.item(0).hasChildNodes() && elements.item(0).getFirstChild() instanceof Text) + return ((Text)elements.item(0).getFirstChild()).getData(); + else + return null; + } + + static public String serialize(Document doc, boolean prettyPrint) + { + String serializedDoc = null; + OutputFormat format = new OutputFormat(Method.XML, null, prettyPrint); + StringWriter stringOut = new StringWriter(); + XMLSerializer serial = new XMLSerializer(stringOut, format); + try + { + serial.asDOMSerializer(); + serial.serialize(doc); + } + catch (java.io.IOException ex) + { + Logger.error(ex.toString()); + } + serializedDoc = stringOut.toString(); + return serializedDoc; + } +} diff --git a/src/main/java/com/c2kernel/persistency/outcome/OutcomeValidator.java b/src/main/java/com/c2kernel/persistency/outcome/OutcomeValidator.java new file mode 100644 index 0000000..73f5706 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/outcome/OutcomeValidator.java @@ -0,0 +1,188 @@ + +package com.c2kernel.persistency.outcome; + +import java.io.IOException; +import java.io.StringReader; + +import org.apache.xerces.parsers.DOMParser; +import org.apache.xerces.parsers.IntegratedParserConfiguration; +import org.apache.xerces.parsers.XMLGrammarPreparser; +import org.apache.xerces.util.SymbolTable; +import org.apache.xerces.util.XMLGrammarPoolImpl; +import org.apache.xerces.xni.XNIException; +import org.apache.xerces.xni.grammars.XMLGrammarDescription; +import org.apache.xerces.xni.parser.XMLErrorHandler; +import org.apache.xerces.xni.parser.XMLInputSource; +import org.apache.xerces.xni.parser.XMLParseException; +import org.apache.xerces.xni.parser.XMLParserConfiguration; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.24 $ + * $Date: 2005/06/09 13:50:10 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + +public class OutcomeValidator implements ErrorHandler, XMLErrorHandler { + + protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; + /** Validation feature id (http://xml.org/sax/features/validation). */ + protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; + /** Schema validation feature id (http://apache.org/xml/features/validation/schema). */ + protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; + /** Schema full checking feature id (http://apache.org/xml/features/validation/schema-full-checking). */ + protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; + public static final String GRAMMAR_POOL = "http://apache.org/xml/properties/internal/grammar-pool"; + + static SchemaValidator schemaValid = new SchemaValidator(); + + Schema schema; + protected StringBuffer errors = null; + XMLGrammarPoolImpl schemaGrammarPool = new XMLGrammarPoolImpl(1); + SymbolTable sym = new SymbolTable(); + + public static OutcomeValidator getValidator(Schema schema) throws InvalidDataException { + String schemaId = schema.docType+"_"+schema.docVersion; + + if (schemaId.equals("Schema_0")) + return schemaValid; + + return new OutcomeValidator(schema); + } + + protected OutcomeValidator() { + errors = new StringBuffer(); + } + + public OutcomeValidator(Schema schema) throws InvalidDataException { + this.schema = schema; + + if (schema.docType.equals("Schema")) + throw new InvalidDataException("Use SchemaValidator to validate schema", ""); + + errors = new StringBuffer(); + Logger.msg(5, "Parsing "+schema.docType+" version "+schema.docVersion+". "+schema.schema.length()+" chars"); + + XMLGrammarPreparser preparser = new XMLGrammarPreparser(sym); + preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); + preparser.setProperty(GRAMMAR_POOL, schemaGrammarPool); + + preparser.setFeature(NAMESPACES_FEATURE_ID, true); + preparser.setFeature(VALIDATION_FEATURE_ID, true); + preparser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, true); + preparser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, true); + preparser.setErrorHandler(this); + try { + preparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA, new XMLInputSource(null, null, null, new StringReader(schema.schema), null)); + } catch (IOException ex) { + throw new InvalidDataException("Error parsing schema: "+ex.getMessage(), ""); + } + + if (errors.length() > 0) { + throw new InvalidDataException("Schema error: \n"+errors.toString(), ""); + } + + } + + public synchronized String validate(Outcome outcome) { + if (outcome == null) return "Outcome object was null"; + Logger.msg(5, "Validating outcome no "+outcome.getID()+" as "+schema.docType+" v"+schema.docVersion); + if (outcome.getSchemaType().equals(schema.docType) + && outcome.getSchemaVersion() == schema.docVersion) { + return validate(outcome.getData()); + } + else + return "Outcome type and version did not match schema "+schema.docType; + } + + public synchronized String validate(String outcome) { + if (outcome == null) return "Outcome String was null"; + errors = new StringBuffer(); + try { + XMLParserConfiguration parserConfiguration = new IntegratedParserConfiguration(sym, schemaGrammarPool); + parserConfiguration.setFeature(NAMESPACES_FEATURE_ID, true); + parserConfiguration.setFeature(VALIDATION_FEATURE_ID, true); + // now we can still do schema features just in case, + // so long as it's our configuraiton...... + parserConfiguration.setFeature(SCHEMA_VALIDATION_FEATURE_ID, true); + parserConfiguration.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, true); + DOMParser parser = new DOMParser(parserConfiguration); + parser.setErrorHandler(this); + + parser.parse(new XMLInputSource(null, null, null, new StringReader(outcome), null)); + } catch (Exception e) { + return e.getMessage(); + } + return errors.toString(); + } + + private void appendError(String level, Exception ex) { + errors.append(level); + String message = ex.getMessage(); + if (message == null || message.length()==0) + message = ex.getClass().getName(); + errors.append(message); + errors.append("\n"); + } + + /** + * ErrorHandler for instances + */ + @Override + public void error(SAXParseException ex) throws SAXException { + appendError("ERROR: ", ex); + } + + /** + * + */ + @Override + public void fatalError(SAXParseException ex) throws SAXException { + appendError("FATAL: ", ex); + } + + /** + * + */ + @Override + public void warning(SAXParseException ex) throws SAXException { + appendError("WARNING: ", ex); + } + + /** + * XMLErrorHandler for schema + */ + @Override + public void error(String domain, String key, XMLParseException ex) + throws XNIException { + appendError("ERROR: ", ex); + } + + /** + * + */ + @Override + public void fatalError(String domain, String key, XMLParseException ex) + throws XNIException { + appendError("FATAL: ", ex); + } + + /** + * + */ + @Override + public void warning(String domain, String key, XMLParseException ex) + throws XNIException { + appendError("WARNING: ", ex); + } + +} diff --git a/src/main/java/com/c2kernel/persistency/outcome/Schema.java b/src/main/java/com/c2kernel/persistency/outcome/Schema.java new file mode 100644 index 0000000..73969f2 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/outcome/Schema.java @@ -0,0 +1,18 @@ +package com.c2kernel.persistency.outcome; + +/** + * @author Andrew Branson + * + * $Revision: 1.3 $ + * $Date: 2006/09/14 14:13:26 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + */ + +public class Schema { + public String docType; + public int docVersion; + public boolean breakApart; + public String schema; + } diff --git a/src/main/java/com/c2kernel/persistency/outcome/SchemaValidator.java b/src/main/java/com/c2kernel/persistency/outcome/SchemaValidator.java new file mode 100644 index 0000000..be8564b --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/outcome/SchemaValidator.java @@ -0,0 +1,55 @@ +package com.c2kernel.persistency.outcome; + +import java.io.IOException; +import java.io.StringReader; + +import org.exolab.castor.xml.schema.reader.SchemaReader; +import org.xml.sax.InputSource; + + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2005/04/26 06:48:13 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + + + +public class SchemaValidator extends OutcomeValidator { + + org.exolab.castor.xml.schema.Schema castorSchema; + /** + * + */ + + public SchemaValidator() { + + } + + public org.exolab.castor.xml.schema.Schema getSOM() { + return castorSchema; + } + + /** + * + */ + + @Override + public synchronized String validate(String outcome) { + errors = new StringBuffer(); + try { + InputSource schemaSource = new InputSource(new StringReader(outcome)); + SchemaReader mySchemaReader = new SchemaReader(schemaSource); + mySchemaReader.setErrorHandler(this); + mySchemaReader.setValidation(true); + castorSchema = mySchemaReader.read(); + } catch (IOException e) { + errors.append(e.getMessage()); + } + return errors.toString(); + } + +} diff --git a/src/main/java/com/c2kernel/persistency/outcome/Viewpoint.java b/src/main/java/com/c2kernel/persistency/outcome/Viewpoint.java new file mode 100644 index 0000000..a3fe283 --- /dev/null +++ b/src/main/java/com/c2kernel/persistency/outcome/Viewpoint.java @@ -0,0 +1,180 @@ +package com.c2kernel.persistency.outcome; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.events.Event; +import com.c2kernel.lookup.Path; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.process.Gateway; + +/** + * @author Andrew Branson + * + * $Revision: 1.10 $ + * $Date: 2005/10/05 07:39:36 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + */ + +// public static final String codeRevision = +// "$Revision: 1.10 $ $Date: 2005/10/05 07:39:36 $ $Author: abranson $"; +public class Viewpoint implements C2KLocalObject { + + int ID = -1; // not really used in this + + // db fields + int sysKey; + String schemaName; + String name; + int schemaVersion; + int eventId; + public static final int NONE = -1; + + public Viewpoint() { + eventId = NONE; + sysKey = Path.INVALID; + schemaVersion = NONE; + schemaName = null; + name = null; + } + + public Viewpoint(int sysKey, String schemaName, String name, int schemaVersion, int eventId) { + this.sysKey = sysKey; + this.schemaName = schemaName; + this.name = name; + this.schemaVersion = schemaVersion; + this.eventId = eventId; + } + + public Outcome getOutcome() throws ObjectNotFoundException, ClusterStorageException { + if (eventId == NONE) throw new ObjectNotFoundException("No last eventId defined", ""); + Outcome retVal = (Outcome)Gateway.getStorage().get(sysKey, ClusterStorage.OUTCOME+"/"+schemaName+"/"+schemaVersion+"/"+eventId, null); + return retVal; + } + + @Override + public String getClusterType() { + return ClusterStorage.VIEWPOINT; + } + + + /** + * Returns the eventId. + * @return int + */ + public int getEventId() { + return eventId; + } + + /** + * Returns the iD. + * @return int + */ + public int getID() { + return ID; + } + + /** + * Returns the name. + * @return String + */ + @Override + public String getName() { + return name; + } + + /** + * Returns the schemaName. + * @return String + */ + public String getSchemaName() { + return schemaName; + } + + /** + * Returns the schemaVersion. + * @return int + */ + public int getSchemaVersion() { + return schemaVersion; + } + + /** + * Returns the sysKey. + * @return int + */ + public int getSysKey() { + return sysKey; + } + + /** + * Sets the eventId. + * @param eventId The eventId to set + */ + public void setEventId(int eventId) { + this.eventId = eventId; + } + + /** + * Sets the iD. + * @param iD The iD to set + */ + public void setID(int iD) { + ID = iD; + } + + /** + * Sets the name. + * @param name The name to set + */ + @Override + public void setName(String name) { + this.name = name; + } + + /** + * Sets the schemaName. + * @param schemaName The schemaName to set + */ + public void setSchemaName(String schemaName) { + this.schemaName = schemaName; + } + + /** + * Sets the schemaVersion. + * @param schemaVersion The schemaVersion to set + */ + public void setSchemaVersion(int schemaVersion) { + this.schemaVersion = schemaVersion; + } + + /** + * Sets the sysKey. + * @param sysKey The sysKey to set + */ + public void setSysKey(int sysKey) { + this.sysKey = sysKey; + } + + /** + * Method getEvent. + * @return GDataRecord + */ + public Event getEvent() + throws InvalidDataException, ClusterStorageException, ObjectNotFoundException + { + if (eventId == NONE) + throw new InvalidDataException("No last eventId defined", ""); + + return (Event)Gateway.getStorage().get(sysKey, ClusterStorage.HISTORY+"/"+eventId, null); + } + + @Override + public String toString() { + return name; + } + +} diff --git a/src/main/java/com/c2kernel/process/AbstractMain.java b/src/main/java/com/c2kernel/process/AbstractMain.java new file mode 100644 index 0000000..7401d1b --- /dev/null +++ b/src/main/java/com/c2kernel/process/AbstractMain.java @@ -0,0 +1,161 @@ +/************************************************************************** + * AbstractMain + * + * $Revision: 1.67 $ + * $Date: 2004/10/25 15:27:35 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.process; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * @author $Author: abranson $ $Date: 2004/10/25 15:27:35 $ + * @version $Revision: 1.67 $ + **************************************************************************/ +abstract public class AbstractMain +{ + public static boolean runningAsWrapper = false; + + /************************************************************************** + * + **************************************************************************/ + static protected void usage() + { + System.out.println(); + System.out.println("USAGE: com.c2kernel.process.AbstractMain \n" + + " -config \n" + + " [-connect ] (or LocalCentre in conf)\n" + + " [-resURL c2kernel/resources] (or KernelResourceURL in conf)\n" + + " [-domResURL domain/resources] (or DomainResourceURL in conf)\n" + + " [-h] [-help] \n" + + " [-logLevel 0-19] \n" + + " [-logFile ]"); + Logger.die("Initialisation error"); + } + + /************************************************************************** + * reading and setting the standard c2k input paramaters + **************************************************************************/ + static public java.util.Properties readC2KArgs( String[] args ) + { + int i = 0; + String configPath = null; + String connectPath = null; + java.util.Properties c2kProps = null; + int logLevel = 0; + PrintStream logStream = System.out; + String centreId = null; + + try + { + if( args != null ) + { + while( i < args.length ) + { + if( args[i].equals("-h") || args[i].equals("-help") ) + { + usage(); + } + else if(args[i].equals("-config")) + { + if( (i+1) >= args.length ) + { + System.out.println("AbstractMain::readC2KArgs() - argument expected " + + "for -config"); + usage(); + } + System.out.println("Config file: "+args[i+1]); + configPath = args[++i]; + + } + else if(args[i].equals("-connect")) + { + if( (i+1) < args.length ) // batch file will have no arg if no cmd line arg + { + connectPath = args[++i]; + } + } + else if(args[i].equals("-logLevel")) + { + if( (i+1) >= args.length ) + { + System.out.println("AbstractMain::readC2KArgs() - argument expected " + + "for -logLevel"); + usage(); + } + logLevel = Integer.parseInt(args[++i]); + } + else if(args[i].equals("-logFile")) + { + if( (i+1) >= args.length ) + { + System.out.println("AbstractMain::readC2KArgs() - argument expected " + + "for -logFile"); + usage(); + } + logStream = new PrintStream(new FileOutputStream(args[++i], true)); + } + i++; + } + + // Set up log stream + Logger.addLogStream(logStream, logLevel); + + if (configPath == null) { + System.out.println("No config file specified"); + usage(); + } + + // Load config & connect files into c2kprops + c2kProps = FileStringUtility.loadConfigFile( configPath ); + + if (connectPath == null) { + // see if LC is listed in the config + Logger.msg(6, "No connect file specified in arguments. Looking in config."); + centreId = c2kProps.getProperty("LocalCentre"); + if (centreId!= null) connectPath = "connect/"+centreId+".clc"; + } + + if (connectPath != null) { + Logger.msg(6, "Connect file: "+connectPath); + if (centreId == null) { + String connectFileName = new File(connectPath).getName(); + centreId = connectFileName.substring(0, connectFileName.lastIndexOf(".clc")); + c2kProps.setProperty("LocalCentre", centreId); + } + FileStringUtility.appendConfigFile( c2kProps, connectPath); + } + else { + System.out.println("No connect file specified in args nor config file. Cannot continue."); + usage(); + } + } + else + { + System.out.println("AbstractMain::readC2KArgs() - no arguments!"); + usage(); + } + } + catch( Exception ex ) + { + System.out.println("Main::readC2KArgs() - bad arguments! "); + ex.printStackTrace(); + usage(); + } + + Logger.msg(7, "AbstractMain::standardSetUp() - readC2KArgs() DONE."); + + return c2kProps; + } + +} diff --git a/src/main/java/com/c2kernel/process/Bootstrap.java b/src/main/java/com/c2kernel/process/Bootstrap.java new file mode 100644 index 0000000..7eacd86 --- /dev/null +++ b/src/main/java/com/c2kernel/process/Bootstrap.java @@ -0,0 +1,288 @@ +package com.c2kernel.process; + +import java.net.InetAddress; +import java.util.Enumeration; +import java.util.StringTokenizer; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.TraceableEntity; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.events.Event; +import com.c2kernel.events.History; +import com.c2kernel.lifecycle.CompositeActivityDef; +import com.c2kernel.lifecycle.instance.CompositeActivity; +import com.c2kernel.lifecycle.instance.Workflow; +import com.c2kernel.lifecycle.instance.predefined.PredefinedStepContainer; +import com.c2kernel.lifecycle.instance.predefined.ServerPredefinedStepContainer; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.lookup.EntityPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.lookup.Path; +import com.c2kernel.lookup.RolePath; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.property.Property; +import com.c2kernel.property.PropertyArrayList; +import com.c2kernel.property.PropertyDescription; +import com.c2kernel.property.PropertyDescriptionList; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +/** + * @version $Revision: 1.25 $ $Date: 2006/01/10 09:48:32 $ + * @author $Author: abranson $ + */ + +public class Bootstrap +{ + static DomainPath thisServerPath; + + /** + * Run everything without timing-out the service wrapper + */ + public static void run() throws Exception { + // check for system agents + checkAdminAgents(); + + // create the server's mother item + createServerItem(); + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.currentThread().setName("Bootstrapper"); + + // make sure all of the boot items are up-to-date + verifyBootDataItems(); + + // verify the server item's wf + initServerItemWf(); + + Logger.msg("Bootstrap.run() - Bootstrapping complete"); + } catch (Exception e) { + Logger.error(e); + Logger.die("Exception performing bootstrap. Check that everything is OK."); + } + } + }).start(); + } + + /************************************************************************** + * Checks all kernel descriptions, stored in resources + **************************************************************************/ + public static void verifyBootDataItems() throws Exception { + String bootItems; + Logger.msg(1, "Verifying kernel boot items"); + bootItems = FileStringUtility.url2String(Resource.getKernelResourceURL("boot/allbootitems.txt")); + verifyBootDataItems(bootItems, null); + Logger.msg(1, "Boot data items complete"); + } + + private static void verifyBootDataItems(String bootList, String ns) { + StringTokenizer str = new StringTokenizer(bootList, "\n\r"); + while (str.hasMoreTokens()) { + String thisItem = str.nextToken(); + int delim = thisItem.indexOf('/'); + String itemType = thisItem.substring(0,delim); + String itemName = thisItem.substring(delim+1); + try { + String data = Resource.getTextResource(ns, "boot/"+thisItem+(itemType.equals("OD")?".xsd":".xml")); + if (data == null) + Logger.die("No data found for "+getDataType(itemType)+" "+itemName); + verifyResource(ns, itemName, itemType, data); + } catch (Exception e) { + Logger.error(e); + Logger.die("Error importing bootstrap items. Unsafe to continue."); + } + } + } + + + public static void verifyResource(String ns, String itemName, String itemType, String data) throws Exception { + Logger.msg(1, "Bootstrap.verifyResource() - Verifying data of "+getDataType(itemType)+" "+itemName); + Enumeration en = Gateway.getLDAPLookup().search(getTypeRoot(itemType), itemName); + ItemProxy thisProxy; + + if (!en.hasMoreElements()) { + Logger.msg("Bootstrap.verifyResource() - "+getDataType(itemType)+" "+itemName+" not found. Creating new."); + thisProxy = createResourceItem(itemType, itemName, ns); + } + else { + DomainPath path = (DomainPath)en.nextElement(); + thisProxy = (ItemProxy)Gateway.getProxyManager().getProxy(path); + try { + Viewpoint currentData = (Viewpoint)thisProxy.getObject(ClusterStorage.VIEWPOINT+"/"+getDataType(itemType)+"/last"); + String oldData = currentData.getOutcome().getData(); + if (data.equals(oldData)) { + Logger.msg(5, "Bootstrap.verifyResource() - Data identical, no update required"); + return; + } + } catch (ObjectNotFoundException ex) { + Logger.error("Bootstrap.verifyResource() - Item exists but no data found! Attempting to insert new."); + } + } + // data was missing or doesn't match + Logger.msg("Bootstrap.verifyResource() - Writing new data to "+getDataType(itemType)+" "+itemName); + History hist = new History(thisProxy.getSystemKey(), thisProxy); + Event newEvent = hist.addEvent("system", "Admin", Transitions.DONE, "Import", "Import", "Import", States.FINISHED); + Outcome newOutcome = new Outcome(newEvent.getID(), data, getDataType(itemType), 0); + Viewpoint newLastView = new Viewpoint(thisProxy.getSystemKey(), getDataType(itemType), "last", 0, newEvent.getID()); + Viewpoint newZeroView = new Viewpoint(thisProxy.getSystemKey(), getDataType(itemType), "0", 0, newEvent.getID()); + Gateway.getStorage().put(thisProxy.getSystemKey(), newOutcome, thisProxy); + Gateway.getStorage().put(thisProxy.getSystemKey(), newLastView, thisProxy); + Gateway.getStorage().put(thisProxy.getSystemKey(), newZeroView, thisProxy); + Gateway.getStorage().commit(thisProxy); + } + + /** + * @param itemType + * @param itemName + * @param data + */ + private static ItemProxy createResourceItem(String itemType, String itemName, String ns) throws Exception { + // create props + PropertyDescriptionList pdList = (PropertyDescriptionList)CastorXMLUtility.unmarshall(Resource.getTextResource(null, "boot/property/"+itemType+"Prop.xml")); + PropertyArrayList props = new PropertyArrayList(); + for (int i = 0; i < pdList.list.size(); i++) { + PropertyDescription pd = pdList.list.get(i); + String propName = pd.getName(); + String propVal = propName.equals("Name")?itemName:pd.getDefaultValue(); + props.list.add(new Property(propName, propVal)); + } + + EntityPath entityPath = Gateway.getLDAPLookup().getNextKeyManager().generateNextEntityKey(); + TraceableEntity newItem = (TraceableEntity)Gateway.getCorbaServer().createEntity(entityPath); + Gateway.getLDAPLookup().add(entityPath); + newItem.initialise( + 1, + CastorXMLUtility.marshall(props), + CastorXMLUtility.marshall(new CompositeActivity())); + DomainPath newDomPath = new DomainPath(getTypeRoot(itemType).toString()+"/system/"+(ns==null?"kernel":ns)+"/"+itemName); + newDomPath.setEntity(entityPath); + Gateway.getLDAPLookup().add(newDomPath); + return (ItemProxy)Gateway.getProxyManager().getProxy(entityPath); + } + + public static DomainPath getTypeRoot(String type) throws Exception { + if (type.equals("CA") || type.equals("EA")) + return new DomainPath("/desc/ActivityDesc/"); + if (type.equals("SC")) + return new DomainPath("/desc/Script/"); + if (type.equals("OD")) + return new DomainPath("/desc/OutcomeDesc/"); + throw new Exception("Unknown bootstrap item type: "+type); + } + + private static String getDataType(String type) throws Exception { + if (type.equals("CA")) + return "CompositeActivityDef"; + if (type.equals("EA")) + return "ElementaryActivityDef"; + if (type.equals("OD")) + return "Schema"; + if (type.equals("SC")) + return "Script"; + throw new Exception("Unknown bootstrap item type: "+type); + + } + + /************************************************************************** + * Checks for the existence of the admin users so you can use Cristal + **************************************************************************/ + private static void checkAgent(String name, String pass, String role, boolean joblist) throws Exception { + Logger.msg(1, "Bootstrap.checkAgent() - Checking for existence of '"+name+"' user."); + LDAPLookup lookup = Gateway.getLDAPLookup(); + try { + lookup.getRoleManager().getAgentPath(name); + Logger.msg(3, "Bootstrap.checkAgent() - User '"+name+"' found."); + return; + } catch (ObjectNotFoundException ex) { } + Logger.msg("Bootstrap.checkAgent() - User '"+name+"' not found. Creating."); + + RolePath rolePath; + try { + rolePath = lookup.getRoleManager().getRolePath(role); + } catch (ObjectNotFoundException ex) { + rolePath = lookup.getRoleManager().createRole(role, joblist); + } + + try { + EntityPath entityPath = lookup.getNextKeyManager().generateNextEntityKey(); + AgentPath agentPath = new AgentPath(entityPath.getSysKey(), name); + agentPath.setPassword(pass); + Gateway.getCorbaServer().createEntity(agentPath); + Gateway.getLDAPLookup().add(agentPath); + + // assign admin role + Logger.msg("Bootstrap.checkAgent() - Assigning role '"+role+"'"); + rolePath.addAgent(agentPath); + Gateway.getStorage().put(agentPath.getSysKey(), new Property("Name", name), null); + Gateway.getStorage().put(agentPath.getSysKey(), new Property("Type", "Agent"), null); + Logger.msg("Bootstrap.checkAgent() - Done"); + } catch (Exception ex) { + Logger.error("Unable to create "+name+" user."); + throw ex; + } + } + + /** + * + */ + public static void checkAdminAgents() throws Exception { + // check for administrative user + String adminPassword = Gateway.getProperty("AdminPassword", "admin12345"); + + checkAgent("admin", adminPassword, "Admin", false); + + // check for import user + checkAgent("system", adminPassword, "Admin", false); + + // check for local usercode user + checkAgent(InetAddress.getLocalHost().getHostName(), "uc", "UserCode", true); + } + + public static void createServerItem() throws Exception { + String serverName = Gateway.getProperty("ItemServer.name"); + thisServerPath = new DomainPath("/servers/"+serverName); + EntityPath serverEntity; + try { + serverEntity = thisServerPath.getEntity(); + } catch (ObjectNotFoundException ex) { + Logger.msg("Creating server item "+thisServerPath); + serverEntity = Gateway.getLDAPLookup().getNextKeyManager().generateNextEntityKey(); + Gateway.getCorbaServer().createEntity(serverEntity); + Gateway.getLDAPLookup().add(serverEntity); + thisServerPath.setEntity(serverEntity); + Gateway.getLDAPLookup().add(thisServerPath); + } + Gateway.getStorage().put(serverEntity.getSysKey(), new Property("Name", serverName), null); + Gateway.getStorage().put(serverEntity.getSysKey(), new Property("Type", "Server"), null); + Gateway.getStorage().put(serverEntity.getSysKey(), new Property("KernelVersion", Resource.getKernelVersion()), null); + if (Gateway.getProperty("ItemServer.Proxy.port") != null) + Gateway.getStorage().put(serverEntity.getSysKey(), + new Property("ProxyPort", Gateway.getProperty("ItemServer.Proxy.port")), null); + if (Gateway.getProperty("ItemServer.Console.port") != null) + Gateway.getStorage().put(serverEntity.getSysKey(), + new Property("ConsolePort", Gateway.getProperty("ItemServer.Console.port")), null); + Gateway.getProxyManager().connectToProxyServer(Gateway.getProperty("ItemServer.name"), Integer.parseInt(Gateway.getProperty("ItemServer.Proxy.port"))); + + } + + public static void initServerItemWf() throws Exception { + CompositeActivityDef serverWfCa = (CompositeActivityDef)LocalObjectLoader.getActDef("ServerItemWorkflow", "last"); + Workflow wf = new Workflow((CompositeActivity)serverWfCa.instantiate()); + PredefinedStepContainer predef = (PredefinedStepContainer)wf.search("workflow/predefined"); + wf.getChildGraphModel().removeVertex(predef); + wf.addChild(new ServerPredefinedStepContainer(), predef.getCentrePoint()); + wf.initialise(thisServerPath.getSysKey(), Gateway.getLDAPLookup().getRoleManager().getAgentPath("system")); + Gateway.getStorage().put(thisServerPath.getSysKey(), wf, null); + // add this proxy server in case it was just registered, or the port has changed + } +} diff --git a/src/main/java/com/c2kernel/process/Gateway.java b/src/main/java/com/c2kernel/process/Gateway.java new file mode 100644 index 0000000..aebd19e --- /dev/null +++ b/src/main/java/com/c2kernel/process/Gateway.java @@ -0,0 +1,429 @@ +package com.c2kernel.process; + +/** + * @version $Revision: 1.17 $ $Date: 2005/10/12 12:51:54 $ + * @author $Author: abranson $ + */ + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Properties; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.CorbaServer; +import com.c2kernel.entity.proxy.AgentProxy; +import com.c2kernel.entity.proxy.EntityProxyManager; +import com.c2kernel.lookup.AgentPath; +import com.c2kernel.lookup.LDAPLookup; +import com.c2kernel.lookup.LDAPProperties; +import com.c2kernel.persistency.ClusterStorageException; +import com.c2kernel.persistency.TransactionManager; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Language; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; +import com.c2kernel.utils.server.SimpleTCPIPServer; + + +/************************************************************************** + * The Gateway is the central object of a CRISTAL process. It initializes, + * maintains and shuts down every other subsystem in both the client and the + * server. + * + * Child objects: + *
      + *
    • LDAPLookup - Provides access to the CRISTAL directory. Find or + * search for Items or Agents. + *
    • EntityProxyManager - Gives a local proxy object for Entities found + * in LDAP. Execute activities in Items, query or subscribe to Entity data. + *
    • TransactionManager - Access to the configured CRISTAL databases + *
    • CorbaServer - Manages the memory pool of active Entities + *
    • mORB - the Orbacus CORBA ORB + *
    + * + * @author $Author: abranson $ $Date: 2005/10/12 12:51:54 $ + * @version $Revision: 1.17 $ + **************************************************************************/ + +public class Gateway +{ + static private Properties mC2KProps; + static private ModuleManager mModules; + static private org.omg.CORBA.ORB mORB; + static private LDAPLookup mLDAPLookup; + static private TransactionManager mStorage; + static private EntityProxyManager mProxyManager; + static private CorbaServer mCorbaServer; + static private SimpleTCPIPServer mHTTPServer; + + + + private Gateway() { } + + /** + * Initialises the Gateway and all of the client objects it holds, with + * the exception of the LDAPLookup, which is initialised during connect() + * + * @param props - java.util.Properties containing all application properties. + * If null, the java system properties are used + * @throws InvalidDataException - invalid properties caused a failure in initialisation + */ + static public void init(Properties props, boolean isServer) throws InvalidDataException { + + // if supplied props are null, use system props + if (props == null) props = System.getProperties(); + + // report version info + Logger.msg("Kernel version: "+Resource.getKernelVersion()); + + // init module manager + try { + mModules = new ModuleManager(ClassLoader.getSystemResources("module.xml"), isServer); + } catch (IOException e) { + Logger.error(e); + throw new InvalidDataException("Could not load module definitions. Classpath problem", ""); + } + + // Start with default props from kernel jar + try { + mC2KProps = FileStringUtility.loadConfigFile( Resource.getKernelResourceURL("textFiles/defaultConf.properties").toString()); + } catch (MalformedURLException ex) { + Logger.die("Default properties not found. Probable cause is missing resources"); + } + + // merge in module props + Properties moduleProperties = mModules.getAllModuleProperties(); + for (Enumeration e = moduleProperties.propertyNames(); e.hasMoreElements();) { + String propName = (String)e.nextElement(); + mC2KProps.put(propName, moduleProperties.get(propName)); + } + + // Overwrite with supplied props + for (Enumeration e = props.propertyNames(); e.hasMoreElements();) { + String propName = (String)e.nextElement(); + mC2KProps.put(propName, props.get(propName)); + } + + // dump properties + dumpC2KProps(7); + + // load kernel mapfiles + try { + CastorXMLUtility.loadMapsFrom(Resource.getKernelResourceURL("mapFiles/")); + } catch (MalformedURLException e1) { + throw new InvalidDataException("Invalid Resource Location", ""); + } + + //Initialise language file + String languageFile = getProperty("language.file"); + if (languageFile != null && languageFile.length() > 0) { + Language.isTranlated=true; + Language.mTableOfTranslation = FileStringUtility.loadLanguageFile(languageFile); + } + + // run module startup scripts + mModules.runScripts("startup"); + } + + /** + * Makes this process capable of creating and managing server entities. Runs the + * bootstrap to create the root LDAP contexts, initialises the CORBA server and + * time-out manager. + * + * @throws InvalidDataException - error initialising + */ + static public void startServer() throws InvalidDataException { + try { + // check top level LDAP contexts + mLDAPLookup.install(); + + // start entity proxy server + EntityProxyManager.initServer(); + + // Init ORB - set various config to sys properties + java.util.Properties sysProps = System.getProperties(); + String serverName = getProperty("ItemServer.name"); + if (serverName != null) + sysProps.put("ORBHost", serverName); + String serverPort = getProperty("ItemServer.iiop", "1500"); + sysProps.put("ORBPort", serverPort); + //TODO: externalize this (or replace corba completely) + sysProps.put("com.sun.CORBA.POA.ORBServerId", "1"); + sysProps.put("com.sun.CORBA.POA.ORBPersistentServerPort", serverPort); + + //Standard initialisation of the ORB + mORB = org.omg.CORBA.ORB.init(new String[0], sysProps); + + Logger.msg("Gateway.init() - ORB initialised. ORB is " + mORB.getClass().getName() ); + + // start corba server components + mCorbaServer = new CorbaServer(); + + // start checking bootstrap items + Bootstrap.run(); + + // register modules + mModules.registerModules(); + + } catch (Exception ex) { + Logger.error(ex); + Logger.die("Exception starting server components. Shutting down."); + } + + // start the http server +// try { +// int httpPort = Integer.parseInt(Gateway.getProperty("ItemServer.HTTP.port")); +// Logger.msg(2, "Starting HTTP Server on port "+httpPort); +// mHTTPServer = new SimpleTCPIPServer(httpPort, ItemHTTPBridge.class, 5); +// mHTTPServer.startListening(); +// } catch (NumberFormatException ex) { +// Logger.msg(3, "Invalid or no HTTP port defined. HTTP server not available."); +// } + + System.out.println("Server '"+Gateway.getCentreId()+"' initialised."); + } + + public static ModuleManager getModuleManager() { + return mModules; + } + + /** + * Connects to the LDAP server in an administrative context - using the admin username and + * password given in the LDAP.user and LDAP.password props of the kernel properties. + * + * @throws InvalidDataException - bad params + * @throws ClusterStorageException - error starting storages + */ + static public void connect() + throws InvalidDataException, + ClusterStorageException + { + LDAPProperties ldapProps = new LDAPProperties(); + + if( ldapProps.mHost != null && ldapProps.mPort != null && + ldapProps.mUser != null && ldapProps.mPassword != null ) + { + try + { + mLDAPLookup = new LDAPLookup(ldapProps); + } + catch (Exception ex) + { + Logger.error(ex); + throw new InvalidDataException("Cannot authenticate. Name and/or password invalid.", ""); + } + } + else + { + Logger.error("LDAP not configured properly."); + throw new InvalidDataException("Cannot authenticate. Name and/or password invalid.", ""); + } + + setup(); + } + + /** + * Authenticates a user and returns and AgentProxy on them without overriding the system LDAP context. + * Useful for handling multiple users in one context e.g. on a web server + * + * @param agentName - username + * @param agentPassword - password + * @return AgentProxy on that user + * @throws InvalidDataException + * @throws ObjectNotFoundException + */ + static public AgentProxy login(String agentName, String agentPassword) throws InvalidDataException, ObjectNotFoundException { + LDAPProperties ldapProps = new LDAPProperties(); + AgentPath agentPath; + try { + agentPath = mLDAPLookup.getRoleManager().getAgentPath(agentName); + } catch (Exception ex) { + Logger.error(ex); + throw new ObjectNotFoundException("Could not resolve agent", ""); + } + String agentDN = agentPath.getFullDN(); + ldapProps.mUser = agentDN; + ldapProps.mPassword = agentPassword; + + try { + LDAPLookup.createConnection(ldapProps); + return (AgentProxy)getProxyManager().getProxy(mLDAPLookup.getRoleManager().getAgentPath(agentName)); + } catch (Exception ex) { + Logger.error(ex); + throw new InvalidDataException("Could not log in", ""); + } + } + + + /** + * Logs into the LDAP server with the given username and password, and initialises the lookup. + * + * @param agentName - username + * @param agentPassword - password + * @return an AgentProxy on the requested user + * @throws InvalidDataException + */ + static public AgentProxy connect(String agentName, String agentPassword) + throws InvalidDataException + { + + LDAPProperties ldapProps = new LDAPProperties(); + if (ldapProps.mHost!=null && ldapProps.mPort!= null && ldapProps.mLocalPath!=null ) + { + try { + ldapProps.mUser = ""; + ldapProps.mPassword = ""; + mLDAPLookup = new LDAPLookup(ldapProps); + String agentDN = mLDAPLookup.getRoleManager().getAgentPath(agentName).getFullDN(); + + //found agentDN, try to log in with it + ldapProps.mUser = agentDN; + ldapProps.mPassword = agentPassword; + mLDAPLookup = new LDAPLookup(ldapProps); + + // find agent proxy + AgentPath agentPath = mLDAPLookup.getRoleManager().getAgentPath(agentName); + + if (agentPath!=null) + { + setup(); + return (AgentProxy) mProxyManager.getProxy(agentPath); + } + else + { + throw new InvalidDataException("The agentDN " +agentDN+ " is invalid.", ""); + } + } catch (ClusterStorageException e) { + throw new InvalidDataException(Language.translate("Error initialising storage")+Language.translate(". See log."), ""); + } catch (ObjectNotFoundException e) { + throw new InvalidDataException(Language.translate("Invalid username/password"), ""); + } catch (Exception e) { + throw new InvalidDataException(Language.translate("Could not log in")+": "+Language.translate(e.getMessage()), ""); + } + + } + else + { + throw new InvalidDataException("Cannot log in. Some connection properties are not set.", ""); + } + + } + + /** + * Initializes the storage and proxy manager, called during connect. + * + * @throws InvalidDataException + * @throws ClusterStorageException + */ + static private void setup() + throws InvalidDataException, + ClusterStorageException + { + + // Init storages + mStorage = new TransactionManager(); + mProxyManager = new EntityProxyManager(); + + } + + /** + * Shuts down all kernel api objects + */ + public static void close() + { + // run shutdown module scripts + mModules.runScripts("shutdown"); + + // shut down servers if running + if (mCorbaServer != null) + mCorbaServer.close(); + mCorbaServer = null; + if (mHTTPServer != null) + mHTTPServer.stopListening(); + mHTTPServer = null; + + // disconnect from storages + if (mStorage != null) + mStorage.close(); + mStorage = null; + + // disconnect from ldap + if (mLDAPLookup != null) + mLDAPLookup.disconnect(); + mLDAPLookup = null; + + // shut down proxy manager + if (mProxyManager != null) + mProxyManager.shutdown(); + mProxyManager = null; + EntityProxyManager.shutdownServer(); + + // close log consoles + Logger.closeConsole(); + + // finally, destroy the ORB + getORB().destroy(); + } + + static public org.omg.CORBA.ORB getORB() + { + if (mORB == null) + mORB = org.omg.CORBA.ORB.init(new String[0], null); + return mORB; + } + + static public LDAPLookup getLDAPLookup() + { + return mLDAPLookup; + } + + static public CorbaServer getCorbaServer() + { + return mCorbaServer; + } + + static public TransactionManager getStorage() + { + return mStorage; + } + + static public EntityProxyManager getProxyManager() + { + return mProxyManager; + } + + static public String getCentreId() { + return getProperty("LocalCentre"); + } + + static public String getProperty(String propName) { + return getProperty(propName, null); + } + + static public String getProperty(String propName, String defaultValue) { + if (mC2KProps == null) return defaultValue; + return mC2KProps.getProperty(propName, defaultValue); + } + + static public void setProperty(String propName, String propValue) { + if (mC2KProps == null) return; + mC2KProps.put(propName, propValue); + } + + static public Enumeration propertyNames() { + return mC2KProps.propertyNames(); + } + + static public void dumpC2KProps(int logLevel) { + if (!Logger.doLog(logLevel)) return; + Logger.msg(logLevel, "C2K Properties:"); + for (Enumeration e = propertyNames(); e.hasMoreElements();) { + String name = (String) e.nextElement(); + Logger.msg(" "+name+": "+getProperty(name)); + } + } +} + diff --git a/src/main/java/com/c2kernel/process/ItemHTTPBridge.java b/src/main/java/com/c2kernel/process/ItemHTTPBridge.java new file mode 100644 index 0000000..40f48f7 --- /dev/null +++ b/src/main/java/com/c2kernel/process/ItemHTTPBridge.java @@ -0,0 +1,52 @@ +package com.c2kernel.process; + +import java.util.StringTokenizer; + +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.server.HTTPRequestHandler; + +/* QueryData over HTTP Socket Handler + * Processes an HTTP request consisting of // + * and returns that kernel object as XML + * Currently supports GET requests. + * REVISIT: POST calls Item.request() + */ + +public class ItemHTTPBridge extends HTTPRequestHandler { + + public ItemHTTPBridge() { } + + @Override + public String getName() { + return "Item HTTP Server"; + } + + @Override + public String processRequest() { + System.out.println("ItemHTTPBridge::ProcessRequest()"); + StringTokenizer tok = new StringTokenizer(resource, "?"); + //String itemPath = tok.nextToken(); + String query = tok.nextToken(); + int sysKey = -1; + //Path path = Gateway.getLDAPLookup().; + if (method.equals("GET")) { + try { + //DomainPath domPath = new DomainPath(itemPath); + //EntityPath entityPath = domPath.getEntity(); + + if (sysKey > -1) { + C2KLocalObject response = Gateway.getStorage().get(sysKey, query, null); + return CastorXMLUtility.marshall(response); + } + else + return error("404 Not Found", "The entity "+sysKey+" you requested was not found."); + } + catch (Exception e) { + return error("400 Bad Request", "Usage: GET <path to item>?<path to kernel object>
    "+e.getClass().getName()); + } + } + return(super.processRequest()); + } + +} diff --git a/src/main/java/com/c2kernel/process/Module.java b/src/main/java/com/c2kernel/process/Module.java new file mode 100644 index 0000000..e2a4f2e --- /dev/null +++ b/src/main/java/com/c2kernel/process/Module.java @@ -0,0 +1,303 @@ +package com.c2kernel.process; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.events.Event; +import com.c2kernel.events.History; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.Dependency; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.DependencyMember; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.NewAgent; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.NewItem; +import com.c2kernel.lifecycle.instance.predefined.entitycreation.Property; +import com.c2kernel.lifecycle.instance.stateMachine.States; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.persistency.outcome.Viewpoint; +import com.c2kernel.scripting.ErrorInfo; +import com.c2kernel.scripting.Script; +import com.c2kernel.scripting.ScriptingEngineException; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; +import com.c2kernel.utils.Resource; + +public class Module { + + private final String ns, name, desc, version; + private String resURL; + private final ArrayList dependency = new ArrayList(); + private final Properties clientProps = new Properties(); + private final Properties serverProps = new Properties(); + private final HashMap clientScripts = new HashMap(); + private final HashMap serverScripts = new HashMap(); + private final ArrayList imports = new ArrayList(); + private static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + private final DocumentBuilder parser; + + static { + dbf.setValidating(false); + dbf.setNamespaceAware(false); + } + + public Module(String moduleXML) throws Exception { + parser = dbf.newDocumentBuilder(); + Document moduleDOM = parser.parse(new InputSource(new StringReader(moduleXML))); + + Element root = (Element)moduleDOM.getElementsByTagName("CristalModule").item(0); + + // Get module metadata + ns = root.getAttribute("ns"); + name = root.getAttribute("name"); + Element info = (Element)moduleDOM.getElementsByTagName("Info").item(0); + desc = ((Text)info.getElementsByTagName("Description").item(0).getFirstChild()).getData(); + version = ((Text)info.getElementsByTagName("Version").item(0).getFirstChild()).getData(); + NodeList nl = info.getElementsByTagName("Dependency"); + for (int i=0; i0) { + resURL = ((Text)nl.item(0).getFirstChild()).getData(); + Resource.addModuleBaseURL(ns, resURL); + } + + // Get config properties + nl = root.getElementsByTagName("Config"); + for (int i=0; i0) { + Element impElem = (Element)nl.item(0); + nl = impElem.getChildNodes(); + for (int i=0; i scripts = isServer?serverScripts:clientScripts; + Script thisScript = scripts.get(event); + if (thisScript == null) return null; + try { + Object result = thisScript.execute(); + if (result instanceof ErrorInfo) + return (ErrorInfo)result; + else + return new ErrorInfo(result.toString()); + } catch (ScriptingEngineException ex) { + Logger.error(ex); + return new ErrorInfo("Error running "+event+" script in module "+ns); + } + } + + public void importAll(ItemProxy serverEntity) { + for (ModuleImport thisImp : imports) { + if (thisImp instanceof ModuleResource) { + ModuleResource thisRes = (ModuleResource)thisImp; + try { + Bootstrap.verifyResource(ns, thisRes.importName, thisRes.resourceType, Resource.getTextResource(ns, thisRes.resourceLocation)); + } catch (Exception ex) { + Logger.error(ex); + } + } + else if (thisImp instanceof ModuleItem) { + ModuleItem thisItem = (ModuleItem)thisImp; + try { + NewItem item = new NewItem(thisItem.importName, "/desc/"+ns, thisItem.workflow); + item.propertyList = thisItem.props; + DomainPath itemPath = new DomainPath(new DomainPath(item.initialPath), item.name); + if (itemPath.exists()) continue; + serverEntity.requestAction( + Gateway.getLDAPLookup().getRoleManager().getAgentPath("system").getSysKey(), + "workflow/predefined/CreateNewItem", + Transitions.DONE, + CastorXMLUtility.marshall(item)); + Logger.msg("Module.importAll() - Created item: "+thisItem.importName); + ItemProxy newProxy = (ItemProxy)Gateway.getProxyManager().getProxy(itemPath); + History hist = new History(newProxy.getSystemKey(), newProxy); + for (String thisView : thisItem.outcomes.keySet()) { + String[] info = thisView.split(":"); + int version = Integer.parseInt(info[1]); + String data = Resource.getTextResource(ns, thisItem.outcomes.get(thisView)); + Event newEvent = hist.addEvent("system", "Admin", Transitions.DONE, "Import", "Import", "Import", States.FINISHED); + Outcome newOutcome = new Outcome(newEvent.getID(), data, info[0], version); + Viewpoint newLastView = new Viewpoint(newProxy.getSystemKey(), info[0], info[2], version, newEvent.getID()); + Gateway.getStorage().put(newProxy.getSystemKey(), newOutcome, newProxy); + Gateway.getStorage().put(newProxy.getSystemKey(), newLastView, newProxy); + } + for (Dependency thisDep : thisItem.deps) { + Gateway.getStorage().put(newProxy.getSystemKey(), thisDep.create(), newProxy); + } + Gateway.getStorage().commit(newProxy); + } catch (Exception ex) { + Logger.error("Error importing item "+thisItem.importName+" from module "+name); + Logger.error(ex); + } + } + else if (thisImp instanceof ModuleAgent) { + ModuleAgent thisAgent = (ModuleAgent)thisImp; + try { + Gateway.getLDAPLookup().getRoleManager().getAgentPath(thisAgent.importName); + Logger.msg(3, "Module.importAll() - User '"+thisAgent.importName+"' found."); + return; + } catch (ObjectNotFoundException ex) { } + Logger.msg("Module.importAll() - User '"+thisAgent.importName+"' not found. Creating."); + + NewAgent agent = new NewAgent(thisAgent.importName, thisAgent.password); + agent.roles = thisAgent.roles; + try { + serverEntity.requestAction( + Gateway.getLDAPLookup().getRoleManager().getAgentPath("system").getSysKey(), + "workflow/predefined/CreateNewAgent", + Transitions.DONE, + CastorXMLUtility.marshall(agent)); + } catch (Exception ex) { + Logger.error("Error importing agent "+thisAgent.importName+" from module "+name); + Logger.error(ex); + } + } + } + } + + public Properties getClientProperties() { + return clientProps; + } + + public Properties getServerProperties() { + return serverProps; + } + + public String getNs() { + return ns; + } + public String getName() { + return name; + } + public String getDesc() { + return desc; + } + public String getVersion() { + return version; + } + public String getResURL() { + return resURL; + } + public ArrayList getDependencies() { + return dependency; + } + public boolean hasDependency(String dep) { + return dependency.contains(dep); + } + + public abstract class ModuleImport { + String importName; + } + + public class ModuleResource extends ModuleImport { + String resourceType; + String resourceLocation; + } + + public class ModuleItem extends ModuleImport { + ArrayList props = new ArrayList(); + HashMap outcomes = new HashMap(); + ArrayList deps = new ArrayList(); + String workflow; + } + + public class ModuleAgent extends ModuleImport { + String password; + ArrayList roles = new ArrayList(); + } +} \ No newline at end of file diff --git a/src/main/java/com/c2kernel/process/ModuleManager.java b/src/main/java/com/c2kernel/process/ModuleManager.java new file mode 100644 index 0000000..e7be9e8 --- /dev/null +++ b/src/main/java/com/c2kernel/process/ModuleManager.java @@ -0,0 +1,82 @@ +package com.c2kernel.process; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Properties; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.lookup.DomainPath; +import com.c2kernel.utils.FileStringUtility; +import com.c2kernel.utils.Logger; + +public class ModuleManager { + ArrayList modules = new ArrayList(); + Properties props = new Properties(); + boolean isServer; + + public ModuleManager(Enumeration moduleEnum, boolean isServer) { + this.isServer = isServer; + ArrayList loadedModules = new ArrayList(); + while(moduleEnum.hasMoreElements()) { + URL newModuleURL = moduleEnum.nextElement(); + try { + Module newModule = new Module(FileStringUtility.url2String(newModuleURL)); + modules.add(newModule); + loadedModules.add(newModule.getName()); + Properties modProp = isServer?newModule.getServerProperties():newModule.getClientProperties(); + for (Enumeration e = modProp.propertyNames(); e.hasMoreElements();) { + String propName = (String)e.nextElement(); + props.put(propName, modProp.get(propName)); + } + } catch (Exception e) { + Logger.error("Could not load module description from "+newModuleURL); + Logger.error(e); + } + } + + Logger.debug(5, "Checking dependencies"); + boolean depFailed = false; + for (Module thisMod : modules) { + ArrayList deps = thisMod.getDependencies(); + for (String dep : deps) { + if (!loadedModules.contains(dep)) { + Logger.error("UNMET MODULE DEPENDENCY: "+thisMod.getName()+" requires "+dep); + depFailed = true; + } + } + } + if (depFailed) Logger.die("Unmet module dependencies. Cannot continue"); + } + + public String getModuleVersions() { + StringBuffer ver = new StringBuffer(); + for (Module thisMod : modules) { + if (ver.length()>0) ver.append(";"); + ver.append(thisMod.getName()+"("+thisMod.getVersion()+")"); + } + return ver.toString(); + } + + + public Properties getAllModuleProperties() { + return props; + } + + public void runScripts(String event) { + for (Module thisMod : modules) { + thisMod.runScript(event, isServer); + } + } + + public void registerModules() throws ObjectNotFoundException { + ItemProxy serverEntity = (ItemProxy)Gateway.getProxyManager().getProxy(new DomainPath("/servers/"+Gateway.getProperty("ItemServer.name"))); + Logger.debug(3, "Registering modules"); + for (Module thisMod : modules) { + Logger.debug(4, "Registering module "+thisMod.getName()); + thisMod.importAll(serverEntity); + Logger.msg("Module "+thisMod.getName()+" registered"); + } + } +} diff --git a/src/main/java/com/c2kernel/process/StandardClient.java b/src/main/java/com/c2kernel/process/StandardClient.java new file mode 100644 index 0000000..f6f48ed --- /dev/null +++ b/src/main/java/com/c2kernel/process/StandardClient.java @@ -0,0 +1,18 @@ +/************************************************************************** + * StandardClient + * + * $Revision: 1.7 $ + * $Date: 2003/04/25 16:17:12 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.process; + +abstract public class StandardClient extends AbstractMain +{ + + //TODO: Auto-update from server + +} diff --git a/src/main/java/com/c2kernel/process/StandardServer.java b/src/main/java/com/c2kernel/process/StandardServer.java new file mode 100644 index 0000000..6804da5 --- /dev/null +++ b/src/main/java/com/c2kernel/process/StandardServer.java @@ -0,0 +1,127 @@ +/************************************************************************** + * StandardServer + * + * $Revision: 1.47 $ + * $Date: 2005/04/28 13:49:43 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.process; + +import org.tanukisoftware.wrapper.WrapperListener; +import org.tanukisoftware.wrapper.WrapperManager; + +import com.c2kernel.utils.Logger; + +/************************************************************************** + * Base class for all servers i.e. c2k processes that serve Entities + * + * @author $Author: abranson $ $Date: 2005/04/28 13:49:43 $ + * @version $Revision: 1.47 $ + **************************************************************************/ +public class StandardServer extends AbstractMain implements WrapperListener +{ + protected static StandardServer server; + + + /************************************************************************** + * C2KRootPOA suitable for Factory objects + **************************************************************************/ + + + + + + /************************************************************************** + * void StandardInitalisation( String[] ) + * + * Set-up calls to ORB, POA and Factorys, both optional and required. + **************************************************************************/ + protected void standardInitialisation( String[] args ) + throws Exception + { + // read args and init Gateway + Gateway.init(readC2KArgs(args), true); + + // connect to LDAP as root + Gateway.connect(); + + //start console + Logger.initConsole("ItemServer"); + + //initialize the server objects + Gateway.startServer(); + + Logger.msg(5, "StandardServer::standardInitialisation - complete."); + + } + + + /************************************************************************** + * Sets up and runs and item server + **************************************************************************/ + @Override + public Integer start(String[] args) + { + try + { + //initialise everything + standardInitialisation( args ); + } + catch( Exception ex ) + { + Logger.error(ex); + Logger.die("Startup failed"); + } + return null; + } + + public static void main(String[] args) { + server = new StandardServer(); + AbstractMain.runningAsWrapper = true; + WrapperManager.start( server, args ); + } + + /** + * + */ + @Override + public void controlEvent(int event) { + if (WrapperManager.isControlledByNativeWrapper()) { + // The Wrapper will take care of this event + } else { + // We are not being controlled by the Wrapper, so + // handle the event ourselves. + if ((event == WrapperManager.WRAPPER_CTRL_C_EVENT) || + (event == WrapperManager.WRAPPER_CTRL_CLOSE_EVENT) || + (event == WrapperManager.WRAPPER_CTRL_SHUTDOWN_EVENT)){ + WrapperManager.stop(0); + } + } + + } + + /************************************************************************** + * Closes all listeners, quits the VM. + * This method should be called to kill the server process + * e.g. from the NT service wrapper + **************************************************************************/ + @Override + public int stop(int arg0) { + try + { + Gateway.close(); + } + catch( Exception ex ) + { + Logger.error(ex); + return 1; + } + + Logger.msg("StandardServer::shutdown - complete. "); + return 0; + } + +} diff --git a/src/main/java/com/c2kernel/process/UserCodeProcess.java b/src/main/java/com/c2kernel/process/UserCodeProcess.java new file mode 100644 index 0000000..7779802 --- /dev/null +++ b/src/main/java/com/c2kernel/process/UserCodeProcess.java @@ -0,0 +1,234 @@ +package com.c2kernel.process; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; + +import com.c2kernel.common.InvalidDataException; +import com.c2kernel.common.InvalidTransitionException; +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.AgentProxy; +import com.c2kernel.entity.proxy.EntityProxyObserver; +import com.c2kernel.entity.proxy.MemberSubscription; +import com.c2kernel.lifecycle.instance.stateMachine.Transitions; +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.31 $ + * $Date: 2004/10/21 08:02:19 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class UserCodeProcess extends StandardClient implements EntityProxyObserver, Runnable { + protected AgentProxy agent; + static boolean active = true; + ArrayList ignoredPaths = new ArrayList(); + HashMap jobs; + + public UserCodeProcess(String agentName, String agentPass) { + // login - try for a while in case server hasn't imported our user yet + for (int i=1;i<6;i++) { + try { + Logger.msg("Login attempt "+i+" of 5"); + agent = Gateway.connect(agentName, agentPass); + break; + } catch (InvalidDataException ex) { + Logger.error("Could not log in."); + Logger.error(ex); + try { + Thread.sleep(5000); + } catch (InterruptedException ex2) { } + } + } + System.out.println(getDesc()+" initialised for " + agentName); + } + + @Override + public void run() { + Thread.currentThread().setName("Usercode Process"); + jobs = new HashMap(); + // subscribe to job list + agent.subscribe(new MemberSubscription(this, ClusterStorage.JOB, true)); + while (active) { + Job thisJob = null; + synchronized (jobs) { + if (jobs.size() > 0) { + thisJob = getJob(jobs, Transitions.COMPLETE); + if (thisJob == null) + thisJob = getJob(jobs, Transitions.START); + if (thisJob == null) + thisJob = getJob(jobs, Transitions.SUSPEND); + if (thisJob == null) + thisJob = getJob(jobs, Transitions.RESUME); + + if (thisJob == null) { + Logger.error("No supported jobs, but joblist is not empty! Discarding remaining jobs"); + jobs.clear(); + } + else + jobs.remove(ClusterStorage.getPath(thisJob)); + } + } + + if (thisJob != null) { + String jobKey = thisJob.getItemSysKey()+":"+thisJob.getStepPath(); + try { + if (thisJob.getPossibleTransition()==Transitions.START) { + Logger.msg(5, "Testing start conditions"); + boolean start = assessStartConditions(thisJob); + if (start) { + Logger.msg(5, "Attempting to start"); + agent.execute(thisJob); + } + else { + Logger.msg(5, "Start conditions failed "+thisJob.getStepName()+" in "+thisJob.getItemSysKey()); + } + } + else if (thisJob.getPossibleTransition()==Transitions.COMPLETE) { + Logger.msg(5, "Executing logic"); + runUCLogic(thisJob); + if (ignoredPaths.contains(jobKey)) + ignoredPaths.remove(jobKey); + } + else if (thisJob.getPossibleTransition()==Transitions.SUSPEND) { + if (ignoredPaths.contains(jobKey)) + agent.execute(thisJob); + } + else if (thisJob.getPossibleTransition()==Transitions.RESUME) { + if (!ignoredPaths.contains(jobKey)) + agent.execute(thisJob); + } + } catch (InvalidTransitionException ex) { + // must have already been done by someone else - ignore + } catch (Throwable ex) { + Logger.error("Error executing "+Transitions.getTransitionName(thisJob.getPossibleTransition())+" job:"); + Logger.error(ex); + ignoredPaths.add(jobKey); + } + } + try { + synchronized (jobs) { + if (jobs.size() == 0) { + Logger.msg("Sleeping"); + while (active && jobs.size() == 0) + jobs.wait(2000); + } + } + } catch (InterruptedException ex) { } + } + + // shut down + try + { + Gateway.close(); + } + catch( Exception ex ) + { + Logger.error(ex); + } + } + + private static Job getJob(HashMap jobs, int transition) { + for (C2KLocalObject c2kLocalObject : jobs.values()) { + Job thisJob = (Job)c2kLocalObject; + if (thisJob.getPossibleTransition() == transition) { + Logger.msg(1,"================================================================="); + Logger.msg(1, "Got "+Transitions.getTransitionName(transition)+" job for "+thisJob.getStepName()+" in "+thisJob.getItemSysKey()); + return thisJob; + } + } + return null; + } + + public boolean assessStartConditions(Job job) { + // default implementation - has no start conditions. + return true; + } + + public void runUCLogic(Job job) throws Exception { + // default implementation - the agent will execute any scripts defined when we execute + agent.execute(job); + } + + + /** + * Receives job from the AgentProxy. Reactivates thread if sleeping. + */ + @Override + public void add(Job contents) { + synchronized(jobs) { + Logger.msg(7, "Adding "+ClusterStorage.getPath(contents)); + jobs.put(ClusterStorage.getPath(contents), contents); + jobs.notify(); + } + + } + + @Override + public void control(String control, String msg) { + if (control == MemberSubscription.ERROR) + Logger.error("Error in job subscription: "+msg); + } + + /** + * Removes job removal notification from the AgentProxy. + */ + @Override + public void remove(String id) { + synchronized(jobs) { + Logger.msg(7, "Deleting "+id); + jobs.remove(id); + } + } + + public static UserCodeProcess getInstance() throws UnknownHostException { + return new UserCodeProcess(InetAddress.getLocalHost().getHostName(), "uc"); + } + + static public void main(String[] args) + { + int status = 0; + + try + { + Gateway.init(readC2KArgs(args), false); + UserCodeProcess proc = getInstance(); + new Thread(proc).start(); + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + @Override + public void run() { + shutdown(); + } + })); + } + catch( Exception ex ) + { + Logger.error(ex); + + try + { + Gateway.close(); + } + catch(Exception ex1) + { + Logger.error(ex1); + } + status = 1; + System.exit(status); + } + } + + public String getDesc() { + return("Usercode Process"); + } + + public static void shutdown() { + active = false; + } + +} diff --git a/src/main/java/com/c2kernel/property/Property.java b/src/main/java/com/c2kernel/property/Property.java new file mode 100644 index 0000000..3022cc5 --- /dev/null +++ b/src/main/java/com/c2kernel/property/Property.java @@ -0,0 +1,85 @@ +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2003/10/03 12:31:28 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.property; + +import com.c2kernel.entity.C2KLocalObject; +import com.c2kernel.persistency.ClusterStorage; + + +public class Property implements C2KLocalObject +{ + private String mName; + private String mValue; + + + /************************************************************************** + * + **************************************************************************/ + public Property() + { + setName( "" ); + setValue( "" ); + } + + + /************************************************************************** + * + **************************************************************************/ + public Property( String name, String value ) + { + setName( name ); + setValue( value ); + } + + /************************************************************************** + * + **************************************************************************/ + @Override + public void setName(String name) + { + mName = name; + } + + + /************************************************************************** + * + **************************************************************************/ + @Override + public String getName() + { + return mName; + } + + + /************************************************************************** + * + **************************************************************************/ + public void setValue( String value ) + { + mValue = value; + } + + + /************************************************************************** + * + **************************************************************************/ + public String getValue() + { + return mValue; + } + /** + * @see com.c2kernel.entity.C2KLocalObject#getClusterType() + */ + @Override + public String getClusterType() { + return ClusterStorage.PROPERTY; + } + +} diff --git a/src/main/java/com/c2kernel/property/PropertyArrayList.java b/src/main/java/com/c2kernel/property/PropertyArrayList.java new file mode 100644 index 0000000..f59b2d5 --- /dev/null +++ b/src/main/java/com/c2kernel/property/PropertyArrayList.java @@ -0,0 +1,29 @@ +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2003/06/20 11:44:30 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.property; + +import java.util.ArrayList; + +import com.c2kernel.utils.CastorArrayList; + +public class PropertyArrayList extends CastorArrayList +{ + public PropertyArrayList() + { + super(); + } + + public PropertyArrayList(ArrayList aList) + { + super(aList); + } + + +} diff --git a/src/main/java/com/c2kernel/property/PropertyDescription.java b/src/main/java/com/c2kernel/property/PropertyDescription.java new file mode 100644 index 0000000..cd3b93c --- /dev/null +++ b/src/main/java/com/c2kernel/property/PropertyDescription.java @@ -0,0 +1,77 @@ +/************************************************************************** + * + * $Revision: 1.5 $ + * $Date: 2003/05/16 11:36:47 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.property; + +public class PropertyDescription +{ + private String mName=null; + private String mDefaultValue=null; + private boolean mIsClassIdentifier=false; + private boolean mIsMutable=false; + + + public PropertyDescription() + { + } + + public PropertyDescription(String name, String defaultValue, boolean isClassIdentifier, boolean isMutable ) + { + setName(name); + setDefaultValue(defaultValue); + setIsClassIdentifier(isClassIdentifier); + setIsMutable(isMutable); + } + + public void setName(String name) + { + mName = name; + } + + public void setIsClassIdentifier(boolean classId) + { + mIsClassIdentifier = classId; + } + + public void setDefaultValue(String defaultValue) + { + mDefaultValue = defaultValue; + } + + public void setIsMutable(boolean mutable) + { + mIsMutable = mutable; + } + + public String getName() + { + return mName; + } + + public boolean getIsClassIdentifier() + { + return mIsClassIdentifier; + } + + public String getDefaultValue() + { + return mDefaultValue; + } + + public boolean getIsMutable() + { + return mIsMutable; + } + + public Property getProperty() + { + return new Property(mName,mDefaultValue); + } + +} diff --git a/src/main/java/com/c2kernel/property/PropertyDescriptionList.java b/src/main/java/com/c2kernel/property/PropertyDescriptionList.java new file mode 100644 index 0000000..a6c68e2 --- /dev/null +++ b/src/main/java/com/c2kernel/property/PropertyDescriptionList.java @@ -0,0 +1,63 @@ +/************************************************************************** + * + * $Revision: 1.3 $ + * $Date: 2003/07/18 12:43:53 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.property; + +import java.util.ArrayList; + +import com.c2kernel.utils.CastorArrayList; + +public class PropertyDescriptionList extends CastorArrayList +{ + public PropertyDescriptionList() + { + super(); + } + + public PropertyDescriptionList(ArrayList aList) + { + super(aList); + } + + public String getClassProps() { + StringBuffer props = new StringBuffer(); + for (Object name : list) { + PropertyDescription element = (PropertyDescription)name; + if (element.getIsClassIdentifier()) { + if (props.length()>0) + props.append(","); + props.append(element.getName()); + } + } + return props.toString(); + } + + public boolean setDefaultValue(String name, String value) { + for (Object name2 : list) { + PropertyDescription element = (PropertyDescription)name2; + if (element.getName().equals(name)) { + element.setDefaultValue(value); + return true; + } + } + return false; + } + + public PropertyArrayList instanciate() { + PropertyArrayList props = new PropertyArrayList(); + for (int i = 0; i < list.size(); i++) { + PropertyDescription pd = list.get(i); + String propName = pd.getName(); + String propVal = pd.getDefaultValue(); + props.list.add( new Property(propName, propVal)); + } + return props; + } + +} diff --git a/src/main/java/com/c2kernel/property/PropertyUtility.java b/src/main/java/com/c2kernel/property/PropertyUtility.java new file mode 100644 index 0000000..f8e714c --- /dev/null +++ b/src/main/java/com/c2kernel/property/PropertyUtility.java @@ -0,0 +1,83 @@ +/************************************************************************** + * + * $Revision: 1.4 $ + * $Date: 2004/10/21 08:02:26 $ + * + * Copyright (C) 2001 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ + +package com.c2kernel.property; + +import java.util.ArrayList; +import java.util.Iterator; + +import com.c2kernel.persistency.ClusterStorage; +import com.c2kernel.persistency.outcome.Outcome; +import com.c2kernel.process.Gateway; +import com.c2kernel.utils.CastorHashMap; +import com.c2kernel.utils.CastorXMLUtility; +import com.c2kernel.utils.Logger; + + +public class PropertyUtility +{ + static public String getValue(ArrayList pdlist, String name) + { + for (PropertyDescription pd : pdlist) { + if ( name.equalsIgnoreCase(pd.getName()) ) + return pd.getDefaultValue(); + } + return null; + } + + static public String getNames(ArrayList pdlist) + { + StringBuffer names = new StringBuffer(); + for (PropertyDescription value : pdlist) + names.append( value.getDefaultValue()).append(" "); + return names.toString(); + } + + static public String getClassIdNames(ArrayList pdlist) + { + StringBuffer names = new StringBuffer(); + + for (Iterator iter = pdlist.iterator(); iter.hasNext();) { + PropertyDescription pd = iter.next(); + if (pd.getIsClassIdentifier()) + names.append(pd.getName()); + if (iter.hasNext()) + names.append(","); + } + return names.toString(); + } + + + static public PropertyDescriptionList getPropertyDescriptionOutcome(int entityKey) + { + try + { + Outcome outc = (Outcome) Gateway.getStorage().get(entityKey, ClusterStorage.VIEWPOINT+"/PropertyDescription/last/data", null); + return (PropertyDescriptionList)CastorXMLUtility.unmarshall(outc.getData()); + } + catch (Exception ex) + { + Logger.error(ex); + return null; + } + } + + static public CastorHashMap createProperty(PropertyDescriptionList pdList) + { + CastorHashMap props = new CastorHashMap(); + for (int i=0; i< pdList.list.size();i++) + { + PropertyDescription pd = pdList.list.get(i); + if (pd.getIsClassIdentifier()) + props.put(pd.getName(),pd.getDefaultValue()); + } + return props; + } + +} diff --git a/src/main/java/com/c2kernel/scripting/ErrorInfo.java b/src/main/java/com/c2kernel/scripting/ErrorInfo.java new file mode 100644 index 0000000..26c0384 --- /dev/null +++ b/src/main/java/com/c2kernel/scripting/ErrorInfo.java @@ -0,0 +1,46 @@ +package com.c2kernel.scripting; + +import java.util.ArrayList; + +/************************************************************************** + * + * $Revision: 1.2 $ + * $Date: 2003/06/06 11:37:45 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class ErrorInfo { + ArrayList msg; + boolean fatal = false; + + public ErrorInfo() { + super(); + msg = new ArrayList(); + } + + public ErrorInfo(String error) { + this(); + msg.add(error); + } + + public void addError(String error) { + msg.add(error); + } + + public String getErrors() { + StringBuffer err = new StringBuffer(); + for (String element : msg) { + err.append(element+"\n"); + } + return err.toString(); + } + + public void setFatal() { + fatal=true; + } + + public boolean getFatal() { + return fatal; + } +} diff --git a/src/main/java/com/c2kernel/scripting/Parameter.java b/src/main/java/com/c2kernel/scripting/Parameter.java new file mode 100644 index 0000000..ed9a963 --- /dev/null +++ b/src/main/java/com/c2kernel/scripting/Parameter.java @@ -0,0 +1,52 @@ +package com.c2kernel.scripting; + + +/************************************************************************** +* Place holder for the Parameter details to be passed to the script. +**************************************************************************/ +public class Parameter { + + private String name; + private Class type; + private boolean initialised=false; + + public Parameter(String name) { + this.name = name; + } + + public Parameter(String name, Class type) { + this.name = name; + this.type = type; + } + + public void setName(String n) + { + name=n; + } + + public String getName() + { + return name; + } + + public void setType(Class t) + { + type=t; + } + + public Class getType() + { + return type; + } + + public void setInitialised(boolean state) + { + initialised=state; + } + + public boolean getInitialised() + { + return initialised; + } + +} diff --git a/src/main/java/com/c2kernel/scripting/ParameterException.java b/src/main/java/com/c2kernel/scripting/ParameterException.java new file mode 100644 index 0000000..b191908 --- /dev/null +++ b/src/main/java/com/c2kernel/scripting/ParameterException.java @@ -0,0 +1,20 @@ +package com.c2kernel.scripting; + +public class ParameterException extends ScriptingEngineException { + + /** + * Creates new ParameterException without detail message. + */ + public ParameterException() { + } + + /** + * Constructs an ParameterException with the specified detail message. + * @param msg the detail message. + */ + public ParameterException(String msg) { + super(msg); + } +} + + diff --git a/src/main/java/com/c2kernel/scripting/Script.java b/src/main/java/com/c2kernel/scripting/Script.java new file mode 100644 index 0000000..7e40003 --- /dev/null +++ b/src/main/java/com/c2kernel/scripting/Script.java @@ -0,0 +1,456 @@ +package com.c2kernel.scripting; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.script.Bindings; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptEngineManager; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.InputSource; + +import com.c2kernel.common.ObjectNotFoundException; +import com.c2kernel.entity.agent.Job; +import com.c2kernel.entity.proxy.AgentProxy; +import com.c2kernel.entity.proxy.ItemProxy; +import com.c2kernel.utils.LocalObjectLoader; +import com.c2kernel.utils.Logger; + +/************************************************************************** + * + * $Revision: 1.25 $ + * $Date: 2005/10/05 07:39:37 $ + * + * Copyright (C) 2003 CERN - European Organization for Nuclear Research + * All rights reserved. + **************************************************************************/ +public class Script +{ + String mScript = ""; + String mName; + String mVersion; + HashMap mInputParams = new HashMap(); + HashMap mAllInputParams = new HashMap(); + HashMap mOutputParams = new HashMap(); + ArrayList