From 0dfa7ff965ae1a37f278c847960eefec34b2a61c Mon Sep 17 00:00:00 2001 From: "Achim D. Brucker" Date: Sun, 17 May 2015 21:02:17 +0200 Subject: [PATCH] Renamed CSVM-Designer to CSVM-Modelling-and-Validation. --- CITATION | 162 + LICENSE | 202 + README.md | 44 + examples/CaseStudyC/Get Civil.activiti | 739 + examples/CaseStudyC/Get Civil.png | Bin 0 -> 26009 bytes examples/CaseStudyC/Get Legal Info.activiti | 470 + examples/CaseStudyC/Get Legal Info.png | Bin 0 -> 15562 bytes examples/CaseStudyC/Get Lots.activiti | 223 + examples/CaseStudyC/Get Lots.png | Bin 0 -> 9184 bytes examples/CaseStudyC/Get Solicitor.activiti | 739 + examples/CaseStudyC/Get Solicitor.png | Bin 0 -> 25562 bytes examples/CaseStudyC/PublishLot.activiti | 482 + examples/CaseStudyC/PublishLot.png | Bin 0 -> 17740 bytes examples/CaseStudyC/RequestLot.activiti | 546 + examples/CaseStudyC/RequestLot.png | Bin 0 -> 24490 bytes examples/CaseStudyC/Select Lot.activiti | 541 + examples/CaseStudyC/Select Lot.png | Bin 0 -> 18193 bytes .../JobApplication/JobApplication.activiti | 950 + examples/JobApplication/JobApplication.png | Bin 0 -> 85670 bytes .../generated/JobApplication.aslan | 101 + .../generated/JobApplication.res | 455 + .../generated/JobApplication.result | 77 + .../generated/JobApplication.sate | 727 + .../CreditWorthinessService.java | 59 + .../LoanOrigination/LoanOrigination.activiti | 1129 + examples/LoanOrigination/LoanOrigination.png | Bin 0 -> 67909 bytes .../generated/LoanOrigination.aslan | 105 + .../generated/LoanOrigination.res | 476 + .../generated/LoanOrigination.result | 80 + .../generated/LoanOrigination.sate | 757 + examples/OrderPlacement/.access^ | 0 .../OrderPlacementProcess.activiti | 625 + .../OrderPlacementProcess.bpmn20.xml | 121 + .../OrderPlacement/OrderPlacementProcess.png | Bin 0 -> 16036 bytes examples/TravelApproval/ResultSender.java | 27 + .../TravelApproval/TravelApproval.activiti | 609 + examples/TravelApproval/TravelApproval.png | Bin 0 -> 33651 bytes .../generated/TravelApproval.aslan | 74 + .../generated/TravelApproval.res | 266 + .../generated/TravelApproval.result | 50 + .../generated/TravelApproval.sate | 427 + examples/misc/ASLanSoDDemo.activiti | 197 + examples/misc/AdvancedSoDDemo.activiti | 771 + src/.gitignore | 5 + .../.settings/org.eclipse.jdt.core.prefs | 12 + src/com.sun.xacml/pom.xml | 66 + .../java/com/sun/xacml/AbstractPolicy.java | 820 + .../com/sun/xacml/BasicEvaluationCtx.java | 1154 + .../com/sun/xacml/ConfigurationStore.java | 1408 + .../main/java/com/sun/xacml/Constants.java | 262 + .../java/com/sun/xacml/EvaluationCtx.java | 342 + .../src/main/java/com/sun/xacml/Indenter.java | 139 + .../main/java/com/sun/xacml/MatchElement.java | 11 + .../main/java/com/sun/xacml/MatchResult.java | 130 + .../main/java/com/sun/xacml/Obligation.java | 369 + .../src/main/java/com/sun/xacml/PDP.java | 480 + .../main/java/com/sun/xacml/PDPConfig.java | 185 + .../java/com/sun/xacml/ParsingException.java | 105 + .../src/main/java/com/sun/xacml/Policy.java | 819 + .../java/com/sun/xacml/PolicyMetaData.java | 306 + .../java/com/sun/xacml/PolicyReference.java | 647 + .../main/java/com/sun/xacml/PolicySet.java | 696 + .../java/com/sun/xacml/PolicyTreeElement.java | 149 + .../com/sun/xacml/ProcessingException.java | 107 + .../src/main/java/com/sun/xacml/Rule.java | 509 + .../src/main/java/com/sun/xacml/Target.java | 390 + .../main/java/com/sun/xacml/TargetMatch.java | 537 + .../java/com/sun/xacml/TargetMatchGroup.java | 330 + .../java/com/sun/xacml/TargetSection.java | 382 + .../sun/xacml/UnknownIdentifierException.java | 71 + .../com/sun/xacml/VersionConstraints.java | 241 + .../com/sun/xacml/attr/AnyURIAttribute.java | 201 + .../sun/xacml/attr/AttributeDesignator.java | 552 + .../com/sun/xacml/attr/AttributeFactory.java | 401 + .../sun/xacml/attr/AttributeFactoryProxy.java | 58 + .../com/sun/xacml/attr/AttributeProxy.java | 80 + .../com/sun/xacml/attr/AttributeSelector.java | 421 + .../com/sun/xacml/attr/AttributeValue.java | 254 + .../java/com/sun/xacml/attr/BagAttribute.java | 265 + .../main/java/com/sun/xacml/attr/Base64.java | 379 + .../sun/xacml/attr/Base64BinaryAttribute.java | 251 + .../sun/xacml/attr/BaseAttributeFactory.java | 267 + .../com/sun/xacml/attr/BooleanAttribute.java | 308 + .../com/sun/xacml/attr/DNSNameAttribute.java | 292 + .../com/sun/xacml/attr/DateAttribute.java | 714 + .../com/sun/xacml/attr/DateTimeAttribute.java | 754 + .../xacml/attr/DayTimeDurationAttribute.java | 585 + .../com/sun/xacml/attr/DecisionAttribute.java | 99 + .../com/sun/xacml/attr/DoubleAttribute.java | 218 + .../sun/xacml/attr/HexBinaryAttribute.java | 326 + .../sun/xacml/attr/IPAddressAttribute.java | 269 + .../sun/xacml/attr/IPv4AddressAttribute.java | 179 + .../sun/xacml/attr/IPv6AddressAttribute.java | 170 + .../com/sun/xacml/attr/IntegerAttribute.java | 202 + .../java/com/sun/xacml/attr/PortRange.java | 264 + .../sun/xacml/attr/RFC822NameAttribute.java | 199 + .../xacml/attr/StandardAttributeFactory.java | 265 + .../com/sun/xacml/attr/StringAttribute.java | 228 + .../com/sun/xacml/attr/TimeAttribute.java | 522 + .../xacml/attr/TypeIdentifierConstants.java | 78 + .../com/sun/xacml/attr/X500NameAttribute.java | 203 + .../attr/YearMonthDurationAttribute.java | 428 + .../main/java/com/sun/xacml/attr/package.html | 7 + .../attr/proxy/AnyURIAttributeProxy.java | 70 + .../proxy/Base64BinaryAttributeProxy.java | 64 + .../attr/proxy/BooleanAttributeProxy.java | 64 + .../attr/proxy/DNSNameAttributeProxy.java | 65 + .../xacml/attr/proxy/DateAttributeProxy.java | 64 + .../attr/proxy/DateTimeAttributeProxy.java | 64 + .../proxy/DayTimeDurationAttributeProxy.java | 64 + .../attr/proxy/DoubleAttributeProxy.java | 64 + .../attr/proxy/HexBinaryAttributeProxy.java | 64 + .../attr/proxy/IPAddressAttributeProxy.java | 66 + .../attr/proxy/IntegerAttributeProxy.java | 64 + .../attr/proxy/RFC822NameAttributeProxy.java | 64 + .../attr/proxy/StringAttributeProxy.java | 65 + .../xacml/attr/proxy/TimeAttributeProxy.java | 64 + .../attr/proxy/X500NameAttributeProxy.java | 64 + .../YearMonthDurationAttributeProxy.java | 64 + .../com/sun/xacml/attr/proxy/package.html | 8 + .../combine/BaseCombiningAlgFactory.java | 156 + .../sun/xacml/combine/CombinerElement.java | 130 + .../sun/xacml/combine/CombinerParameter.java | 204 + .../xacml/combine/CombiningAlgFactory.java | 273 + .../combine/CombiningAlgFactoryProxy.java | 58 + .../sun/xacml/combine/CombiningAlgorithm.java | 161 + .../xacml/combine/DenyOverridesPolicyAlg.java | 179 + .../xacml/combine/DenyOverridesRuleAlg.java | 184 + .../combine/FirstApplicablePolicyAlg.java | 152 + .../xacml/combine/FirstApplicableRuleAlg.java | 128 + .../combine/OnlyOneApplicablePolicyAlg.java | 175 + .../OrderedDenyOverridesPolicyAlg.java | 85 + .../combine/OrderedDenyOverridesRuleAlg.java | 85 + .../OrderedPermitOverridesPolicyAlg.java | 85 + .../OrderedPermitOverridesRuleAlg.java | 85 + .../combine/PermitOverridesPolicyAlg.java | 195 + .../xacml/combine/PermitOverridesRuleAlg.java | 184 + .../xacml/combine/PolicyCombinerElement.java | 167 + .../combine/PolicyCombiningAlgorithm.java | 93 + .../xacml/combine/RuleCombinerElement.java | 134 + .../xacml/combine/RuleCombiningAlgorithm.java | 81 + .../combine/StandardCombiningAlgFactory.java | 209 + .../java/com/sun/xacml/combine/package.html | 7 + .../java/com/sun/xacml/cond/AbsFunction.java | 168 + .../java/com/sun/xacml/cond/AddFunction.java | 187 + .../main/java/com/sun/xacml/cond/Apply.java | 459 + .../java/com/sun/xacml/cond/BagFunction.java | 289 + .../sun/xacml/cond/BaseFunctionFactory.java | 418 + .../xacml/cond/BasicFunctionFactoryProxy.java | 81 + .../sun/xacml/cond/ComparisonFunction.java | 711 + .../java/com/sun/xacml/cond/Condition.java | 409 + .../sun/xacml/cond/ConditionBagFunction.java | 167 + .../sun/xacml/cond/ConditionSetFunction.java | 269 + .../com/sun/xacml/cond/DateMathFunction.java | 373 + .../com/sun/xacml/cond/DivideFunction.java | 179 + .../com/sun/xacml/cond/EqualFunction.java | 299 + .../java/com/sun/xacml/cond/Evaluatable.java | 75 + .../com/sun/xacml/cond/EvaluationResult.java | 195 + .../java/com/sun/xacml/cond/Expression.java | 108 + .../com/sun/xacml/cond/ExpressionHandler.java | 138 + .../com/sun/xacml/cond/FloorFunction.java | 122 + .../java/com/sun/xacml/cond/Function.java | 169 + .../java/com/sun/xacml/cond/FunctionBase.java | 763 + .../com/sun/xacml/cond/FunctionFactory.java | 566 + .../sun/xacml/cond/FunctionFactoryProxy.java | 76 + .../com/sun/xacml/cond/FunctionProxy.java | 70 + .../sun/xacml/cond/FunctionTypeException.java | 107 + .../sun/xacml/cond/GeneralBagFunction.java | 371 + .../sun/xacml/cond/GeneralSetFunction.java | 245 + .../sun/xacml/cond/HigherOrderFunction.java | 715 + .../com/sun/xacml/cond/LogicalFunction.java | 165 + .../java/com/sun/xacml/cond/MapFunction.java | 420 + .../com/sun/xacml/cond/MapFunctionProxy.java | 63 + .../com/sun/xacml/cond/MatchFunction.java | 441 + .../java/com/sun/xacml/cond/ModFunction.java | 122 + .../com/sun/xacml/cond/MultiplyFunction.java | 170 + .../java/com/sun/xacml/cond/NOfFunction.java | 229 + .../java/com/sun/xacml/cond/NotFunction.java | 121 + .../xacml/cond/NumericConvertFunction.java | 182 + .../com/sun/xacml/cond/RoundFunction.java | 136 + .../java/com/sun/xacml/cond/SetFunction.java | 291 + .../xacml/cond/StandardFunctionFactory.java | 424 + .../com/sun/xacml/cond/StringFunction.java | 123 + .../xacml/cond/StringNormalizeFunction.java | 166 + .../com/sun/xacml/cond/SubtractFunction.java | 170 + .../sun/xacml/cond/TimeInRangeFunction.java | 203 + .../sun/xacml/cond/URIStringCatFunction.java | 171 + .../sun/xacml/cond/VariableDefinition.java | 213 + .../com/sun/xacml/cond/VariableManager.java | 373 + .../com/sun/xacml/cond/VariableReference.java | 351 + .../cond/cluster/AbsFunctionCluster.java | 67 + .../cond/cluster/AddFunctionCluster.java | 66 + .../cluster/ComparisonFunctionCluster.java | 66 + .../cluster/ConditionBagFunctionCluster.java | 67 + .../cluster/ConditionSetFunctionCluster.java | 67 + .../cond/cluster/DateMathFunctionCluster.java | 68 + .../cond/cluster/DivideFunctionCluster.java | 66 + .../cond/cluster/EqualFunctionCluster.java | 66 + .../cond/cluster/FloorFunctionCluster.java | 66 + .../xacml/cond/cluster/FunctionCluster.java | 72 + .../cluster/GeneralBagFunctionCluster.java | 66 + .../cluster/GeneralSetFunctionCluster.java | 66 + .../cluster/HigherOrderFunctionCluster.java | 66 + .../cond/cluster/LogicalFunctionCluster.java | 66 + .../cond/cluster/MatchFunctionCluster.java | 66 + .../cond/cluster/ModFunctionCluster.java | 66 + .../cond/cluster/MultiplyFunctionCluster.java | 66 + .../cond/cluster/NOfFunctionCluster.java | 66 + .../cond/cluster/NotFunctionCluster.java | 66 + .../NumericConvertFunctionCluster.java | 67 + .../cond/cluster/RoundFunctionCluster.java | 66 + .../cond/cluster/StringFunctionCluster.java | 71 + .../StringNormalizeFunctionCluster.java | 67 + .../cond/cluster/SubtractFunctionCluster.java | 66 + .../com/sun/xacml/cond/cluster/package.html | 7 + .../main/java/com/sun/xacml/cond/package.html | 19 + .../java/com/sun/xacml/ctx/Attribute.java | 449 + .../java/com/sun/xacml/ctx/InputParser.java | 212 + .../java/com/sun/xacml/ctx/PolicyIssuer.java | 118 + .../java/com/sun/xacml/ctx/RequestCtx.java | 412 + .../com/sun/xacml/ctx/RequestElement.java | 626 + .../java/com/sun/xacml/ctx/ResponseCtx.java | 224 + .../main/java/com/sun/xacml/ctx/Result.java | 723 + .../main/java/com/sun/xacml/ctx/Status.java | 404 + .../java/com/sun/xacml/ctx/StatusDetail.java | 209 + .../main/java/com/sun/xacml/ctx/package.html | 8 + .../sun/xacml/debug/IndirectLocatable.java | 36 + .../java/com/sun/xacml/debug/Locatable.java | 28 + .../java/com/sun/xacml/debug/RuntimeInfo.java | 306 + .../com/sun/xacml/finder/AttributeFinder.java | 300 + .../xacml/finder/AttributeFinderModule.java | 201 + .../com/sun/xacml/finder/PolicyFinder.java | 314 + .../sun/xacml/finder/PolicyFinderModule.java | 169 + .../sun/xacml/finder/PolicyFinderResult.java | 130 + .../finder/RequiredAttributesModule.java | 13 + .../com/sun/xacml/finder/ResourceFinder.java | 301 + .../xacml/finder/ResourceFinderModule.java | 200 + .../xacml/finder/ResourceFinderResult.java | 159 + .../sun/xacml/finder/RevocationFinder.java | 136 + .../xacml/finder/RevocationFinderModule.java | 86 + .../xacml/finder/impl/CurrentEnvModule.java | 208 + .../impl/CurrentRequiredAttributeModule.java | 44 + .../sun/xacml/finder/impl/SelectorModule.java | 241 + .../com/sun/xacml/finder/impl/package.html | 8 + .../java/com/sun/xacml/finder/package.html | 11 + .../src/main/java/com/sun/xacml/package.html | 9 + .../com/sun/xacml/reduction/EdgeExplorer.java | 346 + .../sun/xacml/reduction/ReductionGraph.java | 369 + .../xacml/reduction/ReductionGraphEdge.java | 207 + .../xacml/reduction/ReductionGraphNode.java | 387 + .../src/test/java/com/sun/xacml/AppTest.java | 66 + .../META-INF/MANIFEST.MF | 27 + .../build.properties | 5 + .../plugin.xml | 8 + .../pom.xml | 13 + .../export/aslan/bundle/Activator.java | 55 + .../aslan/export/AslanExportMarshaller.java | 306 + .../export/aslan/export/AslanFileBuilder.java | 254 + .../aslan/export/BindingOfDutyExport.java | 265 + .../aslan/export/ExclusiveGatewayExport.java | 145 + .../export/aslan/export/ExportUtil.java | 160 + .../aslan/export/ParallelGatewayExport.java | 139 + .../aslan/export/SeparationOfDutyExport.java | 216 + .../export/aslan/export/TaskExport.java | 126 + .../META-INF/MANIFEST.MF | 25 + .../plugin.xml | 10 + .../pom.xml | 13 + .../export/html/bundle/Activator.java | 58 + .../html/export/HtmlExportMarshaller.java | 239 + .../export/html/export/HtmlWriter.java | 222 + .../html/export/PropertiesStringBuilder.java | 569 + .../META-INF/MANIFEST.MF | 27 + .../build.properties | 5 + .../plugin.xml | 8 + .../pom.xml | 20 + .../export/xacml/bundle/Activator.java | 56 + .../xacml/export/BindingOfDutyExport.java | 265 + .../xacml/export/ExclusiveGatewayExport.java | 145 + .../export/xacml/export/ExportUtil.java | 160 + .../xacml/export/ParallelGatewayExport.java | 139 + .../xacml/export/SeparationOfDutyExport.java | 215 + .../export/xacml/export/TaskExport.java | 171 + .../xacml/export/XacmlExportMarshaller.java | 195 + .../export/xacml/export/XacmlFileBuilder.java | 329 + .../META-INF/MANIFEST.MF | 23 + .../build.properties | 5 + .../plugin.xml | 10 + .../pom.xml | 13 + .../validation/bpmn20/bundle/Activator.java | 58 + .../validation/BPMN20ProcessValidator.java | 165 + .../META-INF/MANIFEST.MF | 31 + src/eu.aniketos.securebpmn/build.properties | 5 + src/eu.aniketos.securebpmn/plugin.xml | 13 + src/eu.aniketos.securebpmn/pom.xml | 13 + .../eu/aniketos/securebpmn/Activator.java | 56 + .../features/CheckServiceTaskFeature.java | 300 + .../features/ListProcessVariablesFeature.java | 175 + .../features/PerformNtkAnalysisFeature.java | 276 + .../features/ValidateAslanFeature.java | 565 + .../features/ValidateAslanLocalFeature.java | 82 + .../features/ValidateAslanWebFeature.java | 82 + .../securebpmn/ntk/NeedToKnowUtil.java | 453 + .../eu/aniketos/securebpmn/roles/RoleDef.java | 71 + .../securebpmn/roles/RoleDefLine.java | 25 + .../eu/aniketos/securebpmn/roles/RoleRel.java | 60 + .../aniketos/securebpmn/satmc/SatmcFact.java | 25 + .../securebpmn/satmc/SatmcFunction.java | 53 + .../securebpmn/satmc/SatmcMessage.java | 38 + .../securebpmn/satmc/SatmcTraceStep.java | 33 + .../aniketos/securebpmn/satmc/SatmcVar.java | 39 + .../eu/aniketos/securebpmn/satmc/Summary.java | 25 + .../aniketos/securebpmn/util/DialogUtil.java | 134 + .../securebpmn/util/SecurityUtil.java | 360 + .../securebpmn/validation/ProcVarAccess.java | 63 + .../validation/ProcVarCheckASTVisitor.java | 129 + .../validation/ProcVarListASTVisitor.java | 135 + .../validation/SCVMValidationConstants.java | 53 + .../validation/ValidateAslanRunnable.java | 322 + .../view/PlayerControlRunnable.java | 64 + .../validation/view/ValidationView.java | 233 + .../securebpmn/visualization/ActionType.java | 28 + ...ighlightVisualizationElementsRunnable.java | 474 + .../visualization/VisualizationElement.java | 126 + .../visualization/rbac/AttackTracePlayer.java | 199 + .../visualization/rbac/AttackTraceStep.java | 79 + .../visualization/rbac/RbacVisualization.java | 199 + .../eu/avantssar/satmc/SATMCPortType.java | 64 + .../java/eu/avantssar/satmc/SATMCService.java | 71 + .../src/main/java/org/antlr/RoleDef.g | 64 + .../src/main/java/org/antlr/Satmc.g | 214 + .../java/org/antlr/roledef/RoleDefLexer.java | 515 + .../java/org/antlr/roledef/RoleDefParser.java | 323 + .../main/java/org/antlr/satmc/SatmcLexer.java | 1592 + .../java/org/antlr/satmc/SatmcParser.java | 2289 + src/examples/money-tasks/pom.xml | 56 + .../org/acme/palette/AcmeMoneyCustomizer.java | 25 + .../org/acme/servicetasks/AccountManager.java | 28 + .../org/acme/servicetasks/AcmeMoneyTask.java | 122 + .../src/main/resources/icons/coins.png | Bin 0 -> 732 bytes .../META-INF/MANIFEST.MF | 55 + .../build.properties | 10 + .../community_icon.png | Bin 0 -> 6884 bytes .../icons/connection16.gif | Bin 0 -> 882 bytes .../icons/dialogs/layout_circular.gif | Bin 0 -> 909 bytes .../icons/dialogs/layout_organic.gif | Bin 0 -> 159 bytes .../icons/general/arrow_down.gif | Bin 0 -> 89 bytes .../icons/general/arrow_left.gif | Bin 0 -> 878 bytes .../icons/general/arrow_right.gif | Bin 0 -> 95 bytes .../icons/general/arrow_up.gif | Bin 0 -> 94 bytes .../logo/activiti.logo.gradients.128x128.png | Bin 0 -> 49478 bytes .../logo/activiti.logo.gradients.16x16.png | Bin 0 -> 905 bytes .../logo/activiti.logo.gradients.32x32.png | Bin 0 -> 3225 bytes .../logo/activiti.logo.gradients.48x48.png | Bin 0 -> 7081 bytes .../logo/activiti.logo.gradients.64x64.png | Bin 0 -> 12485 bytes .../icons/modifier/attribute_private.gif | Bin 0 -> 88 bytes .../icons/modifier/attribute_protected.gif | Bin 0 -> 89 bytes .../icons/modifier/attribute_public.gif | Bin 0 -> 92 bytes .../icons/modifier/operation_private.gif | Bin 0 -> 96 bytes .../icons/modifier/operation_protected.gif | Bin 0 -> 91 bytes .../icons/modifier/operation_public.gif | Bin 0 -> 97 bytes .../icons/modifier/reference_private.gif | Bin 0 -> 627 bytes .../icons/modifier/reference_protected.gif | Bin 0 -> 628 bytes .../icons/modifier/reference_public.gif | Bin 0 -> 628 bytes .../icons/mof/class.gif | Bin 0 -> 372 bytes .../icons/mof/mof.gif | Bin 0 -> 670 bytes .../icons/mof/newclass.gif | Bin 0 -> 598 bytes .../icons/mof/package.gif | Bin 0 -> 228 bytes .../icons/outline/thumbnail.gif | Bin 0 -> 167 bytes .../icons/outline/tree.gif | Bin 0 -> 133 bytes .../icons/pid16.gif | Bin 0 -> 995 bytes .../icons/rialto16.gif | Bin 0 -> 970 bytes .../icons/sample.gif | Bin 0 -> 983 bytes .../icons/tree/tree_down.gif | Bin 0 -> 209 bytes .../icons/tree/tree_left.gif | Bin 0 -> 209 bytes .../icons/tree/tree_right.gif | Bin 0 -> 209 bytes .../icons/tree/tree_up.gif | Bin 0 -> 213 bytes .../plugin.properties | 20 + src/org.activiti.designer.eclipse/plugin.xml | 229 + src/org.activiti.designer.eclipse/pom.xml | 15 + ...pse.extension.export.ExportMarshaller.exsd | 102 + ...extension.validation.ProcessValidator.exsd | 102 + .../org/activiti/designer/eclipse/Logger.java | 58 + .../eclipse/bpmn/BoundaryEventModel.java | 30 + .../designer/eclipse/bpmn/BpmnParser.java | 1777 + .../designer/eclipse/bpmn/FieldModel.java | 10 + .../designer/eclipse/bpmn/GraphicInfo.java | 30 + .../eclipse/bpmn/SequenceFlowModel.java | 33 + .../eclipse/bpmnimport/BpmnFileReader.java | 1081 + .../FlowSourceNotFoundException.java | 7 + .../bpmnimport/ImportBpmnElementsCommand.java | 61 + .../eclipse/bpmnimport/ImportBpmnUtil.java | 66 + .../eclipse/common/AbstractImageCache.java | 39 + .../common/ActivitiBPMNDiagramConstants.java | 48 + .../common/ActivitiEclipseImageProvider.java | 42 + .../eclipse/common/ActivitiPlugin.java | 175 + .../eclipse/common/ActivitiProjectNature.java | 34 + .../designer/eclipse/common/ColoredFont.java | 81 + .../designer/eclipse/common/FileService.java | 181 + .../eclipse/common/ISampleImageConstants.java | 132 + .../designer/eclipse/common/ImageCache.java | 44 + .../designer/eclipse/common/PluginImage.java | 31 + .../eclipse/common/RenameActionProvider.java | 119 + .../designer/eclipse/common/SampleUtil.java | 90 + .../eclipse/deployment/DeploymentInfo.java | 62 + .../IncludeClassesTreeContentProvider.java | 145 + .../IncludeClassesViewerFilter.java | 20 + .../IncludeFilesTreeContentProvider.java | 68 + .../deployment/IncludeFilesViewerFilter.java | 20 + .../IncludeInDeploymentTreeViewer.java | 88 + .../eclipse/deployment/ProcessDeployer.java | 304 + .../eclipse/editor/ActivitiBMPN2Editor.java | 107 + .../eclipse/editor/ActivitiDiagramEditor.java | 176 + .../editor/ActivitiMultiPageEditor.java | 288 + .../eclipse/editor/sync/DiagramUpdater.java | 343 + .../extension/AbstractDiagramWorker.java | 386 + .../eclipse/extension/ExtensionConstants.java | 22 + .../export/AbstractExportMarshaller.java | 96 + .../extension/export/ExportMarshaller.java | 78 + .../export/SequenceFlowSynchronizer.java | 147 + .../validation/AbstractProcessValidator.java | 18 + .../validation/ProcessValidator.java | 59 + .../eclipse/navigator/BpmnLabelProvider.java | 129 + .../navigator/BpmnTreeContentProvider.java | 155 + .../navigator/nodes/BpmnElementsNode.java | 63 + .../eclipse/navigator/nodes/DiagramsNode.java | 94 + .../nodes/base/AbstractContainerNode.java | 39 + .../AbstractInstancesOfTypeContainerNode.java | 37 + .../navigator/nodes/base/IContainerNode.java | 39 + .../ContentOutlinePageAdapterFactory.java | 55 + .../outline/GraphicsEditorOutlinePage.java | 357 + .../tree/AbstractGraphicsTreeEditPart.java | 274 + .../outline/tree/ColorTreeEditPart.java | 56 + .../tree/ConnectionDecoratorTreeEditPart.java | 79 + .../tree/GraphicsAlgorithmTreeEditPart.java | 80 + .../tree/PictogramElementTreeEditPart.java | 120 + .../tree/PictogramsTreeEditPartFactory.java | 65 + .../outline/tree/PointTreeEditPart.java | 51 + .../outline/tree/StyleTreeEditPart.java | 72 + .../perspective/ActivitiPerspective.java | 68 + ...ctivitiSavePreferencesPageInitializer.java | 48 + .../eclipse/preferences/PreferencesUtil.java | 109 + .../property/PropertiesLabelProvider.java | 156 + .../designer/eclipse/property/TypeMapper.java | 49 + .../ui/AbstractInputFieldWizardPage.java | 221 + .../eclipse/ui/AbstractWizardPage.java | 85 + .../ui/ActivitiEditorContextMenuProvider.java | 26 + .../ui/CreateActivitiProjectWizard.java | 214 + .../eclipse/ui/ExportMarshallerRunnable.java | 109 + .../designer/eclipse/ui/ITextProvider.java | 29 + ...aultActivitiDiagramInitialContentPage.java | 146 + ...eDefaultActivitiDiagramNameWizardPage.java | 73 + .../CreateDefaultActivitiDiagramWizard.java | 277 + .../ui/wizard/diagram/InitialContentInfo.java | 6 + .../ui/wizard/diagram/TemplateInfo.java | 20 + .../CreateDefaultActivitiProjectWizard.java | 254 + .../eclipse/util/ExtensionPointUtil.java | 128 + .../eclipse/util/FlowElementUtil.java | 95 + .../activiti/designer/eclipse/util/Util.java | 240 + .../util/uiprovider/TwoObjectsContainer.java | 68 + .../resources/content/new-diagram-content.xml | 259 + .../content/new-subprocess-content.xml | 259 + .../main/resources/templates/adhoc.bpmn20.xml | 82 + .../parallel-review-group.bpmn20.xml | 172 + .../templates/parallel-review.bpmn20.xml | 154 + .../templates/review-pooled.bpmn20.xml | 129 + .../resources/templates/review.bpmn20.xml | 114 + .../designer/eclipse/bpmn/BpmnParserTest.java | 131 + .../test/resources/VacationRequest.bpmn20.xml | 148 + .../resources/processEventListener.bpmn20.xml | 39 + .../sequenceFlowWithCondition.bpmn20.xml | 20 + .../xsd/BPMN20.xsd | 37 + .../xsd/BPMNDI.xsd | 100 + src/org.activiti.designer.eclipse/xsd/DC.xsd | 29 + src/org.activiti.designer.eclipse/xsd/DI.xsd | 100 + .../xsd/Semantic.xsd | 1562 + .../xsd/activiti-bpmn-extensions-5.2.xsd | 403 + .../META-INF/MANIFEST.MF | 28 + .../build.properties | 5 + .../plugin.xml | 10 + .../pom.xml | 15 + .../export/bpmn20/bundle/Activator.java | 40 + .../export/ActivitiNamespaceConstants.java | 43 + .../export/AlfrescoScriptTaskExport.java | 79 + .../bpmn20/export/AsyncActivityExport.java | 37 + .../bpmn20/export/BPMN20ExportMarshaller.java | 432 + .../bpmn20/export/BoundaryEventExport.java | 119 + .../export/bpmn20/export/BpmnDIExport.java | 324 + .../bpmn20/export/BusinessRuleTaskExport.java | 83 + .../bpmn20/export/CallActivityExport.java | 99 + .../bpmn20/export/DefaultFlowExport.java | 46 + .../export/DelegatingXMLStreamWriter.java | 148 + .../export/ExtensionListenerExport.java | 50 + .../bpmn20/export/FieldExtensionsExport.java | 56 + .../bpmn20/export/FormPropertiesExport.java | 69 + .../export/ImplementationValueExport.java | 61 + .../export/IndentingXMLStreamWriter.java | 174 + .../export/IntermediateCatchEventExport.java | 86 + .../export/bpmn20/export/MailTaskExport.java | 188 + .../bpmn20/export/ManualTaskExport.java | 51 + .../bpmn20/export/MultiInstanceExport.java | 79 + .../bpmn20/export/ReceiveTaskExport.java | 51 + .../bpmn20/export/ScriptTaskExport.java | 57 + .../bpmn20/export/SequenceFlowExport.java | 58 + .../bpmn20/export/ServiceTaskExport.java | 113 + .../export/bpmn20/export/UserTaskExport.java | 129 + .../META-INF/MANIFEST.MF | 25 + .../build.properties | 5 + .../plugin.xml | 10 + .../pom.xml | 15 + .../export/image/bundle/Activator.java | 38 + .../image/export/ImageExportMarshaller.java | 145 + .../build.properties | 2 + .../feature.properties | 143 + src/org.activiti.designer.feature/feature.xml | 191 + .../license.html | 107 + src/org.activiti.designer.feature/pom.xml | 15 + .../META-INF/MANIFEST.MF | 43 + .../build.properties | 6 + .../icons/action.down.png | Bin 0 -> 379 bytes .../icons/action.magnifier.png | Bin 0 -> 615 bytes .../icons/action.up.png | Bin 0 -> 372 bytes .../icons/alfresco.png | Bin 0 -> 607 bytes .../icons/bullet_go.png | Bin 0 -> 410 bytes .../icons/callactivity.png | Bin 0 -> 2990 bytes .../icons/defaultCustomServiceTask.png | Bin 0 -> 634 bytes src/org.activiti.designer.gui/icons/edit.png | Bin 0 -> 691 bytes .../icons/ereference.gif | Bin 0 -> 1611 bytes src/org.activiti.designer.gui/icons/error.png | Bin 0 -> 3497 bytes .../icons/errorCustomServiceTask.png | Bin 0 -> 655 bytes src/org.activiti.designer.gui/icons/new.png | Bin 0 -> 686 bytes src/org.activiti.designer.gui/icons/timer.png | Bin 0 -> 3420 bytes .../icons/type.annotation.png | Bin 0 -> 2871 bytes .../icons/type.business.rule.png | Bin 0 -> 1079 bytes .../icons/type.endevent.none.png | Bin 0 -> 1659 bytes .../icons/type.gateway.exclusive.png | Bin 0 -> 3248 bytes .../icons/type.gateway.inclusive.png | Bin 0 -> 1365 bytes .../icons/type.gateway.parallel.png | Bin 0 -> 426 bytes .../icons/type.loopmarker.png | Bin 0 -> 2997 bytes .../icons/type.mail.png | Bin 0 -> 3221 bytes .../icons/type.manual.png | Bin 0 -> 3339 bytes .../icons/type.receive.png | Bin 0 -> 3221 bytes .../icons/type.script.png | Bin 0 -> 1392 bytes .../icons/type.security.bod.png | Bin 0 -> 732 bytes .../icons/type.security.sod.png | Bin 0 -> 1073 bytes .../icons/type.send.png | Bin 0 -> 1410 bytes .../icons/type.service.png | Bin 0 -> 1445 bytes .../icons/type.startevent.none.png | Bin 0 -> 1737 bytes .../icons/type.subprocess.collapsed.png | Bin 0 -> 3094 bytes .../icons/type.subprocess.expanded.png | Bin 0 -> 3094 bytes .../icons/type.user.png | Bin 0 -> 3226 bytes src/org.activiti.designer.gui/plugin.xml | 414 + src/org.activiti.designer.gui/pom.xml | 15 + .../features/AddAlfrescoMailTaskFeature.java | 15 + .../AddAlfrescoScriptTaskFeature.java | 15 + .../AddAlfrescoStartEventFeature.java | 114 + .../gui/features/AddAlfrescoTaskFeature.java | 163 + .../features/AddAlfrescoUserTaskFeature.java | 15 + .../CreateAlfrescoMailTaskFeature.java | 63 + .../CreateAlfrescoScriptTaskFeature.java | 63 + .../CreateAlfrescoStartEventFeature.java | 60 + .../CreateAlfrescoUserTaskFeature.java | 63 + .../PropertyAlfrescoMailTaskFilter.java | 20 + .../PropertyAlfrescoMailTaskSection.java | 179 + .../PropertyAlfrescoScriptTaskFilter.java | 20 + .../PropertyAlfrescoScriptTaskSection.java | 134 + .../PropertyAlfrescoStartEventFilter.java | 20 + .../PropertyAlfrescoStartEventSection.java | 113 + .../PropertyAlfrescoUserTaskFilter.java | 20 + .../PropertyAlfrescoUserTaskSection.java | 368 + .../java/org/activiti/designer/Activator.java | 92 + .../ActivitiExtensionImageProvider.java | 25 + .../designer/ActivitiImageProvider.java | 101 + .../org/activiti/designer/PluginImage.java | 46 + .../actions/GenerateUnitTestAction.java | 53 + .../ActivitiBPMNDiagramTypeProvider.java | 33 + .../diagram/ActivitiBPMNFeatureProvider.java | 325 + .../diagram/ActivitiToolBehaviorProvider.java | 822 + .../AbstractCreateBPMNConnectionFeature.java | 31 + .../AbstractCreateFastBPMNFeature.java | 143 + .../features/AddBoundaryErrorFeature.java | 134 + .../features/AddBoundaryTimerFeature.java | 138 + .../features/AddBusinessRuleTaskFeature.java | 16 + .../features/AddCallActivityFeature.java | 157 + .../AddEmbeddedSubProcessFeature.java | 137 + .../designer/features/AddEndEventFeature.java | 11 + .../features/AddErrorEndEventFeature.java | 108 + .../designer/features/AddEventFeature.java | 123 + .../features/AddExclusiveGatewayFeature.java | 131 + .../features/AddInclusiveGatewayFeature.java | 127 + .../designer/features/AddMailTaskFeature.java | 16 + .../features/AddManualTaskFeature.java | 16 + .../features/AddParallelGatewayFeature.java | 131 + .../features/AddReceiveTaskFeature.java | 16 + .../features/AddScriptTaskFeature.java | 17 + .../features/AddSequenceFlowFeature.java | 269 + .../features/AddServiceTaskFeature.java | 31 + .../features/AddStartEventFeature.java | 11 + .../designer/features/AddTaskFeature.java | 309 + .../AddTimerCatchingEventFeature.java | 112 + .../features/AddTimerStartEventFeature.java | 11 + .../designer/features/AddUserTaskFeature.java | 16 + .../features/ChangeElementTypeFeature.java | 160 + .../features/CopyFlowElementFeature.java | 68 + .../features/CreateBoundaryErrorFeature.java | 81 + .../features/CreateBoundaryTimerFeature.java | 82 + .../CreateBusinessRuleTaskFeature.java | 59 + .../features/CreateCallActivityFeature.java | 62 + .../CreateCustomServiceTaskFeature.java | 21 + .../CreateEmbeddedSubProcessFeature.java | 56 + .../features/CreateEndEventFeature.java | 60 + .../features/CreateErrorEndEventFeature.java | 63 + .../CreateExclusiveGatewayFeature.java | 58 + .../CreateInclusiveGatewayFeature.java | 57 + .../features/CreateMailTaskFeature.java | 58 + .../features/CreateManualTaskFeature.java | 58 + .../CreateParallelGatewayFeature.java | 57 + .../features/CreateReceiveTaskFeature.java | 58 + .../features/CreateScriptTaskFeature.java | 59 + .../features/CreateSequenceFlowFeature.java | 143 + .../features/CreateServiceTaskFeature.java | 106 + .../features/CreateStartEventFeature.java | 61 + .../CreateTimerCatchingEventFeature.java | 63 + .../CreateTimerStartEventFeature.java | 64 + .../features/CreateUserTaskFeature.java | 63 + .../features/DeleteFlowElementFeature.java | 214 + .../features/DeleteSequenceFlowFeature.java | 143 + .../DirectEditFlowElementFeature.java | 77 + .../ExpandCollapseSubProcessFeature.java | 135 + .../features/MoveBoundaryEventFeature.java | 106 + .../features/PasteFlowElementFeature.java | 83 + .../features/SaveBpmnModelFeature.java | 63 + .../features/SubProcessResizeFeature.java | 62 + .../designer/features/TaskResizeFeature.java | 116 + .../UpdateConnectionFlowElementFeature.java | 166 + .../features/UpdateFlowElementFeature.java | 88 + .../gui/actions/CopyActionHandler.java | 40 + .../gui/actions/PasteActionHandler.java | 40 + .../designer/model/FieldExtensionModel.java | 25 + .../designer/popupmenus/DeploymentMenu.java | 222 + .../designer/popupmenus/ImportBpmnMenu.java | 93 + .../ActivitiEditorPreferencesPage.java | 31 + .../ActivitiImportPreferencesPage.java | 37 + .../preferences/ActivitiPreferencePage.java | 38 + .../ActivitiSavePreferencesPage.java | 72 + .../preferences/AlfrescoPreferencesPage.java | 139 + .../property/PropertyBoundaryErrorFilter.java | 37 + .../PropertyBoundaryErrorSection.java | 121 + .../property/PropertyBoundaryTimerFilter.java | 28 + .../PropertyBoundaryTimerSection.java | 205 + .../designer/property/PropertyBpmnFilter.java | 35 + .../property/PropertyBpmnSection.java | 319 + .../PropertyBusinessRuleTaskFilter.java | 20 + .../PropertyBusinessRuleTaskSection.java | 221 + .../property/PropertyCallActivityFilter.java | 20 + .../property/PropertyCallActivitySection.java | 234 + .../PropertyCustomServiceTaskFilter.java | 21 + .../PropertyCustomServiceTaskSection.java | 454 + .../property/PropertyDiagramFilter.java | 16 + .../property/PropertyDiagramSection.java | 189 + .../PropertyExecutionListenerFilter.java | 26 + .../PropertyExecutionListenerSection.java | 78 + .../property/PropertyFormPropertyFilter.java | 21 + .../property/PropertyFormPropertySection.java | 81 + .../property/PropertyIOParameterSection.java | 103 + .../PropertyIntermediateCatchTimerFilter.java | 28 + ...PropertyIntermediateCatchTimerSection.java | 172 + .../property/PropertyMailTaskFilter.java | 21 + .../property/PropertyMailTaskSection.java | 171 + .../property/PropertyMultiInstanceFilter.java | 19 + .../PropertyMultiInstanceSection.java | 258 + .../property/PropertyScriptTaskFilter.java | 20 + .../property/PropertyScriptTaskSection.java | 133 + .../property/PropertySequenceFlowFilter.java | 20 + .../property/PropertySequenceFlowSection.java | 121 + .../property/PropertyServiceTaskFilter.java | 21 + .../property/PropertyServiceTaskSection.java | 398 + .../property/PropertyStartEventFilter.java | 25 + .../property/PropertyStartEventSection.java | 144 + .../property/PropertyTaskListenerFilter.java | 20 + .../property/PropertyTaskListenerSection.java | 74 + .../PropertyTimerStartEventFilter.java | 23 + .../PropertyTimerStartEventSection.java | 173 + .../property/PropertyUserTaskFilter.java | 21 + .../property/PropertyUserTaskSection.java | 383 + .../property/custom/MultilineTextDialog.java | 122 + .../property/custom/PeriodDialog.java | 129 + .../custom/PeriodPropertyElement.java | 66 + .../extension/CustomServiceTaskContext.java | 28 + .../CustomServiceTaskContextImpl.java | 137 + .../property/extension/FormToolTip.java | 71 + .../property/extension/JarClassLoader.java | 116 + .../field/AbstractCustomPropertyField.java | 225 + .../CustomPropertyBooleanChoiceField.java | 80 + .../CustomPropertyComboboxChoiceField.java | 125 + .../field/CustomPropertyDataGridField.java | 638 + .../field/CustomPropertyDatePickerField.java | 131 + .../extension/field/CustomPropertyField.java | 65 + .../CustomPropertyMultilineTextField.java | 86 + .../field/CustomPropertyPeriodField.java | 140 + .../field/CustomPropertyRadioChoiceField.java | 156 + .../field/CustomPropertyTextField.java | 85 + .../property/extension/field/FieldInfo.java | 76 + .../PeriodRequiredFieldValidator.java | 58 + .../RadioRequiredFieldValidator.java | 57 + .../extension/util/ExtensionPropertyUtil.java | 89 + .../extension/util/ExtensionUtil.java | 581 + .../property/ui/AbstractListenerDialog.java | 519 + .../property/ui/AbstractListenerEditor.java | 255 + .../property/ui/ExecutionListenerDialog.java | 41 + .../property/ui/ExecutionListenerEditor.java | 24 + .../property/ui/FieldExtensionDialog.java | 156 + .../property/ui/FieldExtensionEditor.java | 179 + .../property/ui/FormPropertyDialog.java | 296 + .../property/ui/FormPropertyEditor.java | 297 + .../designer/property/ui/FormValueDialog.java | 159 + .../designer/property/ui/FormValueEditor.java | 75 + .../property/ui/IOParameterDialog.java | 163 + .../property/ui/IOParameterEditor.java | 219 + .../property/ui/TableFieldEditor.java | 610 + .../property/ui/TaskListenerDialog.java | 27 + .../property/ui/TaskListenerEditor.java | 25 + .../runner/TestRunnerClassGenerator.java | 139 + .../features/AddSecurityBodFeature.java | 189 + .../features/AddSecurityFlowFeature.java | 292 + .../features/AddSecuritySodFeature.java | 189 + .../features/CreateSecurityBodFeature.java | 80 + .../features/CreateSecurityFlowFeature.java | 148 + .../features/CreateSecuritySodFeature.java | 80 + .../features/DeleteSecurityFlowFeature.java | 155 + .../security/property/PropertyNtkFilter.java | 51 + .../security/property/PropertyNtkSection.java | 804 + .../security/property/PropertyRbacFilter.java | 43 + .../property/PropertyRbacSection.java | 539 + .../property/PropertySodBodFilter.java | 45 + .../property/PropertySodBodSection.java | 714 + .../activiti/designer/util/BpmnBOUtil.java | 108 + .../org/activiti/designer/util/CloneUtil.java | 347 + .../META-INF/MANIFEST.MF | 14 + .../build.properties | 9 + .../html/images/activiti_logo.png | Bin 0 -> 5241 bytes .../html/preferences/maintopic.html | 40 + src/org.activiti.designer.help/html/toc.html | 21 + .../html/usage/maintopic.html | 17 + src/org.activiti.designer.help/plugin.xml | 17 + src/org.activiti.designer.help/pom.xml | 15 + .../org/activiti/designer/help/Activator.java | 30 + src/org.activiti.designer.help/toc.xml | 11 + .../tocpreferences.xml | 7 + src/org.activiti.designer.help/tocusage.xml | 7 + .../META-INF/MANIFEST.MF | 21 + .../build.properties | 4 + src/org.activiti.designer.integration/pom.xml | 15 + .../designer/integration/Activator.java | 30 + .../AbstractDefaultPaletteCustomizer.java | 17 + .../palette/DefaultPaletteCustomizer.java | 20 + .../integration/palette/PaletteEntry.java | 22 + .../AbstractCustomServiceTask.java | 189 + .../servicetask/CustomServiceTask.java | 108 + .../servicetask/DiagramBaseShape.java | 16 + .../integration/servicetask/PropertyType.java | 59 + .../annotation/DataGridProperty.java | 37 + .../annotation/DatePickerProperty.java | 51 + .../servicetask/annotation/Help.java | 25 + .../servicetask/annotation/Property.java | 60 + .../servicetask/annotation/PropertyItems.java | 28 + .../servicetask/annotation/Runtime.java | 29 + .../validator/EmailFieldValidator.java | 60 + .../servicetask/validator/FieldValidator.java | 21 + .../validator/RequiredFieldValidator.java | 75 + .../validator/ValidationException.java | 45 + .../.classpath | 7 + src/org.activiti.designer.model.edit/.project | 28 + .../META-INF/MANIFEST.MF | 19 + .../build.properties | 21 + .../icons/full/obj16/ActivitiListener.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ActivityAction.gif | Bin 0 -> 129 bytes .../obj16/ActivityAuthorizationConstraint.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AdHocSubProcess.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AlfrescoMailTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AlfrescoScriptBase.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AlfrescoScriptTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AlfrescoStartEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AlfrescoUserTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Assignment.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Association.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AtomicActivityAction.gif | Bin 0 -> 129 bytes .../obj16/AtomicItemAwareElementAction.gif | Bin 0 -> 129 bytes .../icons/full/obj16/AtomicProcessAction.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Auditing.gif | Bin 0 -> 129 bytes .../full/obj16/AuthorizationConstraint.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNDiagram.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNEdge.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNLabel.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNLabelStyle.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNPlane.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BPMNShape.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BindingOfDuty.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BoundaryEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Bounds.gif | Bin 0 -> 129 bytes .../icons/full/obj16/BusinessRuleTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CallActivity.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CallChoreography.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CallConversation.gif | Bin 0 -> 129 bytes .../full/obj16/CancelEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CandidateGroup.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CandidateUser.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Category.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CategoryValue.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Choreography.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ChoreographyTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Collaboration.gif | Bin 0 -> 129 bytes .../full/obj16/CompensateEventDefinition.gif | Bin 0 -> 129 bytes .../full/obj16/ComplexBehaviorDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ComplexGateway.gif | Bin 0 -> 129 bytes .../full/obj16/CompositeActivityAction.gif | Bin 0 -> 129 bytes .../obj16/CompositeItemAwareElementAction.gif | Bin 0 -> 129 bytes .../full/obj16/CompositeProcessAction.gif | Bin 0 -> 129 bytes .../full/obj16/ConditionalEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Conversation.gif | Bin 0 -> 129 bytes .../full/obj16/ConversationAssociation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ConversationLink.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CorrelationKey.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CorrelationProperty.gif | Bin 0 -> 129 bytes .../full/obj16/CorrelationPropertyBinding.gif | Bin 0 -> 129 bytes ...CorrelationPropertyRetrievalExpression.gif | Bin 0 -> 129 bytes .../full/obj16/CorrelationSubscription.gif | Bin 0 -> 129 bytes .../icons/full/obj16/CustomProperty.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataAssociation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataGrid.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataGridField.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataGridRow.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataInput.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataInputAssociation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataObject.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataObjectReference.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataOutput.gif | Bin 0 -> 129 bytes .../full/obj16/DataOutputAssociation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataState.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataStore.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DataStoreReference.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Definitions.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Diagram.gif | Bin 0 -> 129 bytes .../icons/full/obj16/DocumentRoot.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Documentation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Edge.gif | Bin 0 -> 129 bytes .../icons/full/obj16/EndEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/EndPoint.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Error.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ErrorEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Escalation.gif | Bin 0 -> 129 bytes .../full/obj16/EscalationEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/EventBasedGateway.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ExclusiveGateway.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Expression.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Extension.gif | Bin 0 -> 129 bytes .../obj16/ExtensionAttributeDefinition.gif | Bin 0 -> 129 bytes .../full/obj16/ExtensionAttributeValue.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ExtensionDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/FieldExtension.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Font.gif | Bin 0 -> 129 bytes .../icons/full/obj16/FormProperty.gif | Bin 0 -> 129 bytes .../icons/full/obj16/FormValue.gif | Bin 0 -> 129 bytes .../icons/full/obj16/FormalExpression.gif | Bin 0 -> 129 bytes .../full/obj16/GlobalBusinessRuleTask.gif | Bin 0 -> 129 bytes .../full/obj16/GlobalChoreographyTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/GlobalConversation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/GlobalManualTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/GlobalScriptTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/GlobalTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/GlobalUserTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Group.gif | Bin 0 -> 129 bytes .../icons/full/obj16/HumanPerformer.gif | Bin 0 -> 129 bytes .../icons/full/obj16/IOParameter.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ImplicitThrowEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Import.gif | Bin 0 -> 129 bytes .../icons/full/obj16/InclusiveGateway.gif | Bin 0 -> 129 bytes .../icons/full/obj16/InputOutputBinding.gif | Bin 0 -> 129 bytes .../full/obj16/InputOutputSpecification.gif | Bin 0 -> 129 bytes .../icons/full/obj16/InputSet.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Interface.gif | Bin 0 -> 129 bytes .../full/obj16/IntermediateCatchEvent.gif | Bin 0 -> 129 bytes .../full/obj16/IntermediateThrowEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ItemAwareElement.gif | Bin 0 -> 129 bytes .../full/obj16/ItemAwareElementAction.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ItemDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Label.gif | Bin 0 -> 129 bytes .../icons/full/obj16/LabeledEdge.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Lane.gif | Bin 0 -> 129 bytes .../icons/full/obj16/LaneSet.gif | Bin 0 -> 129 bytes .../icons/full/obj16/LinkEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/MailTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ManualTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Message.gif | Bin 0 -> 129 bytes .../full/obj16/MessageEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/MessageFlow.gif | Bin 0 -> 129 bytes .../full/obj16/MessageFlowAssociation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Monitoring.gif | Bin 0 -> 129 bytes .../MultiInstanceLoopCharacteristics.gif | Bin 0 -> 129 bytes .../icons/full/obj16/NeedToKnow.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Operation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/OutputSet.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ParallelGateway.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Participant.gif | Bin 0 -> 129 bytes .../full/obj16/ParticipantAssociation.gif | Bin 0 -> 129 bytes .../full/obj16/ParticipantMultiplicity.gif | Bin 0 -> 129 bytes .../icons/full/obj16/PartnerEntity.gif | Bin 0 -> 129 bytes .../icons/full/obj16/PartnerRole.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Performer.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Plane.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Point.gif | Bin 0 -> 129 bytes .../icons/full/obj16/PotentialOwner.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Process.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ProcessAction.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Property.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ReceiveTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Relationship.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Rendering.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Resource.gif | Bin 0 -> 129 bytes .../obj16/ResourceAssignmentExpression.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ResourceParameter.gif | Bin 0 -> 129 bytes .../full/obj16/ResourceParameterBinding.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ResourceRole.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Role.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ScriptTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SecurityFlow.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SecurityFlowNode.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SendTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SeparationOfDuty.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SequenceFlow.gif | Bin 0 -> 129 bytes .../icons/full/obj16/ServiceTask.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Shape.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Signal.gif | Bin 0 -> 129 bytes .../full/obj16/SignalEventDefinition.gif | Bin 0 -> 129 bytes .../obj16/StandardLoopCharacteristics.gif | Bin 0 -> 129 bytes .../icons/full/obj16/StartEvent.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SubChoreography.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SubConversation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/SubProcess.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Task.gif | Bin 0 -> 129 bytes .../full/obj16/TerminateEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/TextAnnotation.gif | Bin 0 -> 129 bytes .../icons/full/obj16/TimerEventDefinition.gif | Bin 0 -> 129 bytes .../icons/full/obj16/Transaction.gif | Bin 0 -> 129 bytes .../icons/full/obj16/User.gif | Bin 0 -> 129 bytes .../icons/full/obj16/UserTask.gif | Bin 0 -> 129 bytes .../plugin.properties | 907 + .../plugin.xml | 81 + .../di/provider/BPMNDiagramItemProvider.java | 198 + .../di/provider/BPMNEdgeItemProvider.java | 279 + .../di/provider/BPMNLabelItemProvider.java | 166 + .../provider/BPMNLabelStyleItemProvider.java | 192 + .../di/provider/BPMNPlaneItemProvider.java | 166 + .../di/provider/BPMNShapeItemProvider.java | 344 + .../BpmnDiItemProviderAdapterFactory.java | 342 + .../di/provider/DocumentRootItemProvider.java | 224 + .../ActivitiListenerItemProvider.java | 288 + .../bpmn2/provider/ActivityItemProvider.java | 393 + .../provider/AdHocSubProcessItemProvider.java | 230 + .../AlfrescoMailTaskItemProvider.java | 202 + .../AlfrescoScriptBaseItemProvider.java | 181 + .../AlfrescoScriptTaskItemProvider.java | 203 + .../AlfrescoStartEventItemProvider.java | 181 + .../AlfrescoUserTaskItemProvider.java | 181 + .../bpmn2/provider/ArtifactItemProvider.java | 115 + .../provider/AssignmentItemProvider.java | 167 + .../provider/AssociationItemProvider.java | 199 + .../bpmn2/provider/AuditingItemProvider.java | 127 + .../provider/BaseElementItemProvider.java | 231 + .../provider/BoundaryEventItemProvider.java | 179 + .../Bpmn2ItemProviderAdapterFactory.java | 3723 ++ .../BusinessRuleTaskItemProvider.java | 246 + .../provider/CallActivityItemProvider.java | 252 + .../CallChoreographyItemProvider.java | 200 + .../CallConversationItemProvider.java | 199 + .../provider/CallableElementItemProvider.java | 218 + .../CancelEventDefinitionItemProvider.java | 130 + .../provider/CandidateGroupItemProvider.java | 158 + .../provider/CandidateUserItemProvider.java | 158 + .../provider/CatchEventItemProvider.java | 270 + .../bpmn2/provider/CategoryItemProvider.java | 200 + .../provider/CategoryValueItemProvider.java | 180 + .../ChoreographyActivityItemProvider.java | 232 + .../provider/ChoreographyItemProvider.java | 349 + .../ChoreographyTaskItemProvider.java | 150 + .../provider/CollaborationItemProvider.java | 314 + ...CompensateEventDefinitionItemProvider.java | 186 + ...ComplexBehaviorDefinitionItemProvider.java | 185 + .../provider/ComplexDataTypeItemProvider.java | 115 + .../provider/ComplexGatewayItemProvider.java | 200 + ...onditionalEventDefinitionItemProvider.java | 183 + .../ConversationAssociationItemProvider.java | 176 + .../provider/ConversationItemProvider.java | 127 + .../ConversationLinkItemProvider.java | 198 + .../ConversationNodeItemProvider.java | 273 + .../provider/CorrelationKeyItemProvider.java | 180 + ...orrelationPropertyBindingItemProvider.java | 202 + .../CorrelationPropertyItemProvider.java | 223 + ...opertyRetrievalExpressionItemProvider.java | 179 + .../CorrelationSubscriptionItemProvider.java | 203 + .../provider/CustomPropertyItemProvider.java | 201 + .../provider/DataAssociationItemProvider.java | 223 + .../provider/DataGridFieldItemProvider.java | 180 + .../bpmn2/provider/DataGridItemProvider.java | 174 + .../provider/DataGridRowItemProvider.java | 202 + .../DataInputAssociationItemProvider.java | 129 + .../bpmn2/provider/DataInputItemProvider.java | 240 + .../provider/DataObjectItemProvider.java | 244 + .../DataObjectReferenceItemProvider.java | 239 + .../DataOutputAssociationItemProvider.java | 130 + .../provider/DataOutputItemProvider.java | 241 + .../bpmn2/provider/DataStateItemProvider.java | 157 + .../bpmn2/provider/DataStoreItemProvider.java | 201 + .../DataStoreReferenceItemProvider.java | 239 + .../provider/DefinitionsItemProvider.java | 466 + .../provider/DocumentRootItemProvider.java | 5518 +++ .../provider/DocumentationItemProvider.java | 179 + .../bpmn2/provider/EndEventItemProvider.java | 127 + .../bpmn2/provider/EndPointItemProvider.java | 127 + .../ErrorEventDefinitionItemProvider.java | 181 + .../bpmn2/provider/ErrorItemProvider.java | 195 + ...EscalationEventDefinitionItemProvider.java | 154 + .../provider/EscalationItemProvider.java | 214 + .../EventBasedGatewayItemProvider.java | 181 + .../provider/EventDefinitionItemProvider.java | 115 + .../bpmn2/provider/EventItemProvider.java | 207 + .../ExclusiveGatewayItemProvider.java | 149 + .../provider/ExpressionItemProvider.java | 127 + ...ensionAttributeDefinitionItemProvider.java | 226 + .../ExtensionAttributeValueItemProvider.java | 911 + .../ExtensionDefinitionItemProvider.java | 219 + .../bpmn2/provider/ExtensionItemProvider.java | 216 + .../provider/FieldExtensionItemProvider.java | 179 + .../provider/FlowElementItemProvider.java | 217 + .../FlowElementsContainerItemProvider.java | 337 + .../bpmn2/provider/FlowNodeItemProvider.java | 214 + .../provider/FormPropertyItemProvider.java | 306 + .../bpmn2/provider/FormValueItemProvider.java | 180 + .../FormalExpressionItemProvider.java | 198 + .../bpmn2/provider/GatewayItemProvider.java | 146 + .../GlobalBusinessRuleTaskItemProvider.java | 163 + .../GlobalChoreographyTaskItemProvider.java | 154 + .../GlobalConversationItemProvider.java | 127 + .../GlobalManualTaskItemProvider.java | 127 + .../GlobalScriptTaskItemProvider.java | 180 + .../provider/GlobalTaskItemProvider.java | 186 + .../provider/GlobalUserTaskItemProvider.java | 202 + .../bpmn2/provider/GroupItemProvider.java | 150 + .../provider/HumanPerformerItemProvider.java | 127 + .../provider/IOParameterItemProvider.java | 179 + .../ImplicitThrowEventItemProvider.java | 127 + .../bpmn2/provider/ImportItemProvider.java | 213 + .../InclusiveGatewayItemProvider.java | 149 + .../InputOutputBindingItemProvider.java | 202 + .../InputOutputSpecificationItemProvider.java | 199 + .../bpmn2/provider/InputSetItemProvider.java | 237 + .../provider/InteractionNodeItemProvider.java | 174 + .../bpmn2/provider/InterfaceItemProvider.java | 219 + .../IntermediateCatchEventItemProvider.java | 129 + .../IntermediateThrowEventItemProvider.java | 129 + .../ItemAwareElementItemProvider.java | 219 + .../provider/ItemDefinitionItemProvider.java | 220 + .../bpmn2/provider/LaneItemProvider.java | 865 + .../bpmn2/provider/LaneSetItemProvider.java | 199 + .../LinkEventDefinitionItemProvider.java | 199 + .../LoopCharacteristicsItemProvider.java | 115 + .../bpmn2/provider/MailTaskItemProvider.java | 277 + .../provider/ManualTaskItemProvider.java | 127 + .../MessageEventDefinitionItemProvider.java | 172 + .../MessageFlowAssociationItemProvider.java | 175 + .../provider/MessageFlowItemProvider.java | 220 + .../bpmn2/provider/MessageItemProvider.java | 176 + .../provider/MonitoringItemProvider.java | 127 + ...stanceLoopCharacteristicsItemProvider.java | 380 + .../bpmn2/provider/OperationItemProvider.java | 238 + .../bpmn2/provider/OutputSetItemProvider.java | 237 + .../provider/ParallelGatewayItemProvider.java | 127 + .../ParticipantAssociationItemProvider.java | 175 + .../provider/ParticipantItemProvider.java | 307 + .../ParticipantMultiplicityItemProvider.java | 199 + .../provider/PartnerEntityItemProvider.java | 178 + .../provider/PartnerRoleItemProvider.java | 180 + .../bpmn2/provider/PerformerItemProvider.java | 127 + .../provider/PotentialOwnerItemProvider.java | 127 + .../bpmn2/provider/ProcessItemProvider.java | 561 + .../bpmn2/provider/PropertyItemProvider.java | 157 + .../provider/ReceiveTaskItemProvider.java | 220 + .../provider/RelationshipItemProvider.java | 219 + .../bpmn2/provider/RenderingItemProvider.java | 127 + ...ourceAssignmentExpressionItemProvider.java | 199 + .../bpmn2/provider/ResourceItemProvider.java | 200 + .../ResourceParameterBindingItemProvider.java | 218 + .../ResourceParameterItemProvider.java | 200 + .../provider/ResourceRoleItemProvider.java | 231 + .../provider/RootElementItemProvider.java | 115 + .../provider/ScriptTaskItemProvider.java | 181 + .../bpmn2/provider/SendTaskItemProvider.java | 199 + .../provider/SequenceFlowItemProvider.java | 248 + .../provider/ServiceTaskItemProvider.java | 263 + .../SignalEventDefinitionItemProvider.java | 152 + .../bpmn2/provider/SignalItemProvider.java | 176 + ...andardLoopCharacteristicsItemProvider.java | 250 + .../provider/StartEventItemProvider.java | 246 + .../provider/SubChoreographyItemProvider.java | 350 + .../provider/SubConversationItemProvider.java | 127 + .../provider/SubProcessItemProvider.java | 376 + .../bpmn2/provider/TaskItemProvider.java | 173 + .../TerminateEventDefinitionItemProvider.java | 130 + .../provider/TextAnnotationItemProvider.java | 180 + .../provider/ThrowEventItemProvider.java | 244 + .../TimerEventDefinitionItemProvider.java | 227 + .../provider/TransactionItemProvider.java | 179 + .../bpmn2/provider/UserTaskItemProvider.java | 327 + .../dd/dc/provider/BoundsItemProvider.java | 232 + .../DcItemProviderAdapterFactory.java | 273 + .../dc/provider/DocumentRootItemProvider.java | 200 + .../dd/dc/provider/FontItemProvider.java | 273 + .../dd/dc/provider/PointItemProvider.java | 192 + .../DiItemProviderAdapterFactory.java | 216 + .../provider/DiagramElementItemProvider.java | 262 + .../dd/di/provider/DiagramItemProvider.java | 274 + .../di/provider/DocumentRootItemProvider.java | 295 + .../dd/di/provider/EdgeItemProvider.java | 219 + .../dd/di/provider/LabelItemProvider.java | 175 + .../di/provider/LabeledEdgeItemProvider.java | 149 + .../di/provider/LabeledShapeItemProvider.java | 137 + .../dd/di/provider/NodeItemProvider.java | 115 + .../dd/di/provider/PlaneItemProvider.java | 187 + .../dd/di/provider/ShapeItemProvider.java | 175 + .../dd/di/provider/StyleItemProvider.java | 161 + .../provider/ActionItemProvider.java | 179 + .../provider/ActivityActionItemProvider.java | 151 + ...tyAuthorizationConstraintItemProvider.java | 156 + .../AtomicActivityActionItemProvider.java | 129 + ...micItemAwareElementActionItemProvider.java | 132 + .../AtomicProcessActionItemProvider.java | 127 + .../AuthorizationConstraintItemProvider.java | 234 + .../provider/BindingOfDutyItemProvider.java | 184 + .../CompositeActivityActionItemProvider.java | 154 + ...iteItemAwareElementActionItemProvider.java | 156 + .../CompositeProcessActionItemProvider.java | 154 + .../provider/GroupItemProvider.java | 176 + .../ItemAwareElementActionItemProvider.java | 154 + .../provider/NeedToKnowItemProvider.java | 127 + .../provider/PermissionItemProvider.java | 222 + .../provider/ProcessActionItemProvider.java | 151 + .../provider/RoleItemProvider.java | 233 + ...Securebpmn2ItemProviderAdapterFactory.java | 703 + .../provider/SecurityFlowItemProvider.java | 184 + .../SecurityFlowNodeItemProvider.java | 142 + .../SeparationOfDutyItemProvider.java | 184 + .../provider/SubjectItemProvider.java | 170 + .../provider/UserItemProvider.java | 157 + .../securebpmn2/provider/bpmn2EditPlugin.java | 99 + .../.classpath | 7 + .../.project | 28 + .../META-INF/MANIFEST.MF | 21 + .../build.properties | 21 + .../icons/full/obj16/Bpmn2ModelFile.gif | Bin 0 -> 346 bytes .../icons/full/obj16/BpmnDiModelFile.gif | Bin 0 -> 346 bytes .../icons/full/obj16/DcModelFile.gif | Bin 0 -> 346 bytes .../icons/full/obj16/DiModelFile.gif | Bin 0 -> 346 bytes .../icons/full/obj16/Securebpmn2ModelFile.gif | Bin 0 -> 346 bytes .../icons/full/wizban/NewBpmn2.gif | Bin 0 -> 2462 bytes .../icons/full/wizban/NewSecurebpmn2.gif | Bin 0 -> 2462 bytes .../plugin.properties | 84 + .../plugin.xml | 106 + .../BpmnDiActionBarContributor.java | 459 + .../bpmn2/di/presentation/BpmnDiEditor.java | 1616 + .../Bpmn2ActionBarContributor.java | 459 + .../bpmn2/presentation/Bpmn2Editor.java | 1614 + .../bpmn2/presentation/Bpmn2ModelWizard.java | 692 + .../presentation/DcActionBarContributor.java | 459 + .../eclipse/dd/dc/presentation/DcEditor.java | 1614 + .../presentation/DiActionBarContributor.java | 459 + .../eclipse/dd/di/presentation/DiEditor.java | 1614 + .../Securebpmn2ActionBarContributor.java | 458 + .../presentation/Securebpmn2Editor.java | 1614 + .../presentation/Securebpmn2ModelWizard.java | 678 + .../presentation/bpmn2EditorPlugin.java | 101 + .../META-INF/MANIFEST.MF | 19 + .../build.properties | 19 + .../plugin.properties | 15 + .../bpmn2/di/tests/BPMNDiagramTest.java | 84 + .../eclipse/bpmn2/di/tests/BPMNEdgeTest.java | 84 + .../bpmn2/di/tests/BPMNLabelStyleTest.java | 84 + .../eclipse/bpmn2/di/tests/BPMNLabelTest.java | 84 + .../eclipse/bpmn2/di/tests/BPMNPlaneTest.java | 84 + .../eclipse/bpmn2/di/tests/BPMNShapeTest.java | 84 + .../eclipse/bpmn2/di/tests/BpmnDiExample.java | 139 + .../eclipse/bpmn2/di/tests/BpmnDiTests.java | 64 + .../bpmn2/di/tests/DocumentRootTest.java | 268 + .../bpmn2/tests/ActivitiListenerTest.java | 82 + .../org/eclipse/bpmn2/tests/ActivityTest.java | 67 + .../bpmn2/tests/AdHocSubProcessTest.java | 82 + .../bpmn2/tests/AlfrescoMailTaskTest.java | 82 + .../bpmn2/tests/AlfrescoScriptBaseTest.java | 82 + .../bpmn2/tests/AlfrescoScriptTaskTest.java | 82 + .../bpmn2/tests/AlfrescoStartEventTest.java | 82 + .../bpmn2/tests/AlfrescoUserTaskTest.java | 82 + .../org/eclipse/bpmn2/tests/ArtifactTest.java | 48 + .../eclipse/bpmn2/tests/AssignmentTest.java | 82 + .../eclipse/bpmn2/tests/AssociationTest.java | 82 + .../org/eclipse/bpmn2/tests/AuditingTest.java | 82 + .../eclipse/bpmn2/tests/BaseElementTest.java | 86 + .../bpmn2/tests/BoundaryEventTest.java | 82 + .../org/eclipse/bpmn2/tests/Bpmn2Example.java | 140 + .../org/eclipse/bpmn2/tests/Bpmn2Tests.java | 190 + .../bpmn2/tests/BusinessRuleTaskTest.java | 82 + .../eclipse/bpmn2/tests/CallActivityTest.java | 82 + .../bpmn2/tests/CallChoreographyTest.java | 82 + .../bpmn2/tests/CallConversationTest.java | 82 + .../bpmn2/tests/CallableElementTest.java | 48 + .../tests/CancelEventDefinitionTest.java | 82 + .../bpmn2/tests/CandidateGroupTest.java | 82 + .../bpmn2/tests/CandidateUserTest.java | 82 + .../eclipse/bpmn2/tests/CatchEventTest.java | 48 + .../org/eclipse/bpmn2/tests/CategoryTest.java | 82 + .../bpmn2/tests/CategoryValueTest.java | 101 + .../bpmn2/tests/ChoreographyActivityTest.java | 48 + .../bpmn2/tests/ChoreographyTaskTest.java | 82 + .../eclipse/bpmn2/tests/ChoreographyTest.java | 82 + .../bpmn2/tests/CollaborationTest.java | 82 + .../tests/CompensateEventDefinitionTest.java | 82 + .../tests/ComplexBehaviorDefinitionTest.java | 82 + .../bpmn2/tests/ComplexDataTypeTest.java | 48 + .../bpmn2/tests/ComplexGatewayTest.java | 82 + .../tests/ConditionalEventDefinitionTest.java | 82 + .../tests/ConversationAssociationTest.java | 82 + .../bpmn2/tests/ConversationLinkTest.java | 82 + .../bpmn2/tests/ConversationNodeTest.java | 81 + .../eclipse/bpmn2/tests/ConversationTest.java | 82 + .../bpmn2/tests/CorrelationKeyTest.java | 82 + .../tests/CorrelationPropertyBindingTest.java | 82 + ...lationPropertyRetrievalExpressionTest.java | 83 + .../bpmn2/tests/CorrelationPropertyTest.java | 82 + .../tests/CorrelationSubscriptionTest.java | 82 + .../bpmn2/tests/CustomPropertyTest.java | 82 + .../bpmn2/tests/DataAssociationTest.java | 82 + .../bpmn2/tests/DataGridFieldTest.java | 82 + .../eclipse/bpmn2/tests/DataGridRowTest.java | 82 + .../org/eclipse/bpmn2/tests/DataGridTest.java | 82 + .../bpmn2/tests/DataInputAssociationTest.java | 82 + .../eclipse/bpmn2/tests/DataInputTest.java | 129 + .../bpmn2/tests/DataObjectReferenceTest.java | 82 + .../eclipse/bpmn2/tests/DataObjectTest.java | 82 + .../tests/DataOutputAssociationTest.java | 82 + .../eclipse/bpmn2/tests/DataOutputTest.java | 129 + .../eclipse/bpmn2/tests/DataStateTest.java | 82 + .../bpmn2/tests/DataStoreReferenceTest.java | 82 + .../eclipse/bpmn2/tests/DataStoreTest.java | 82 + .../eclipse/bpmn2/tests/DefinitionsTest.java | 82 + .../eclipse/bpmn2/tests/DocumentRootTest.java | 3738 ++ .../bpmn2/tests/DocumentationTest.java | 82 + .../org/eclipse/bpmn2/tests/EndEventTest.java | 82 + .../org/eclipse/bpmn2/tests/EndPointTest.java | 82 + .../bpmn2/tests/ErrorEventDefinitionTest.java | 82 + .../org/eclipse/bpmn2/tests/ErrorTest.java | 81 + .../tests/EscalationEventDefinitionTest.java | 82 + .../eclipse/bpmn2/tests/EscalationTest.java | 101 + .../bpmn2/tests/EventBasedGatewayTest.java | 82 + .../bpmn2/tests/EventDefinitionTest.java | 82 + .../org/eclipse/bpmn2/tests/EventTest.java | 81 + .../bpmn2/tests/ExclusiveGatewayTest.java | 82 + .../eclipse/bpmn2/tests/ExpressionTest.java | 82 + .../ExtensionAttributeDefinitionTest.java | 133 + .../tests/ExtensionAttributeValueTest.java | 187 + .../bpmn2/tests/ExtensionDefinitionTest.java | 120 + .../eclipse/bpmn2/tests/ExtensionTest.java | 101 + .../bpmn2/tests/FieldExtensionTest.java | 82 + .../eclipse/bpmn2/tests/FlowElementTest.java | 48 + .../tests/FlowElementsContainerTest.java | 48 + .../org/eclipse/bpmn2/tests/FlowNodeTest.java | 67 + .../eclipse/bpmn2/tests/FormPropertyTest.java | 82 + .../eclipse/bpmn2/tests/FormValueTest.java | 82 + .../bpmn2/tests/FormalExpressionTest.java | 82 + .../org/eclipse/bpmn2/tests/GatewayTest.java | 48 + .../tests/GlobalBusinessRuleTaskTest.java | 82 + .../tests/GlobalChoreographyTaskTest.java | 82 + .../bpmn2/tests/GlobalConversationTest.java | 82 + .../bpmn2/tests/GlobalManualTaskTest.java | 82 + .../bpmn2/tests/GlobalScriptTaskTest.java | 82 + .../eclipse/bpmn2/tests/GlobalTaskTest.java | 82 + .../bpmn2/tests/GlobalUserTaskTest.java | 82 + .../org/eclipse/bpmn2/tests/GroupTest.java | 82 + .../bpmn2/tests/HumanPerformerTest.java | 82 + .../eclipse/bpmn2/tests/IOParameterTest.java | 82 + .../bpmn2/tests/ImplicitThrowEventTest.java | 82 + .../org/eclipse/bpmn2/tests/ImportTest.java | 101 + .../bpmn2/tests/InclusiveGatewayTest.java | 82 + .../bpmn2/tests/InputOutputBindingTest.java | 101 + .../tests/InputOutputSpecificationTest.java | 82 + .../org/eclipse/bpmn2/tests/InputSetTest.java | 82 + .../bpmn2/tests/InteractionNodeTest.java | 100 + .../eclipse/bpmn2/tests/InterfaceTest.java | 82 + .../tests/IntermediateCatchEventTest.java | 82 + .../tests/IntermediateThrowEventTest.java | 82 + .../bpmn2/tests/ItemAwareElementTest.java | 82 + .../bpmn2/tests/ItemDefinitionTest.java | 114 + .../org/eclipse/bpmn2/tests/LaneSetTest.java | 82 + .../src/org/eclipse/bpmn2/tests/LaneTest.java | 82 + .../bpmn2/tests/LinkEventDefinitionTest.java | 82 + .../bpmn2/tests/LoopCharacteristicsTest.java | 48 + .../org/eclipse/bpmn2/tests/MailTaskTest.java | 82 + .../eclipse/bpmn2/tests/ManualTaskTest.java | 82 + .../tests/MessageEventDefinitionTest.java | 82 + .../tests/MessageFlowAssociationTest.java | 82 + .../eclipse/bpmn2/tests/MessageFlowTest.java | 82 + .../org/eclipse/bpmn2/tests/MessageTest.java | 82 + .../eclipse/bpmn2/tests/MonitoringTest.java | 82 + .../MultiInstanceLoopCharacteristicsTest.java | 84 + .../eclipse/bpmn2/tests/OperationTest.java | 82 + .../eclipse/bpmn2/tests/OutputSetTest.java | 82 + .../bpmn2/tests/ParallelGatewayTest.java | 82 + .../tests/ParticipantAssociationTest.java | 82 + .../tests/ParticipantMultiplicityTest.java | 101 + .../eclipse/bpmn2/tests/ParticipantTest.java | 115 + .../bpmn2/tests/PartnerEntityTest.java | 82 + .../eclipse/bpmn2/tests/PartnerRoleTest.java | 82 + .../eclipse/bpmn2/tests/PerformerTest.java | 82 + .../bpmn2/tests/PotentialOwnerTest.java | 82 + .../org/eclipse/bpmn2/tests/ProcessTest.java | 81 + .../org/eclipse/bpmn2/tests/PropertyTest.java | 82 + .../eclipse/bpmn2/tests/ReceiveTaskTest.java | 82 + .../eclipse/bpmn2/tests/RelationshipTest.java | 82 + .../eclipse/bpmn2/tests/RenderingTest.java | 82 + .../ResourceAssignmentExpressionTest.java | 101 + .../tests/ResourceParameterBindingTest.java | 101 + .../bpmn2/tests/ResourceParameterTest.java | 82 + .../eclipse/bpmn2/tests/ResourceRoleTest.java | 82 + .../org/eclipse/bpmn2/tests/ResourceTest.java | 82 + .../eclipse/bpmn2/tests/RootElementTest.java | 48 + .../eclipse/bpmn2/tests/ScriptTaskTest.java | 82 + .../org/eclipse/bpmn2/tests/SendTaskTest.java | 82 + .../eclipse/bpmn2/tests/SequenceFlowTest.java | 82 + .../eclipse/bpmn2/tests/ServiceTaskTest.java | 82 + .../tests/SignalEventDefinitionTest.java | 82 + .../org/eclipse/bpmn2/tests/SignalTest.java | 82 + .../StandardLoopCharacteristicsTest.java | 82 + .../eclipse/bpmn2/tests/StartEventTest.java | 82 + .../bpmn2/tests/SubChoreographyTest.java | 82 + .../bpmn2/tests/SubConversationTest.java | 82 + .../eclipse/bpmn2/tests/SubProcessTest.java | 82 + .../src/org/eclipse/bpmn2/tests/TaskTest.java | 115 + .../tests/TerminateEventDefinitionTest.java | 82 + .../bpmn2/tests/TextAnnotationTest.java | 82 + .../eclipse/bpmn2/tests/ThrowEventTest.java | 48 + .../bpmn2/tests/TimerEventDefinitionTest.java | 82 + .../eclipse/bpmn2/tests/TransactionTest.java | 82 + .../org/eclipse/bpmn2/tests/UserTaskTest.java | 82 + .../org/eclipse/dd/dc/tests/BoundsTest.java | 101 + .../org/eclipse/dd/dc/tests/DcExample.java | 139 + .../src/org/eclipse/dd/dc/tests/DcTests.java | 60 + .../eclipse/dd/dc/tests/DocumentRootTest.java | 187 + .../src/org/eclipse/dd/dc/tests/FontTest.java | 120 + .../org/eclipse/dd/dc/tests/PointTest.java | 101 + .../org/eclipse/dd/di/tests/DiExample.java | 135 + .../src/org/eclipse/dd/di/tests/DiTests.java | 59 + .../dd/di/tests/DiagramElementTest.java | 142 + .../org/eclipse/dd/di/tests/DiagramTest.java | 100 + .../eclipse/dd/di/tests/DocumentRootTest.java | 376 + .../src/org/eclipse/dd/di/tests/EdgeTest.java | 81 + .../org/eclipse/dd/di/tests/LabelTest.java | 48 + .../eclipse/dd/di/tests/LabeledEdgeTest.java | 67 + .../eclipse/dd/di/tests/LabeledShapeTest.java | 67 + .../src/org/eclipse/dd/di/tests/NodeTest.java | 48 + .../org/eclipse/dd/di/tests/PlaneTest.java | 67 + .../org/eclipse/dd/di/tests/ShapeTest.java | 48 + .../org/eclipse/dd/di/tests/StyleTest.java | 67 + .../eclipse/securebpmn2/tests/ActionTest.java | 50 + .../securebpmn2/tests/ActivityActionTest.java | 82 + .../ActivityAuthorizationConstraintTest.java | 84 + .../tests/AtomicActivityActionTest.java | 82 + .../AtomicItemAwareElementActionTest.java | 84 + .../tests/AtomicProcessActionTest.java | 82 + .../tests/AuthorizationConstraintTest.java | 82 + .../securebpmn2/tests/BindingOfDutyTest.java | 82 + .../tests/CompositeActivityActionTest.java | 82 + .../CompositeItemAwareElementActionTest.java | 84 + .../tests/CompositeProcessActionTest.java | 82 + .../eclipse/securebpmn2/tests/GroupTest.java | 82 + .../tests/ItemAwareElementActionTest.java | 82 + .../securebpmn2/tests/NeedToKnowTest.java | 82 + .../securebpmn2/tests/PermissionTest.java | 84 + .../securebpmn2/tests/ProcessActionTest.java | 82 + .../eclipse/securebpmn2/tests/RoleTest.java | 82 + .../securebpmn2/tests/Securebpmn2Example.java | 136 + .../securebpmn2/tests/Securebpmn2Tests.java | 78 + .../tests/SecurityFlowNodeTest.java | 84 + .../securebpmn2/tests/SecurityFlowTest.java | 84 + .../tests/SeparationOfDutyTest.java | 82 + .../securebpmn2/tests/SubjectTest.java | 50 + .../eclipse/securebpmn2/tests/UserTest.java | 82 + .../securebpmn2/tests/bpmn2AllTests.java | 71 + .../META-INF/MANIFEST.MF | 31 + .../build.properties | 11 + .../model/BPMN20.ecore | 4566 ++ .../model/BPMN20.genmodel | 1102 + .../model/BPMNDI.ecore | 270 + .../model/DC.ecore | 180 + .../model/DI.ecore | 303 + .../model/SecureBPMN20.ecore | 118 + .../plugin.properties | 15 + src/org.activiti.designer.model/plugin.xml | 69 + src/org.activiti.designer.model/pom.xml | 15 + .../org/eclipse/bpmn2/ActivitiListener.java | 187 + .../main/java/org/eclipse/bpmn2/Activity.java | 383 + .../java/org/eclipse/bpmn2/AdHocOrdering.java | 220 + .../org/eclipse/bpmn2/AdHocSubProcess.java | 121 + .../org/eclipse/bpmn2/AlfrescoMailTask.java | 114 + .../org/eclipse/bpmn2/AlfrescoScriptBase.java | 87 + .../org/eclipse/bpmn2/AlfrescoScriptTask.java | 60 + .../org/eclipse/bpmn2/AlfrescoStartEvent.java | 28 + .../org/eclipse/bpmn2/AlfrescoUserTask.java | 28 + .../main/java/org/eclipse/bpmn2/Artifact.java | 29 + .../java/org/eclipse/bpmn2/Assignment.java | 89 + .../java/org/eclipse/bpmn2/Association.java | 120 + .../eclipse/bpmn2/AssociationDirection.java | 247 + .../main/java/org/eclipse/bpmn2/Auditing.java | 28 + .../java/org/eclipse/bpmn2/BaseElement.java | 119 + .../java/org/eclipse/bpmn2/BoundaryEvent.java | 92 + .../java/org/eclipse/bpmn2/Bpmn2Factory.java | 1296 + .../java/org/eclipse/bpmn2/Bpmn2Package.java | 34751 ++++++++++++++++ .../org/eclipse/bpmn2/BusinessRuleTask.java | 151 + .../java/org/eclipse/bpmn2/CallActivity.java | 124 + .../org/eclipse/bpmn2/CallChoreography.java | 81 + .../org/eclipse/bpmn2/CallConversation.java | 81 + .../org/eclipse/bpmn2/CallableElement.java | 128 + .../eclipse/bpmn2/CancelEventDefinition.java | 28 + .../org/eclipse/bpmn2/CandidateGroup.java | 60 + .../java/org/eclipse/bpmn2/CandidateUser.java | 60 + .../java/org/eclipse/bpmn2/CatchEvent.java | 164 + .../main/java/org/eclipse/bpmn2/Category.java | 81 + .../java/org/eclipse/bpmn2/CategoryValue.java | 82 + .../java/org/eclipse/bpmn2/Choreography.java | 28 + .../eclipse/bpmn2/ChoreographyActivity.java | 132 + .../eclipse/bpmn2/ChoreographyLoopType.java | 275 + .../org/eclipse/bpmn2/ChoreographyTask.java | 53 + .../java/org/eclipse/bpmn2/Collaboration.java | 281 + .../bpmn2/CompensateEventDefinition.java | 89 + .../bpmn2/ComplexBehaviorDefinition.java | 89 + .../org/eclipse/bpmn2/ComplexDataType.java | 28 + .../org/eclipse/bpmn2/ComplexGateway.java | 89 + .../bpmn2/ConditionalEventDefinition.java | 61 + .../java/org/eclipse/bpmn2/Conversation.java | 28 + .../bpmn2/ConversationAssociation.java | 89 + .../org/eclipse/bpmn2/ConversationLink.java | 121 + .../org/eclipse/bpmn2/ConversationNode.java | 118 + .../org/eclipse/bpmn2/CorrelationKey.java | 81 + .../eclipse/bpmn2/CorrelationProperty.java | 109 + .../bpmn2/CorrelationPropertyBinding.java | 89 + ...orrelationPropertyRetrievalExpression.java | 89 + .../bpmn2/CorrelationSubscription.java | 81 + .../org/eclipse/bpmn2/CustomProperty.java | 114 + .../org/eclipse/bpmn2/DataAssociation.java | 127 + .../main/java/org/eclipse/bpmn2/DataGrid.java | 52 + .../java/org/eclipse/bpmn2/DataGridField.java | 87 + .../java/org/eclipse/bpmn2/DataGridRow.java | 79 + .../java/org/eclipse/bpmn2/DataInput.java | 149 + .../eclipse/bpmn2/DataInputAssociation.java | 28 + .../java/org/eclipse/bpmn2/DataObject.java | 62 + .../eclipse/bpmn2/DataObjectReference.java | 61 + .../java/org/eclipse/bpmn2/DataOutput.java | 149 + .../eclipse/bpmn2/DataOutputAssociation.java | 28 + .../java/org/eclipse/bpmn2/DataState.java | 61 + .../java/org/eclipse/bpmn2/DataStore.java | 118 + .../org/eclipse/bpmn2/DataStoreReference.java | 61 + .../java/org/eclipse/bpmn2/Definitions.java | 297 + .../java/org/eclipse/bpmn2/DocumentRoot.java | 3866 ++ .../java/org/eclipse/bpmn2/Documentation.java | 89 + .../main/java/org/eclipse/bpmn2/EndEvent.java | 28 + .../main/java/org/eclipse/bpmn2/EndPoint.java | 28 + .../main/java/org/eclipse/bpmn2/Error.java | 117 + .../eclipse/bpmn2/ErrorEventDefinition.java | 88 + .../java/org/eclipse/bpmn2/Escalation.java | 119 + .../bpmn2/EscalationEventDefinition.java | 61 + .../main/java/org/eclipse/bpmn2/Event.java | 54 + .../org/eclipse/bpmn2/EventBasedGateway.java | 93 + .../eclipse/bpmn2/EventBasedGatewayType.java | 220 + .../org/eclipse/bpmn2/EventDefinition.java | 28 + .../org/eclipse/bpmn2/ExclusiveGateway.java | 61 + .../java/org/eclipse/bpmn2/Expression.java | 28 + .../java/org/eclipse/bpmn2/Extension.java | 92 + .../bpmn2/ExtensionAttributeDefinition.java | 146 + .../bpmn2/ExtensionAttributeValue.java | 116 + .../eclipse/bpmn2/ExtensionDefinition.java | 83 + .../org/eclipse/bpmn2/FieldExtension.java | 87 + .../java/org/eclipse/bpmn2/FlowElement.java | 140 + .../eclipse/bpmn2/FlowElementsContainer.java | 71 + .../main/java/org/eclipse/bpmn2/FlowNode.java | 135 + .../java/org/eclipse/bpmn2/FormProperty.java | 214 + .../java/org/eclipse/bpmn2/FormValue.java | 87 + .../org/eclipse/bpmn2/FormalExpression.java | 116 + .../main/java/org/eclipse/bpmn2/Gateway.java | 66 + .../org/eclipse/bpmn2/GatewayDirection.java | 274 + .../eclipse/bpmn2/GlobalBusinessRuleTask.java | 61 + .../eclipse/bpmn2/GlobalChoreographyTask.java | 61 + .../org/eclipse/bpmn2/GlobalConversation.java | 28 + .../org/eclipse/bpmn2/GlobalManualTask.java | 28 + .../org/eclipse/bpmn2/GlobalScriptTask.java | 89 + .../java/org/eclipse/bpmn2/GlobalTask.java | 53 + .../org/eclipse/bpmn2/GlobalUserTask.java | 81 + .../main/java/org/eclipse/bpmn2/Group.java | 61 + .../org/eclipse/bpmn2/HumanPerformer.java | 28 + .../java/org/eclipse/bpmn2/IOParameter.java | 87 + .../org/eclipse/bpmn2/ImplicitThrowEvent.java | 28 + .../main/java/org/eclipse/bpmn2/Import.java | 119 + .../org/eclipse/bpmn2/InclusiveGateway.java | 61 + .../org/eclipse/bpmn2/InputOutputBinding.java | 119 + .../bpmn2/InputOutputSpecification.java | 107 + .../main/java/org/eclipse/bpmn2/InputSet.java | 143 + .../org/eclipse/bpmn2/InteractionNode.java | 75 + .../java/org/eclipse/bpmn2/Interface.java | 109 + .../eclipse/bpmn2/IntermediateCatchEvent.java | 28 + .../eclipse/bpmn2/IntermediateThrowEvent.java | 28 + .../org/eclipse/bpmn2/ItemAwareElement.java | 112 + .../org/eclipse/bpmn2/ItemDefinition.java | 148 + .../main/java/org/eclipse/bpmn2/ItemKind.java | 220 + .../src/main/java/org/eclipse/bpmn2/Lane.java | 167 + .../main/java/org/eclipse/bpmn2/LaneSet.java | 81 + .../eclipse/bpmn2/LinkEventDefinition.java | 113 + .../eclipse/bpmn2/LoopCharacteristics.java | 29 + .../main/java/org/eclipse/bpmn2/MailTask.java | 224 + .../java/org/eclipse/bpmn2/ManualTask.java | 28 + .../main/java/org/eclipse/bpmn2/Message.java | 89 + .../eclipse/bpmn2/MessageEventDefinition.java | 89 + .../java/org/eclipse/bpmn2/MessageFlow.java | 145 + .../eclipse/bpmn2/MessageFlowAssociation.java | 89 + .../java/org/eclipse/bpmn2/Monitoring.java | 28 + .../eclipse/bpmn2/MultiInstanceBehavior.java | 274 + .../MultiInstanceLoopCharacteristics.java | 362 + .../java/org/eclipse/bpmn2/Operation.java | 165 + .../java/org/eclipse/bpmn2/OutputSet.java | 143 + .../org/eclipse/bpmn2/ParallelGateway.java | 28 + .../java/org/eclipse/bpmn2/Participant.java | 155 + .../eclipse/bpmn2/ParticipantAssociation.java | 89 + .../bpmn2/ParticipantMultiplicity.java | 93 + .../java/org/eclipse/bpmn2/PartnerEntity.java | 81 + .../java/org/eclipse/bpmn2/PartnerRole.java | 81 + .../java/org/eclipse/bpmn2/Performer.java | 28 + .../org/eclipse/bpmn2/PotentialOwner.java | 28 + .../main/java/org/eclipse/bpmn2/Process.java | 389 + .../java/org/eclipse/bpmn2/ProcessType.java | 247 + .../main/java/org/eclipse/bpmn2/Property.java | 61 + .../java/org/eclipse/bpmn2/ReceiveTask.java | 146 + .../java/org/eclipse/bpmn2/Relationship.java | 132 + .../eclipse/bpmn2/RelationshipDirection.java | 274 + .../java/org/eclipse/bpmn2/Rendering.java | 28 + .../main/java/org/eclipse/bpmn2/Resource.java | 81 + .../bpmn2/ResourceAssignmentExpression.java | 63 + .../org/eclipse/bpmn2/ResourceParameter.java | 117 + .../bpmn2/ResourceParameterBinding.java | 91 + .../java/org/eclipse/bpmn2/ResourceRole.java | 137 + .../java/org/eclipse/bpmn2/RootElement.java | 29 + .../java/org/eclipse/bpmn2/ScriptTask.java | 89 + .../main/java/org/eclipse/bpmn2/SendTask.java | 117 + .../java/org/eclipse/bpmn2/SequenceFlow.java | 168 + .../java/org/eclipse/bpmn2/ServiceTask.java | 179 + .../main/java/org/eclipse/bpmn2/Signal.java | 89 + .../eclipse/bpmn2/SignalEventDefinition.java | 61 + .../bpmn2/StandardLoopCharacteristics.java | 118 + .../java/org/eclipse/bpmn2/StartEvent.java | 135 + .../org/eclipse/bpmn2/SubChoreography.java | 54 + .../org/eclipse/bpmn2/SubConversation.java | 53 + .../java/org/eclipse/bpmn2/SubProcess.java | 82 + .../src/main/java/org/eclipse/bpmn2/Task.java | 28 + .../bpmn2/TerminateEventDefinition.java | 28 + .../org/eclipse/bpmn2/TextAnnotation.java | 90 + .../java/org/eclipse/bpmn2/ThrowEvent.java | 136 + .../eclipse/bpmn2/TimerEventDefinition.java | 117 + .../java/org/eclipse/bpmn2/Transaction.java | 88 + .../main/java/org/eclipse/bpmn2/UserTask.java | 240 + .../org/eclipse/bpmn2/di/BPMNDiagram.java | 83 + .../java/org/eclipse/bpmn2/di/BPMNEdge.java | 181 + .../java/org/eclipse/bpmn2/di/BPMNLabel.java | 63 + .../org/eclipse/bpmn2/di/BPMNLabelStyle.java | 65 + .../java/org/eclipse/bpmn2/di/BPMNPlane.java | 65 + .../java/org/eclipse/bpmn2/di/BPMNShape.java | 264 + .../org/eclipse/bpmn2/di/BpmnDiFactory.java | 109 + .../org/eclipse/bpmn2/di/BpmnDiPackage.java | 1560 + .../org/eclipse/bpmn2/di/DocumentRoot.java | 263 + .../eclipse/bpmn2/di/MessageVisibleKind.java | 220 + .../eclipse/bpmn2/di/ParticipantBandKind.java | 329 + .../bpmn2/di/impl/BPMNDiagramImpl.java | 251 + .../eclipse/bpmn2/di/impl/BPMNEdgeImpl.java | 473 + .../eclipse/bpmn2/di/impl/BPMNLabelImpl.java | 175 + .../bpmn2/di/impl/BPMNLabelStyleImpl.java | 203 + .../eclipse/bpmn2/di/impl/BPMNPlaneImpl.java | 176 + .../eclipse/bpmn2/di/impl/BPMNShapeImpl.java | 636 + .../bpmn2/di/impl/BpmnDiFactoryImpl.java | 268 + .../bpmn2/di/impl/BpmnDiPackageImpl.java | 923 + .../bpmn2/di/impl/DocumentRootImpl.java | 553 + .../bpmn2/di/util/BpmnDiAdapterFactory.java | 446 + .../di/util/BpmnDiResourceFactoryImpl.java | 70 + .../bpmn2/di/util/BpmnDiResourceImpl.java | 40 + .../eclipse/bpmn2/di/util/BpmnDiSwitch.java | 460 + .../bpmn2/di/util/BpmnDiXMLProcessor.java | 62 + .../bpmn2/impl/ActivitiListenerImpl.java | 470 + .../org/eclipse/bpmn2/impl/ActivityImpl.java | 936 + .../bpmn2/impl/AdHocSubProcessImpl.java | 338 + .../bpmn2/impl/AlfrescoMailTaskImpl.java | 292 + .../bpmn2/impl/AlfrescoScriptBaseImpl.java | 235 + .../bpmn2/impl/AlfrescoScriptTaskImpl.java | 333 + .../bpmn2/impl/AlfrescoStartEventImpl.java | 276 + .../bpmn2/impl/AlfrescoUserTaskImpl.java | 276 + .../org/eclipse/bpmn2/impl/ArtifactImpl.java | 51 + .../eclipse/bpmn2/impl/AssignmentImpl.java | 274 + .../eclipse/bpmn2/impl/AssociationImpl.java | 312 + .../org/eclipse/bpmn2/impl/AuditingImpl.java | 51 + .../eclipse/bpmn2/impl/BaseElementImpl.java | 324 + .../eclipse/bpmn2/impl/BoundaryEventImpl.java | 291 + .../eclipse/bpmn2/impl/Bpmn2FactoryImpl.java | 2208 + .../eclipse/bpmn2/impl/Bpmn2PackageImpl.java | 8614 ++++ .../bpmn2/impl/BusinessRuleTaskImpl.java | 373 + .../eclipse/bpmn2/impl/CallActivityImpl.java | 349 + .../bpmn2/impl/CallChoreographyImpl.java | 241 + .../bpmn2/impl/CallConversationImpl.java | 242 + .../bpmn2/impl/CallableElementImpl.java | 369 + .../bpmn2/impl/CancelEventDefinitionImpl.java | 52 + .../bpmn2/impl/CandidateGroupImpl.java | 178 + .../eclipse/bpmn2/impl/CandidateUserImpl.java | 177 + .../eclipse/bpmn2/impl/CatchEventImpl.java | 445 + .../org/eclipse/bpmn2/impl/CategoryImpl.java | 242 + .../eclipse/bpmn2/impl/CategoryValueImpl.java | 261 + .../bpmn2/impl/ChoreographyActivityImpl.java | 355 + .../eclipse/bpmn2/impl/ChoreographyImpl.java | 248 + .../bpmn2/impl/ChoreographyTaskImpl.java | 149 + .../eclipse/bpmn2/impl/CollaborationImpl.java | 713 + .../impl/CompensateEventDefinitionImpl.java | 249 + .../impl/ComplexBehaviorDefinitionImpl.java | 294 + .../bpmn2/impl/ComplexDataTypeImpl.java | 52 + .../bpmn2/impl/ComplexGatewayImpl.java | 251 + .../impl/ConditionalEventDefinitionImpl.java | 208 + .../impl/ConversationAssociationImpl.java | 253 + .../eclipse/bpmn2/impl/ConversationImpl.java | 52 + .../bpmn2/impl/ConversationLinkImpl.java | 389 + .../bpmn2/impl/ConversationNodeImpl.java | 470 + .../bpmn2/impl/CorrelationKeyImpl.java | 225 + .../impl/CorrelationPropertyBindingImpl.java | 279 + .../bpmn2/impl/CorrelationPropertyImpl.java | 310 + ...lationPropertyRetrievalExpressionImpl.java | 281 + .../impl/CorrelationSubscriptionImpl.java | 242 + .../bpmn2/impl/CustomPropertyImpl.java | 332 + .../bpmn2/impl/DataAssociationImpl.java | 340 + .../eclipse/bpmn2/impl/DataGridFieldImpl.java | 234 + .../org/eclipse/bpmn2/impl/DataGridImpl.java | 165 + .../eclipse/bpmn2/impl/DataGridRowImpl.java | 239 + .../bpmn2/impl/DataInputAssociationImpl.java | 52 + .../org/eclipse/bpmn2/impl/DataInputImpl.java | 405 + .../eclipse/bpmn2/impl/DataObjectImpl.java | 456 + .../bpmn2/impl/DataObjectReferenceImpl.java | 438 + .../bpmn2/impl/DataOutputAssociationImpl.java | 52 + .../eclipse/bpmn2/impl/DataOutputImpl.java | 406 + .../org/eclipse/bpmn2/impl/DataStateImpl.java | 177 + .../org/eclipse/bpmn2/impl/DataStoreImpl.java | 288 + .../bpmn2/impl/DataStoreReferenceImpl.java | 459 + .../eclipse/bpmn2/impl/DefinitionsImpl.java | 685 + .../eclipse/bpmn2/impl/DocumentRootImpl.java | 6649 +++ .../eclipse/bpmn2/impl/DocumentationImpl.java | 234 + .../org/eclipse/bpmn2/impl/EndEventImpl.java | 51 + .../org/eclipse/bpmn2/impl/EndPointImpl.java | 51 + .../bpmn2/impl/ErrorEventDefinitionImpl.java | 245 + .../org/eclipse/bpmn2/impl/ErrorImpl.java | 300 + .../impl/EscalationEventDefinitionImpl.java | 176 + .../eclipse/bpmn2/impl/EscalationImpl.java | 302 + .../bpmn2/impl/EventBasedGatewayImpl.java | 236 + .../bpmn2/impl/EventDefinitionImpl.java | 52 + .../org/eclipse/bpmn2/impl/EventImpl.java | 314 + .../bpmn2/impl/ExclusiveGatewayImpl.java | 152 + .../eclipse/bpmn2/impl/ExpressionImpl.java | 51 + .../ExtensionAttributeDefinitionImpl.java | 418 + .../impl/ExtensionAttributeValueImpl.java | 348 + .../bpmn2/impl/ExtensionDefinitionImpl.java | 264 + .../org/eclipse/bpmn2/impl/ExtensionImpl.java | 274 + .../bpmn2/impl/FieldExtensionImpl.java | 236 + .../eclipse/bpmn2/impl/FlowElementImpl.java | 423 + .../bpmn2/impl/FlowElementsContainerImpl.java | 208 + .../org/eclipse/bpmn2/impl/FlowNodeImpl.java | 362 + .../eclipse/bpmn2/impl/FormPropertyImpl.java | 522 + .../org/eclipse/bpmn2/impl/FormValueImpl.java | 234 + .../bpmn2/impl/FormalExpressionImpl.java | 304 + .../org/eclipse/bpmn2/impl/GatewayImpl.java | 179 + .../impl/GlobalBusinessRuleTaskImpl.java | 179 + .../impl/GlobalChoreographyTaskImpl.java | 181 + .../bpmn2/impl/GlobalConversationImpl.java | 52 + .../bpmn2/impl/GlobalManualTaskImpl.java | 52 + .../bpmn2/impl/GlobalScriptTaskImpl.java | 235 + .../eclipse/bpmn2/impl/GlobalTaskImpl.java | 168 + .../bpmn2/impl/GlobalUserTaskImpl.java | 243 + .../org/eclipse/bpmn2/impl/GroupImpl.java | 173 + .../bpmn2/impl/HumanPerformerImpl.java | 51 + .../eclipse/bpmn2/impl/IOParameterImpl.java | 233 + .../bpmn2/impl/ImplicitThrowEventImpl.java | 52 + .../org/eclipse/bpmn2/impl/ImportImpl.java | 290 + .../bpmn2/impl/InclusiveGatewayImpl.java | 152 + .../bpmn2/impl/InputOutputBindingImpl.java | 265 + .../impl/InputOutputSpecificationImpl.java | 288 + .../org/eclipse/bpmn2/impl/InputSetImpl.java | 394 + .../bpmn2/impl/InteractionNodeImpl.java | 236 + .../org/eclipse/bpmn2/impl/InterfaceImpl.java | 306 + .../impl/IntermediateCatchEventImpl.java | 52 + .../impl/IntermediateThrowEventImpl.java | 52 + .../bpmn2/impl/ItemAwareElementImpl.java | 342 + .../bpmn2/impl/ItemDefinitionImpl.java | 367 + .../java/org/eclipse/bpmn2/impl/LaneImpl.java | 483 + .../org/eclipse/bpmn2/impl/LaneSetImpl.java | 239 + .../bpmn2/impl/LinkEventDefinitionImpl.java | 365 + .../bpmn2/impl/LoopCharacteristicsImpl.java | 52 + .../org/eclipse/bpmn2/impl/MailTaskImpl.java | 511 + .../eclipse/bpmn2/impl/ManualTaskImpl.java | 51 + .../impl/MessageEventDefinitionImpl.java | 242 + .../impl/MessageFlowAssociationImpl.java | 247 + .../eclipse/bpmn2/impl/MessageFlowImpl.java | 375 + .../org/eclipse/bpmn2/impl/MessageImpl.java | 242 + .../eclipse/bpmn2/impl/MonitoringImpl.java | 51 + .../MultiInstanceLoopCharacteristicsImpl.java | 908 + .../org/eclipse/bpmn2/impl/OperationImpl.java | 420 + .../org/eclipse/bpmn2/impl/OutputSetImpl.java | 393 + .../bpmn2/impl/ParallelGatewayImpl.java | 51 + .../impl/ParticipantAssociationImpl.java | 247 + .../eclipse/bpmn2/impl/ParticipantImpl.java | 577 + .../impl/ParticipantMultiplicityImpl.java | 235 + .../eclipse/bpmn2/impl/PartnerEntityImpl.java | 223 + .../eclipse/bpmn2/impl/PartnerRoleImpl.java | 223 + .../org/eclipse/bpmn2/impl/PerformerImpl.java | 51 + .../bpmn2/impl/PotentialOwnerImpl.java | 52 + .../org/eclipse/bpmn2/impl/ProcessImpl.java | 1077 + .../org/eclipse/bpmn2/impl/PropertyImpl.java | 177 + .../eclipse/bpmn2/impl/ReceiveTaskImpl.java | 367 + .../eclipse/bpmn2/impl/RelationshipImpl.java | 313 + .../org/eclipse/bpmn2/impl/RenderingImpl.java | 51 + .../ResourceAssignmentExpressionImpl.java | 209 + .../org/eclipse/bpmn2/impl/ResourceImpl.java | 242 + .../impl/ResourceParameterBindingImpl.java | 277 + .../bpmn2/impl/ResourceParameterImpl.java | 300 + .../eclipse/bpmn2/impl/ResourceRoleImpl.java | 400 + .../eclipse/bpmn2/impl/RootElementImpl.java | 52 + .../eclipse/bpmn2/impl/ScriptTaskImpl.java | 234 + .../org/eclipse/bpmn2/impl/SendTaskImpl.java | 311 + .../eclipse/bpmn2/impl/SequenceFlowImpl.java | 504 + .../eclipse/bpmn2/impl/ServiceTaskImpl.java | 443 + .../bpmn2/impl/SignalEventDefinitionImpl.java | 174 + .../org/eclipse/bpmn2/impl/SignalImpl.java | 244 + .../impl/StandardLoopCharacteristicsImpl.java | 364 + .../eclipse/bpmn2/impl/StartEventImpl.java | 355 + .../bpmn2/impl/SubChoreographyImpl.java | 288 + .../bpmn2/impl/SubConversationImpl.java | 169 + .../eclipse/bpmn2/impl/SubProcessImpl.java | 361 + .../java/org/eclipse/bpmn2/impl/TaskImpl.java | 274 + .../impl/TerminateEventDefinitionImpl.java | 52 + .../bpmn2/impl/TextAnnotationImpl.java | 234 + .../eclipse/bpmn2/impl/ThrowEventImpl.java | 373 + .../bpmn2/impl/TimerEventDefinitionImpl.java | 378 + .../eclipse/bpmn2/impl/TransactionImpl.java | 233 + .../org/eclipse/bpmn2/impl/UserTaskImpl.java | 583 + .../java/org/eclipse/bpmn2/impl/bpmn2.ecore | 4567 ++ .../bpmn2/util/Bpmn2AdapterFactory.java | 3247 ++ .../bpmn2/util/Bpmn2ResourceFactoryImpl.java | 70 + .../eclipse/bpmn2/util/Bpmn2ResourceImpl.java | 40 + .../org/eclipse/bpmn2/util/Bpmn2Switch.java | 4501 ++ .../eclipse/bpmn2/util/Bpmn2XMLProcessor.java | 62 + .../main/java/org/eclipse/dd/dc/Bounds.java | 149 + .../java/org/eclipse/dd/dc/DcFactory.java | 81 + .../java/org/eclipse/dd/dc/DcPackage.java | 757 + .../java/org/eclipse/dd/dc/DocumentRoot.java | 179 + .../src/main/java/org/eclipse/dd/dc/Font.java | 221 + .../main/java/org/eclipse/dd/dc/Point.java | 93 + .../org/eclipse/dd/dc/impl/BoundsImpl.java | 342 + .../org/eclipse/dd/dc/impl/DcFactoryImpl.java | 145 + .../org/eclipse/dd/dc/impl/DcPackageImpl.java | 628 + .../eclipse/dd/dc/impl/DocumentRootImpl.java | 408 + .../java/org/eclipse/dd/dc/impl/FontImpl.java | 495 + .../org/eclipse/dd/dc/impl/PointImpl.java | 232 + .../eclipse/dd/dc/util/DcAdapterFactory.java | 188 + .../dd/dc/util/DcResourceFactoryImpl.java | 70 + .../eclipse/dd/dc/util/DcResourceImpl.java | 40 + .../java/org/eclipse/dd/dc/util/DcSwitch.java | 203 + .../org/eclipse/dd/dc/util/DcValidator.java | 212 + .../eclipse/dd/dc/util/DcXMLProcessor.java | 62 + .../java/org/eclipse/dd/di/DiFactory.java | 54 + .../java/org/eclipse/dd/di/DiPackage.java | 1901 + .../main/java/org/eclipse/dd/di/Diagram.java | 185 + .../org/eclipse/dd/di/DiagramElement.java | 153 + .../java/org/eclipse/dd/di/DocumentRoot.java | 375 + .../src/main/java/org/eclipse/dd/di/Edge.java | 88 + .../main/java/org/eclipse/dd/di/Label.java | 64 + .../java/org/eclipse/dd/di/LabeledEdge.java | 53 + .../java/org/eclipse/dd/di/LabeledShape.java | 53 + .../src/main/java/org/eclipse/dd/di/Node.java | 29 + .../main/java/org/eclipse/dd/di/Plane.java | 71 + .../main/java/org/eclipse/dd/di/Shape.java | 64 + .../main/java/org/eclipse/dd/di/Style.java | 64 + .../org/eclipse/dd/di/impl/DiFactoryImpl.java | 109 + .../org/eclipse/dd/di/impl/DiPackageImpl.java | 1084 + .../dd/di/impl/DiagramElementImpl.java | 449 + .../org/eclipse/dd/di/impl/DiagramImpl.java | 462 + .../eclipse/dd/di/impl/DocumentRootImpl.java | 727 + .../java/org/eclipse/dd/di/impl/EdgeImpl.java | 259 + .../org/eclipse/dd/di/impl/LabelImpl.java | 200 + .../eclipse/dd/di/impl/LabeledEdgeImpl.java | 113 + .../eclipse/dd/di/impl/LabeledShapeImpl.java | 114 + .../java/org/eclipse/dd/di/impl/NodeImpl.java | 51 + .../org/eclipse/dd/di/impl/PlaneImpl.java | 205 + .../org/eclipse/dd/di/impl/ShapeImpl.java | 200 + .../org/eclipse/dd/di/impl/StyleImpl.java | 177 + .../eclipse/dd/di/util/DiAdapterFactory.java | 321 + .../dd/di/util/DiResourceFactoryImpl.java | 70 + .../eclipse/dd/di/util/DiResourceImpl.java | 40 + .../java/org/eclipse/dd/di/util/DiSwitch.java | 383 + .../org/eclipse/dd/di/util/DiValidator.java | 303 + .../eclipse/dd/di/util/DiXMLProcessor.java | 62 + .../java/org/eclipse/securebpmn2/Action.java | 83 + .../eclipse/securebpmn2/ActivityAction.java | 85 + .../ActivityAuthorizationConstraint.java | 57 + .../securebpmn2/AtomicActivityAction.java | 28 + .../AtomicItemAwareElementAction.java | 28 + .../securebpmn2/AtomicProcessAction.java | 28 + .../securebpmn2/AuthorizationConstraint.java | 135 + .../eclipse/securebpmn2/BindingOfDuty.java | 87 + .../securebpmn2/CompositeActivityAction.java | 54 + .../CompositeItemAwareElementAction.java | 54 + .../securebpmn2/CompositeProcessAction.java | 54 + .../java/org/eclipse/securebpmn2/Group.java | 81 + .../securebpmn2/ItemAwareElementAction.java | 85 + .../org/eclipse/securebpmn2/NeedToKnow.java | 28 + .../org/eclipse/securebpmn2/Permission.java | 121 + .../eclipse/securebpmn2/ProcessAction.java | 83 + .../java/org/eclipse/securebpmn2/Role.java | 138 + .../securebpmn2/Securebpmn2Factory.java | 226 + .../securebpmn2/Securebpmn2Package.java | 3754 ++ .../org/eclipse/securebpmn2/SecurityFlow.java | 96 + .../eclipse/securebpmn2/SecurityFlowNode.java | 30 + .../eclipse/securebpmn2/SeparationOfDuty.java | 87 + .../java/org/eclipse/securebpmn2/Subject.java | 75 + .../java/org/eclipse/securebpmn2/User.java | 60 + .../eclipse/securebpmn2/impl/ActionImpl.java | 263 + .../securebpmn2/impl/ActivityActionImpl.java | 300 + .../ActivityAuthorizationConstraintImpl.java | 189 + .../impl/AtomicActivityActionImpl.java | 52 + .../AtomicItemAwareElementActionImpl.java | 52 + .../impl/AtomicProcessActionImpl.java | 52 + .../impl/AuthorizationConstraintImpl.java | 379 + .../securebpmn2/impl/BindingOfDutyImpl.java | 237 + .../impl/CompositeActivityActionImpl.java | 188 + .../CompositeItemAwareElementActionImpl.java | 189 + .../impl/CompositeProcessActionImpl.java | 188 + .../eclipse/securebpmn2/impl/GroupImpl.java | 259 + .../impl/ItemAwareElementActionImpl.java | 288 + .../securebpmn2/impl/NeedToKnowImpl.java | 51 + .../securebpmn2/impl/PermissionImpl.java | 348 + .../securebpmn2/impl/ProcessActionImpl.java | 278 + .../eclipse/securebpmn2/impl/RoleImpl.java | 387 + .../impl/Securebpmn2FactoryImpl.java | 338 + .../impl/Securebpmn2PackageImpl.java | 1036 + .../securebpmn2/impl/SecurityFlowImpl.java | 309 + .../impl/SecurityFlowNodeImpl.java | 54 + .../impl/SeparationOfDutyImpl.java | 239 + .../eclipse/securebpmn2/impl/SubjectImpl.java | 226 + .../eclipse/securebpmn2/impl/UserImpl.java | 177 + .../securebpmn2/impl/securebpmn2.ecore | 122 + .../util/Securebpmn2AdapterFactory.java | 596 + .../util/Securebpmn2ResourceFactoryImpl.java | 70 + .../util/Securebpmn2ResourceImpl.java | 40 + .../securebpmn2/util/Securebpmn2Switch.java | 773 + .../util/Securebpmn2XMLProcessor.java | 64 + .../org/eclipse/bpmn2/impl/bpmn2.ecore | 4552 ++ src/org.activiti.designer.parent/.classpath | 5 + src/org.activiti.designer.parent/.project | 17 + .../.settings/org.eclipse.jdt.core.prefs | 12 + src/org.activiti.designer.parent/pom.xml | 122 + .../index.html | 59 + src/org.activiti.designer.updatesite/pom.xml | 15 + src/org.activiti.designer.updatesite/site.xml | 14 + .../web/assets/images/activiti_logo.png | Bin 0 -> 5241 bytes .../web/assets/images/drive_web.png | Bin 0 -> 686 bytes .../web/assets/styles/site.css | 101 + .../web/site.xsl | 136 + .../work/site.css | 12 + .../work/site.xsl | 214 + .../.settings/org.eclipse.jdt.core.prefs | 8 + .../META-INF/MANIFEST.MF | 33 + .../build.properties | 4 + src/org.activiti.designer.util/pom.xml | 15 + .../org/activiti/designer/util/Activator.java | 50 + .../designer/util/eclipse/ActivitiUiUtil.java | 273 + .../util/editor/ModifiableListEditor.java | 98 + .../features/AbstractCreateBPMNFeature.java | 31 + .../designer/util/platform/OSEnum.java | 7 + .../designer/util/platform/OSUtil.java | 18 + .../util/preferences/Preferences.java | 43 + .../property/ActivitiPropertySection.java | 29 + .../designer/util/style/StyleUtil.java | 227 + .../util/workspace/ActivitiWorkspaceUtil.java | 175 + .../util/workspace/BpmnProcessParser.java | 83 + .../META-INF/MANIFEST.MF | 26 + .../build.properties | 5 + .../plugin.xml | 10 + .../pom.xml | 15 + .../validation/bpmn20/bundle/Activator.java | 40 + .../bpmn20/bundle/PluginConstants.java | 34 + .../validation/BPMN20ProcessValidator.java | 120 + .../worker/ProcessValidationWorker.java | 22 + .../worker/ProcessValidationWorkerInfo.java | 29 + .../worker/ProcessValidationWorkerMarker.java | 43 + .../impl/ScriptTaskValidationWorker.java | 53 + .../impl/SequenceFlowValidationWorker.java | 53 + .../impl/ServiceTaskValidationWorker.java | 54 + .../impl/SubProcessValidationWorker.java | 43 + .../worker/impl/UserTaskValidationWorker.java | 63 + .../worker/impl/ValidationCode.java | 24 + 1909 files changed, 381464 insertions(+) create mode 100644 CITATION create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/CaseStudyC/Get Civil.activiti create mode 100644 examples/CaseStudyC/Get Civil.png create mode 100644 examples/CaseStudyC/Get Legal Info.activiti create mode 100644 examples/CaseStudyC/Get Legal Info.png create mode 100644 examples/CaseStudyC/Get Lots.activiti create mode 100644 examples/CaseStudyC/Get Lots.png create mode 100644 examples/CaseStudyC/Get Solicitor.activiti create mode 100644 examples/CaseStudyC/Get Solicitor.png create mode 100644 examples/CaseStudyC/PublishLot.activiti create mode 100644 examples/CaseStudyC/PublishLot.png create mode 100644 examples/CaseStudyC/RequestLot.activiti create mode 100644 examples/CaseStudyC/RequestLot.png create mode 100644 examples/CaseStudyC/Select Lot.activiti create mode 100644 examples/CaseStudyC/Select Lot.png create mode 100644 examples/JobApplication/JobApplication.activiti create mode 100644 examples/JobApplication/JobApplication.png create mode 100644 examples/JobApplication/generated/JobApplication.aslan create mode 100644 examples/JobApplication/generated/JobApplication.res create mode 100644 examples/JobApplication/generated/JobApplication.result create mode 100644 examples/JobApplication/generated/JobApplication.sate create mode 100644 examples/LoanOrigination/CreditWorthinessService.java create mode 100644 examples/LoanOrigination/LoanOrigination.activiti create mode 100644 examples/LoanOrigination/LoanOrigination.png create mode 100644 examples/LoanOrigination/generated/LoanOrigination.aslan create mode 100644 examples/LoanOrigination/generated/LoanOrigination.res create mode 100644 examples/LoanOrigination/generated/LoanOrigination.result create mode 100644 examples/LoanOrigination/generated/LoanOrigination.sate create mode 100644 examples/OrderPlacement/.access^ create mode 100644 examples/OrderPlacement/OrderPlacementProcess.activiti create mode 100644 examples/OrderPlacement/OrderPlacementProcess.bpmn20.xml create mode 100644 examples/OrderPlacement/OrderPlacementProcess.png create mode 100644 examples/TravelApproval/ResultSender.java create mode 100644 examples/TravelApproval/TravelApproval.activiti create mode 100644 examples/TravelApproval/TravelApproval.png create mode 100644 examples/TravelApproval/generated/TravelApproval.aslan create mode 100644 examples/TravelApproval/generated/TravelApproval.res create mode 100644 examples/TravelApproval/generated/TravelApproval.result create mode 100644 examples/TravelApproval/generated/TravelApproval.sate create mode 100644 examples/misc/ASLanSoDDemo.activiti create mode 100644 examples/misc/AdvancedSoDDemo.activiti create mode 100644 src/.gitignore create mode 100644 src/com.sun.xacml/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/com.sun.xacml/pom.xml create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/AbstractPolicy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/BasicEvaluationCtx.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ConfigurationStore.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Constants.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/EvaluationCtx.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Indenter.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/MatchElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/MatchResult.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Obligation.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PDP.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PDPConfig.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ParsingException.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Policy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyMetaData.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyReference.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PolicySet.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyTreeElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ProcessingException.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Rule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/Target.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatch.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatchGroup.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/TargetSection.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/UnknownIdentifierException.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/VersionConstraints.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AnyURIAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeDesignator.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeFactoryProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeSelector.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeValue.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BagAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64BinaryAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BaseAttributeFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BooleanAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DNSNameAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateTimeAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DayTimeDurationAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DecisionAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DoubleAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/HexBinaryAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPAddressAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv4AddressAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv6AddressAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IntegerAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/PortRange.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/RFC822NameAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StandardAttributeFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StringAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TimeAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TypeIdentifierConstants.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/X500NameAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/YearMonthDurationAttribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/AnyURIAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/Base64BinaryAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/BooleanAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DNSNameAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateTimeAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DayTimeDurationAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DoubleAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/HexBinaryAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IPAddressAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IntegerAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/RFC822NameAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/StringAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/TimeAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/X500NameAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/YearMonthDurationAttributeProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/BaseCombiningAlgFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerParameter.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactoryProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgorithm.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesPolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesRuleAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicablePolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicableRuleAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OnlyOneApplicablePolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesPolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesRuleAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesPolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesRuleAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesPolicyAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesRuleAlg.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombinerElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombiningAlgorithm.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombinerElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombiningAlgorithm.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/StandardCombiningAlgFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/combine/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AbsFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AddFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Apply.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BagFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BaseFunctionFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BasicFunctionFactoryProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ComparisonFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Condition.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionBagFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionSetFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DateMathFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DivideFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EqualFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Evaluatable.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EvaluationResult.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Expression.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ExpressionHandler.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FloorFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Function.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionBase.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactoryProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionTypeException.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralBagFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralSetFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/HigherOrderFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/LogicalFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunctionProxy.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MatchFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ModFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MultiplyFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NOfFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NotFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NumericConvertFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/RoundFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SetFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StandardFunctionFactory.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringNormalizeFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SubtractFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/TimeInRangeFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/URIStringCatFunction.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableDefinition.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableManager.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableReference.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AbsFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AddFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ComparisonFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionBagFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionSetFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DateMathFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DivideFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/EqualFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FloorFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralBagFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralSetFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/HigherOrderFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/LogicalFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MatchFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ModFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MultiplyFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NOfFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NotFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NumericConvertFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/RoundFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringNormalizeFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/SubtractFunctionCluster.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/cond/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Attribute.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/InputParser.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/PolicyIssuer.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestCtx.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestElement.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/ResponseCtx.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Result.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Status.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/StatusDetail.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/debug/IndirectLocatable.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/debug/Locatable.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/debug/RuntimeInfo.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinder.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinderModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinder.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderResult.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RequiredAttributesModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinder.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderResult.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinder.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinderModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentEnvModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentRequiredAttributeModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/SelectorModule.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/finder/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/package.html create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/EdgeExplorer.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraph.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphEdge.java create mode 100644 src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphNode.java create mode 100644 src/com.sun.xacml/src/test/java/com/sun/xacml/AppTest.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/META-INF/MANIFEST.MF create mode 100644 src/eu.aniketos.securebpmn.export.aslan/build.properties create mode 100644 src/eu.aniketos.securebpmn.export.aslan/plugin.xml create mode 100644 src/eu.aniketos.securebpmn.export.aslan/pom.xml create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/bundle/Activator.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanExportMarshaller.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanFileBuilder.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/BindingOfDutyExport.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExclusiveGatewayExport.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExportUtil.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ParallelGatewayExport.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/SeparationOfDutyExport.java create mode 100644 src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/TaskExport.java create mode 100644 src/eu.aniketos.securebpmn.export.html/META-INF/MANIFEST.MF create mode 100644 src/eu.aniketos.securebpmn.export.html/plugin.xml create mode 100644 src/eu.aniketos.securebpmn.export.html/pom.xml create mode 100644 src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/bundle/Activator.java create mode 100644 src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlExportMarshaller.java create mode 100644 src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlWriter.java create mode 100644 src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/PropertiesStringBuilder.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/META-INF/MANIFEST.MF create mode 100644 src/eu.aniketos.securebpmn.export.xacml/build.properties create mode 100644 src/eu.aniketos.securebpmn.export.xacml/plugin.xml create mode 100644 src/eu.aniketos.securebpmn.export.xacml/pom.xml create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/bundle/Activator.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/BindingOfDutyExport.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExclusiveGatewayExport.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExportUtil.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ParallelGatewayExport.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/SeparationOfDutyExport.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/TaskExport.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlExportMarshaller.java create mode 100644 src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlFileBuilder.java create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/META-INF/MANIFEST.MF create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/build.properties create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/plugin.xml create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/pom.xml create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/bundle/Activator.java create mode 100644 src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/validation/BPMN20ProcessValidator.java create mode 100644 src/eu.aniketos.securebpmn/META-INF/MANIFEST.MF create mode 100644 src/eu.aniketos.securebpmn/build.properties create mode 100644 src/eu.aniketos.securebpmn/plugin.xml create mode 100644 src/eu.aniketos.securebpmn/pom.xml create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/Activator.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/CheckServiceTaskFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ListProcessVariablesFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/PerformNtkAnalysisFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanLocalFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanWebFeature.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/ntk/NeedToKnowUtil.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDef.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDefLine.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleRel.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFact.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFunction.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcMessage.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcTraceStep.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcVar.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/Summary.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/DialogUtil.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/SecurityUtil.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarAccess.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarCheckASTVisitor.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarListASTVisitor.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/SCVMValidationConstants.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ValidateAslanRunnable.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/PlayerControlRunnable.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/ValidationView.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/ActionType.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/HighlightVisualizationElementsRunnable.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/VisualizationElement.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTracePlayer.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTraceStep.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/RbacVisualization.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCPortType.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCService.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/RoleDef.g create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/Satmc.g create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefLexer.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefParser.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/satmc/SatmcLexer.java create mode 100644 src/eu.aniketos.securebpmn/src/main/java/org/antlr/satmc/SatmcParser.java create mode 100644 src/examples/money-tasks/pom.xml create mode 100644 src/examples/money-tasks/src/main/java/org/acme/palette/AcmeMoneyCustomizer.java create mode 100644 src/examples/money-tasks/src/main/java/org/acme/servicetasks/AccountManager.java create mode 100644 src/examples/money-tasks/src/main/java/org/acme/servicetasks/AcmeMoneyTask.java create mode 100644 src/examples/money-tasks/src/main/resources/icons/coins.png create mode 100644 src/org.activiti.designer.eclipse/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.eclipse/build.properties create mode 100644 src/org.activiti.designer.eclipse/community_icon.png create mode 100644 src/org.activiti.designer.eclipse/icons/connection16.gif create mode 100644 src/org.activiti.designer.eclipse/icons/dialogs/layout_circular.gif create mode 100644 src/org.activiti.designer.eclipse/icons/dialogs/layout_organic.gif create mode 100644 src/org.activiti.designer.eclipse/icons/general/arrow_down.gif create mode 100644 src/org.activiti.designer.eclipse/icons/general/arrow_left.gif create mode 100644 src/org.activiti.designer.eclipse/icons/general/arrow_right.gif create mode 100644 src/org.activiti.designer.eclipse/icons/general/arrow_up.gif create mode 100644 src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.128x128.png create mode 100644 src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.16x16.png create mode 100644 src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.32x32.png create mode 100644 src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.48x48.png create mode 100644 src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.64x64.png create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/attribute_private.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/attribute_protected.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/attribute_public.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/operation_private.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/operation_protected.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/operation_public.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/reference_private.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/reference_protected.gif create mode 100644 src/org.activiti.designer.eclipse/icons/modifier/reference_public.gif create mode 100644 src/org.activiti.designer.eclipse/icons/mof/class.gif create mode 100644 src/org.activiti.designer.eclipse/icons/mof/mof.gif create mode 100644 src/org.activiti.designer.eclipse/icons/mof/newclass.gif create mode 100644 src/org.activiti.designer.eclipse/icons/mof/package.gif create mode 100644 src/org.activiti.designer.eclipse/icons/outline/thumbnail.gif create mode 100644 src/org.activiti.designer.eclipse/icons/outline/tree.gif create mode 100644 src/org.activiti.designer.eclipse/icons/pid16.gif create mode 100644 src/org.activiti.designer.eclipse/icons/rialto16.gif create mode 100644 src/org.activiti.designer.eclipse/icons/sample.gif create mode 100644 src/org.activiti.designer.eclipse/icons/tree/tree_down.gif create mode 100644 src/org.activiti.designer.eclipse/icons/tree/tree_left.gif create mode 100644 src/org.activiti.designer.eclipse/icons/tree/tree_right.gif create mode 100644 src/org.activiti.designer.eclipse/icons/tree/tree_up.gif create mode 100644 src/org.activiti.designer.eclipse/plugin.properties create mode 100644 src/org.activiti.designer.eclipse/plugin.xml create mode 100644 src/org.activiti.designer.eclipse/pom.xml create mode 100644 src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.export.ExportMarshaller.exsd create mode 100644 src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.validation.ProcessValidator.exsd create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/Logger.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BoundaryEventModel.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BpmnParser.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/FieldModel.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/GraphicInfo.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/SequenceFlowModel.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/BpmnFileReader.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/FlowSourceNotFoundException.java create mode 100755 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnElementsCommand.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnUtil.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/AbstractImageCache.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiBPMNDiagramConstants.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiEclipseImageProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiPlugin.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiProjectNature.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ColoredFont.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/FileService.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ISampleImageConstants.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ImageCache.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/PluginImage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/RenameActionProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/SampleUtil.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/DeploymentInfo.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesTreeContentProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesViewerFilter.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesTreeContentProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesViewerFilter.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeInDeploymentTreeViewer.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/ProcessDeployer.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiBMPN2Editor.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiDiagramEditor.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiMultiPageEditor.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/sync/DiagramUpdater.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/AbstractDiagramWorker.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/ExtensionConstants.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/AbstractExportMarshaller.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/ExportMarshaller.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/SequenceFlowSynchronizer.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/AbstractProcessValidator.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/ProcessValidator.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnLabelProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnTreeContentProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/BpmnElementsNode.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/DiagramsNode.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractContainerNode.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractInstancesOfTypeContainerNode.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/IContainerNode.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/ContentOutlinePageAdapterFactory.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/GraphicsEditorOutlinePage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/AbstractGraphicsTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ColorTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ConnectionDecoratorTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/GraphicsAlgorithmTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PictogramElementTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PictogramsTreeEditPartFactory.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PointTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/StyleTreeEditPart.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/perspective/ActivitiPerspective.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/preferences/ActivitiSavePreferencesPageInitializer.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/preferences/PreferencesUtil.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/property/PropertiesLabelProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/property/TypeMapper.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/AbstractInputFieldWizardPage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/AbstractWizardPage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/ActivitiEditorContextMenuProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/CreateActivitiProjectWizard.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/ExportMarshallerRunnable.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/ITextProvider.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/diagram/CreateDefaultActivitiDiagramInitialContentPage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/diagram/CreateDefaultActivitiDiagramNameWizardPage.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/diagram/CreateDefaultActivitiDiagramWizard.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/diagram/InitialContentInfo.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/diagram/TemplateInfo.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/ui/wizard/project/CreateDefaultActivitiProjectWizard.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/util/ExtensionPointUtil.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/util/FlowElementUtil.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/util/Util.java create mode 100644 src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/util/uiprovider/TwoObjectsContainer.java create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/content/new-diagram-content.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/content/new-subprocess-content.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/templates/adhoc.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/templates/parallel-review-group.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/templates/parallel-review.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/templates/review-pooled.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/main/resources/templates/review.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/test/java/org/activiti/designer/eclipse/bpmn/BpmnParserTest.java create mode 100644 src/org.activiti.designer.eclipse/src/test/resources/VacationRequest.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/test/resources/processEventListener.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/src/test/resources/sequenceFlowWithCondition.bpmn20.xml create mode 100644 src/org.activiti.designer.eclipse/xsd/BPMN20.xsd create mode 100644 src/org.activiti.designer.eclipse/xsd/BPMNDI.xsd create mode 100644 src/org.activiti.designer.eclipse/xsd/DC.xsd create mode 100644 src/org.activiti.designer.eclipse/xsd/DI.xsd create mode 100644 src/org.activiti.designer.eclipse/xsd/Semantic.xsd create mode 100644 src/org.activiti.designer.eclipse/xsd/activiti-bpmn-extensions-5.2.xsd create mode 100644 src/org.activiti.designer.export.bpmn20/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.export.bpmn20/build.properties create mode 100644 src/org.activiti.designer.export.bpmn20/plugin.xml create mode 100644 src/org.activiti.designer.export.bpmn20/pom.xml create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/bundle/Activator.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ActivitiNamespaceConstants.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/AlfrescoScriptTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/AsyncActivityExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/BPMN20ExportMarshaller.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/BoundaryEventExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/BpmnDIExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/BusinessRuleTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/CallActivityExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/DefaultFlowExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/DelegatingXMLStreamWriter.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ExtensionListenerExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/FieldExtensionsExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/FormPropertiesExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ImplementationValueExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/IndentingXMLStreamWriter.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/IntermediateCatchEventExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/MailTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ManualTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/MultiInstanceExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ReceiveTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ScriptTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/SequenceFlowExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/ServiceTaskExport.java create mode 100644 src/org.activiti.designer.export.bpmn20/src/main/java/org/activiti/designer/export/bpmn20/export/UserTaskExport.java create mode 100644 src/org.activiti.designer.export.image/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.export.image/build.properties create mode 100644 src/org.activiti.designer.export.image/plugin.xml create mode 100644 src/org.activiti.designer.export.image/pom.xml create mode 100644 src/org.activiti.designer.export.image/src/main/java/org/activiti/designer/export/image/bundle/Activator.java create mode 100644 src/org.activiti.designer.export.image/src/main/java/org/activiti/designer/export/image/export/ImageExportMarshaller.java create mode 100644 src/org.activiti.designer.feature/build.properties create mode 100644 src/org.activiti.designer.feature/feature.properties create mode 100644 src/org.activiti.designer.feature/feature.xml create mode 100644 src/org.activiti.designer.feature/license.html create mode 100644 src/org.activiti.designer.feature/pom.xml create mode 100644 src/org.activiti.designer.gui/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.gui/build.properties create mode 100644 src/org.activiti.designer.gui/icons/action.down.png create mode 100644 src/org.activiti.designer.gui/icons/action.magnifier.png create mode 100644 src/org.activiti.designer.gui/icons/action.up.png create mode 100644 src/org.activiti.designer.gui/icons/alfresco.png create mode 100644 src/org.activiti.designer.gui/icons/bullet_go.png create mode 100644 src/org.activiti.designer.gui/icons/callactivity.png create mode 100644 src/org.activiti.designer.gui/icons/defaultCustomServiceTask.png create mode 100644 src/org.activiti.designer.gui/icons/edit.png create mode 100644 src/org.activiti.designer.gui/icons/ereference.gif create mode 100644 src/org.activiti.designer.gui/icons/error.png create mode 100644 src/org.activiti.designer.gui/icons/errorCustomServiceTask.png create mode 100644 src/org.activiti.designer.gui/icons/new.png create mode 100644 src/org.activiti.designer.gui/icons/timer.png create mode 100644 src/org.activiti.designer.gui/icons/type.annotation.png create mode 100644 src/org.activiti.designer.gui/icons/type.business.rule.png create mode 100644 src/org.activiti.designer.gui/icons/type.endevent.none.png create mode 100644 src/org.activiti.designer.gui/icons/type.gateway.exclusive.png create mode 100644 src/org.activiti.designer.gui/icons/type.gateway.inclusive.png create mode 100644 src/org.activiti.designer.gui/icons/type.gateway.parallel.png create mode 100644 src/org.activiti.designer.gui/icons/type.loopmarker.png create mode 100644 src/org.activiti.designer.gui/icons/type.mail.png create mode 100644 src/org.activiti.designer.gui/icons/type.manual.png create mode 100644 src/org.activiti.designer.gui/icons/type.receive.png create mode 100644 src/org.activiti.designer.gui/icons/type.script.png create mode 100644 src/org.activiti.designer.gui/icons/type.security.bod.png create mode 100644 src/org.activiti.designer.gui/icons/type.security.sod.png create mode 100644 src/org.activiti.designer.gui/icons/type.send.png create mode 100644 src/org.activiti.designer.gui/icons/type.service.png create mode 100644 src/org.activiti.designer.gui/icons/type.startevent.none.png create mode 100644 src/org.activiti.designer.gui/icons/type.subprocess.collapsed.png create mode 100644 src/org.activiti.designer.gui/icons/type.subprocess.expanded.png create mode 100644 src/org.activiti.designer.gui/icons/type.user.png create mode 100644 src/org.activiti.designer.gui/plugin.xml create mode 100644 src/org.activiti.designer.gui/pom.xml create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/AddAlfrescoMailTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/AddAlfrescoScriptTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/AddAlfrescoStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/AddAlfrescoTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/AddAlfrescoUserTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/CreateAlfrescoMailTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/CreateAlfrescoScriptTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/CreateAlfrescoStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/features/CreateAlfrescoUserTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoMailTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoMailTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoScriptTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoScriptTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoStartEventFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoStartEventSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoUserTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/com/alfresco/designer/gui/property/PropertyAlfrescoUserTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/Activator.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/ActivitiExtensionImageProvider.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/ActivitiImageProvider.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/PluginImage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/actions/GenerateUnitTestAction.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/diagram/ActivitiBPMNDiagramTypeProvider.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/diagram/ActivitiBPMNFeatureProvider.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/diagram/ActivitiToolBehaviorProvider.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AbstractCreateBPMNConnectionFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AbstractCreateFastBPMNFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddBoundaryErrorFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddBoundaryTimerFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddBusinessRuleTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddCallActivityFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddEmbeddedSubProcessFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddEndEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddErrorEndEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddExclusiveGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddInclusiveGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddMailTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddManualTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddParallelGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddReceiveTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddScriptTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddSequenceFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddServiceTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddTimerCatchingEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddTimerStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/AddUserTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/ChangeElementTypeFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CopyFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateBoundaryErrorFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateBoundaryTimerFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateBusinessRuleTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateCallActivityFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateCustomServiceTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateEmbeddedSubProcessFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateEndEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateErrorEndEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateExclusiveGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateInclusiveGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateMailTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateManualTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateParallelGatewayFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateReceiveTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateScriptTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateSequenceFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateServiceTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateTimerCatchingEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateTimerStartEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/CreateUserTaskFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/DeleteFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/DeleteSequenceFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/DirectEditFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/ExpandCollapseSubProcessFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/MoveBoundaryEventFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/PasteFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/SaveBpmnModelFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/SubProcessResizeFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/TaskResizeFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/UpdateConnectionFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/features/UpdateFlowElementFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/gui/actions/CopyActionHandler.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/gui/actions/PasteActionHandler.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/model/FieldExtensionModel.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/popupmenus/DeploymentMenu.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/popupmenus/ImportBpmnMenu.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/preferences/ActivitiEditorPreferencesPage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/preferences/ActivitiImportPreferencesPage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/preferences/ActivitiPreferencePage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/preferences/ActivitiSavePreferencesPage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/preferences/AlfrescoPreferencesPage.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBoundaryErrorFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBoundaryErrorSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBoundaryTimerFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBoundaryTimerSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBpmnFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBpmnSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBusinessRuleTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyBusinessRuleTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyCallActivityFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyCallActivitySection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyCustomServiceTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyCustomServiceTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyDiagramFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyDiagramSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyExecutionListenerFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyExecutionListenerSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyFormPropertyFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyFormPropertySection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyIOParameterSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyIntermediateCatchTimerFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyIntermediateCatchTimerSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyMailTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyMailTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyMultiInstanceFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyMultiInstanceSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyScriptTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyScriptTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertySequenceFlowFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertySequenceFlowSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyServiceTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyServiceTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyStartEventFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyStartEventSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyTaskListenerFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyTaskListenerSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyTimerStartEventFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyTimerStartEventSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyUserTaskFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/PropertyUserTaskSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/custom/MultilineTextDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/custom/PeriodDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/custom/PeriodPropertyElement.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/CustomServiceTaskContext.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/CustomServiceTaskContextImpl.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/FormToolTip.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/JarClassLoader.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/AbstractCustomPropertyField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyBooleanChoiceField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyComboboxChoiceField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyDataGridField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyDatePickerField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyMultilineTextField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyPeriodField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyRadioChoiceField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/CustomPropertyTextField.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/FieldInfo.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/validator/PeriodRequiredFieldValidator.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/field/validator/RadioRequiredFieldValidator.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/util/ExtensionPropertyUtil.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/extension/util/ExtensionUtil.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/AbstractListenerDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/AbstractListenerEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/ExecutionListenerDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/ExecutionListenerEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FieldExtensionDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FieldExtensionEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FormPropertyDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FormPropertyEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FormValueDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/FormValueEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/IOParameterDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/IOParameterEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/TableFieldEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/TaskListenerDialog.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/property/ui/TaskListenerEditor.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/runner/TestRunnerClassGenerator.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/AddSecurityBodFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/AddSecurityFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/AddSecuritySodFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/CreateSecurityBodFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/CreateSecurityFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/CreateSecuritySodFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/features/DeleteSecurityFlowFeature.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertyNtkFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertyNtkSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertyRbacFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertyRbacSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertySodBodFilter.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/security/property/PropertySodBodSection.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/util/BpmnBOUtil.java create mode 100644 src/org.activiti.designer.gui/src/main/java/org/activiti/designer/util/CloneUtil.java create mode 100644 src/org.activiti.designer.help/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.help/build.properties create mode 100644 src/org.activiti.designer.help/html/images/activiti_logo.png create mode 100644 src/org.activiti.designer.help/html/preferences/maintopic.html create mode 100644 src/org.activiti.designer.help/html/toc.html create mode 100644 src/org.activiti.designer.help/html/usage/maintopic.html create mode 100644 src/org.activiti.designer.help/plugin.xml create mode 100644 src/org.activiti.designer.help/pom.xml create mode 100644 src/org.activiti.designer.help/src/main/java/org/activiti/designer/help/Activator.java create mode 100644 src/org.activiti.designer.help/toc.xml create mode 100644 src/org.activiti.designer.help/tocpreferences.xml create mode 100644 src/org.activiti.designer.help/tocusage.xml create mode 100644 src/org.activiti.designer.integration/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.integration/build.properties create mode 100644 src/org.activiti.designer.integration/pom.xml create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/Activator.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/palette/AbstractDefaultPaletteCustomizer.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/palette/DefaultPaletteCustomizer.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/palette/PaletteEntry.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/AbstractCustomServiceTask.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/CustomServiceTask.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/DiagramBaseShape.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/PropertyType.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/DataGridProperty.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/DatePickerProperty.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/Help.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/Property.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/PropertyItems.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/annotation/Runtime.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/validator/EmailFieldValidator.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/validator/FieldValidator.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/validator/RequiredFieldValidator.java create mode 100644 src/org.activiti.designer.integration/src/main/java/org/activiti/designer/integration/servicetask/validator/ValidationException.java create mode 100644 src/org.activiti.designer.model.edit/.classpath create mode 100644 src/org.activiti.designer.model.edit/.project create mode 100644 src/org.activiti.designer.model.edit/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.model.edit/build.properties create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ActivitiListener.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ActivityAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ActivityAuthorizationConstraint.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AdHocSubProcess.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AlfrescoMailTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AlfrescoScriptBase.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AlfrescoScriptTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AlfrescoStartEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AlfrescoUserTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Assignment.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Association.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AtomicActivityAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AtomicItemAwareElementAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AtomicProcessAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Auditing.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/AuthorizationConstraint.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNDiagram.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNEdge.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNLabel.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNLabelStyle.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNPlane.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BPMNShape.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BindingOfDuty.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BoundaryEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Bounds.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/BusinessRuleTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CallActivity.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CallChoreography.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CallConversation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CancelEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CandidateGroup.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CandidateUser.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Category.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CategoryValue.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Choreography.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ChoreographyTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Collaboration.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CompensateEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ComplexBehaviorDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ComplexGateway.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CompositeActivityAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CompositeItemAwareElementAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CompositeProcessAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ConditionalEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Conversation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ConversationAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ConversationLink.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CorrelationKey.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CorrelationProperty.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CorrelationPropertyBinding.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CorrelationPropertyRetrievalExpression.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CorrelationSubscription.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/CustomProperty.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataGrid.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataGridField.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataGridRow.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataInput.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataInputAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataObject.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataObjectReference.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataOutput.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataOutputAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataState.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataStore.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DataStoreReference.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Definitions.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Diagram.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/DocumentRoot.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Documentation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Edge.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/EndEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/EndPoint.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Error.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ErrorEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Escalation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/EscalationEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/EventBasedGateway.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ExclusiveGateway.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Expression.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Extension.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ExtensionAttributeDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ExtensionAttributeValue.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ExtensionDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/FieldExtension.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Font.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/FormProperty.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/FormValue.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/FormalExpression.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalBusinessRuleTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalChoreographyTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalConversation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalManualTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalScriptTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/GlobalUserTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Group.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/HumanPerformer.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/IOParameter.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ImplicitThrowEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Import.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/InclusiveGateway.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/InputOutputBinding.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/InputOutputSpecification.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/InputSet.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Interface.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/IntermediateCatchEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/IntermediateThrowEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ItemAwareElement.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ItemAwareElementAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ItemDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Label.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/LabeledEdge.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Lane.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/LaneSet.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/LinkEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/MailTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ManualTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Message.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/MessageEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/MessageFlow.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/MessageFlowAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Monitoring.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/MultiInstanceLoopCharacteristics.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/NeedToKnow.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Operation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/OutputSet.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ParallelGateway.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Participant.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ParticipantAssociation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ParticipantMultiplicity.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/PartnerEntity.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/PartnerRole.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Performer.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Plane.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Point.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/PotentialOwner.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Process.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ProcessAction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Property.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ReceiveTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Relationship.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Rendering.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Resource.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ResourceAssignmentExpression.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ResourceParameter.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ResourceParameterBinding.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ResourceRole.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Role.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ScriptTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SecurityFlow.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SecurityFlowNode.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SendTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SeparationOfDuty.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SequenceFlow.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/ServiceTask.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Shape.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Signal.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SignalEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/StandardLoopCharacteristics.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/StartEvent.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SubChoreography.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SubConversation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/SubProcess.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Task.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/TerminateEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/TextAnnotation.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/TimerEventDefinition.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/Transaction.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/User.gif create mode 100644 src/org.activiti.designer.model.edit/icons/full/obj16/UserTask.gif create mode 100644 src/org.activiti.designer.model.edit/plugin.properties create mode 100644 src/org.activiti.designer.model.edit/plugin.xml create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNDiagramItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNEdgeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNLabelItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNLabelStyleItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNPlaneItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BPMNShapeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/BpmnDiItemProviderAdapterFactory.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/di/provider/DocumentRootItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ActivitiListenerItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ActivityItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AdHocSubProcessItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AlfrescoMailTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AlfrescoScriptBaseItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AlfrescoScriptTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AlfrescoStartEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AlfrescoUserTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ArtifactItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AssignmentItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/AuditingItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/BaseElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/BoundaryEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/Bpmn2ItemProviderAdapterFactory.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/BusinessRuleTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CallActivityItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CallChoreographyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CallConversationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CallableElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CancelEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CandidateGroupItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CandidateUserItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CatchEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CategoryItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CategoryValueItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ChoreographyActivityItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ChoreographyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ChoreographyTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CollaborationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CompensateEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ComplexBehaviorDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ComplexDataTypeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ComplexGatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ConditionalEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ConversationAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ConversationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ConversationLinkItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ConversationNodeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CorrelationKeyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CorrelationPropertyBindingItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CorrelationPropertyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CorrelationPropertyRetrievalExpressionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CorrelationSubscriptionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/CustomPropertyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataGridFieldItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataGridItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataGridRowItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataInputAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataInputItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataObjectItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataObjectReferenceItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataOutputAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataOutputItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataStateItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataStoreItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DataStoreReferenceItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DefinitionsItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DocumentRootItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/DocumentationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EndEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EndPointItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ErrorEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ErrorItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EscalationEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EscalationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EventBasedGatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/EventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExclusiveGatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExpressionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExtensionAttributeDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExtensionAttributeValueItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExtensionDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ExtensionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FieldExtensionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FlowElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FlowElementsContainerItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FlowNodeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FormPropertyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FormValueItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/FormalExpressionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalBusinessRuleTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalChoreographyTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalConversationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalManualTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalScriptTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GlobalUserTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/GroupItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/HumanPerformerItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/IOParameterItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ImplicitThrowEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ImportItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InclusiveGatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InputOutputBindingItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InputOutputSpecificationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InputSetItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InteractionNodeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/InterfaceItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/IntermediateCatchEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/IntermediateThrowEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ItemAwareElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ItemDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/LaneItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/LaneSetItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/LinkEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/LoopCharacteristicsItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MailTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ManualTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MessageEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MessageFlowAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MessageFlowItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MessageItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MonitoringItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/MultiInstanceLoopCharacteristicsItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/OperationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/OutputSetItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ParallelGatewayItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ParticipantAssociationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ParticipantItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ParticipantMultiplicityItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/PartnerEntityItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/PartnerRoleItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/PerformerItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/PotentialOwnerItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ProcessItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/PropertyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ReceiveTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/RelationshipItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/RenderingItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ResourceAssignmentExpressionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ResourceItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ResourceParameterBindingItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ResourceParameterItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ResourceRoleItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/RootElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ScriptTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SendTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SequenceFlowItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ServiceTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SignalEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SignalItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/StandardLoopCharacteristicsItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/StartEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SubChoreographyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SubConversationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/SubProcessItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/TaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/TerminateEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/TextAnnotationItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/ThrowEventItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/TimerEventDefinitionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/TransactionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/bpmn2/provider/UserTaskItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/dc/provider/BoundsItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/dc/provider/DcItemProviderAdapterFactory.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/dc/provider/DocumentRootItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/dc/provider/FontItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/dc/provider/PointItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/DiItemProviderAdapterFactory.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/DiagramElementItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/DiagramItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/DocumentRootItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/EdgeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/LabelItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/LabeledEdgeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/LabeledShapeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/NodeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/PlaneItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/ShapeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/dd/di/provider/StyleItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/ActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/ActivityActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/ActivityAuthorizationConstraintItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/AtomicActivityActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/AtomicItemAwareElementActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/AtomicProcessActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/AuthorizationConstraintItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/BindingOfDutyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/CompositeActivityActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/CompositeItemAwareElementActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/CompositeProcessActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/GroupItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/ItemAwareElementActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/NeedToKnowItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/PermissionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/ProcessActionItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/RoleItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/Securebpmn2ItemProviderAdapterFactory.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/SecurityFlowItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/SecurityFlowNodeItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/SeparationOfDutyItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/SubjectItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/UserItemProvider.java create mode 100644 src/org.activiti.designer.model.edit/src/org/eclipse/securebpmn2/provider/bpmn2EditPlugin.java create mode 100644 src/org.activiti.designer.model.editor/.classpath create mode 100644 src/org.activiti.designer.model.editor/.project create mode 100644 src/org.activiti.designer.model.editor/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.model.editor/build.properties create mode 100644 src/org.activiti.designer.model.editor/icons/full/obj16/Bpmn2ModelFile.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/obj16/BpmnDiModelFile.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/obj16/DcModelFile.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/obj16/DiModelFile.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/obj16/Securebpmn2ModelFile.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/wizban/NewBpmn2.gif create mode 100644 src/org.activiti.designer.model.editor/icons/full/wizban/NewSecurebpmn2.gif create mode 100644 src/org.activiti.designer.model.editor/plugin.properties create mode 100644 src/org.activiti.designer.model.editor/plugin.xml create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/bpmn2/di/presentation/BpmnDiActionBarContributor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/bpmn2/di/presentation/BpmnDiEditor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/bpmn2/presentation/Bpmn2ActionBarContributor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/bpmn2/presentation/Bpmn2Editor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/bpmn2/presentation/Bpmn2ModelWizard.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/dd/dc/presentation/DcActionBarContributor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/dd/dc/presentation/DcEditor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/dd/di/presentation/DiActionBarContributor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/dd/di/presentation/DiEditor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/securebpmn2/presentation/Securebpmn2ActionBarContributor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/securebpmn2/presentation/Securebpmn2Editor.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/securebpmn2/presentation/Securebpmn2ModelWizard.java create mode 100644 src/org.activiti.designer.model.editor/src/org/eclipse/securebpmn2/presentation/bpmn2EditorPlugin.java create mode 100644 src/org.activiti.designer.model.tests/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.model.tests/build.properties create mode 100644 src/org.activiti.designer.model.tests/plugin.properties create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNDiagramTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNEdgeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNLabelStyleTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNLabelTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNPlaneTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BPMNShapeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BpmnDiExample.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/BpmnDiTests.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/di/tests/DocumentRootTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ActivitiListenerTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ActivityTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AdHocSubProcessTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AlfrescoMailTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AlfrescoScriptBaseTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AlfrescoScriptTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AlfrescoStartEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AlfrescoUserTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ArtifactTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AssignmentTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/AuditingTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/BaseElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/BoundaryEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/Bpmn2Example.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/Bpmn2Tests.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/BusinessRuleTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CallActivityTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CallChoreographyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CallConversationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CallableElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CancelEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CandidateGroupTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CandidateUserTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CatchEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CategoryTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CategoryValueTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ChoreographyActivityTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ChoreographyTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ChoreographyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CollaborationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CompensateEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ComplexBehaviorDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ComplexDataTypeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ComplexGatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ConditionalEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ConversationAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ConversationLinkTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ConversationNodeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ConversationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CorrelationKeyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CorrelationPropertyBindingTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CorrelationPropertyRetrievalExpressionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CorrelationPropertyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CorrelationSubscriptionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/CustomPropertyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataGridFieldTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataGridRowTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataGridTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataInputAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataInputTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataObjectReferenceTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataObjectTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataOutputAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataOutputTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataStateTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataStoreReferenceTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DataStoreTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DefinitionsTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DocumentRootTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/DocumentationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EndEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EndPointTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ErrorEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ErrorTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EscalationEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EscalationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EventBasedGatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/EventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExclusiveGatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExpressionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExtensionAttributeDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExtensionAttributeValueTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExtensionDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ExtensionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FieldExtensionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FlowElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FlowElementsContainerTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FlowNodeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FormPropertyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FormValueTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/FormalExpressionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalBusinessRuleTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalChoreographyTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalConversationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalManualTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalScriptTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GlobalUserTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/GroupTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/HumanPerformerTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/IOParameterTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ImplicitThrowEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ImportTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InclusiveGatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InputOutputBindingTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InputOutputSpecificationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InputSetTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InteractionNodeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/InterfaceTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/IntermediateCatchEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/IntermediateThrowEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ItemAwareElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ItemDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/LaneSetTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/LaneTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/LinkEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/LoopCharacteristicsTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MailTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ManualTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MessageEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MessageFlowAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MessageFlowTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MessageTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MonitoringTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/MultiInstanceLoopCharacteristicsTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/OperationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/OutputSetTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ParallelGatewayTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ParticipantAssociationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ParticipantMultiplicityTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ParticipantTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/PartnerEntityTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/PartnerRoleTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/PerformerTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/PotentialOwnerTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ProcessTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/PropertyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ReceiveTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/RelationshipTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/RenderingTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ResourceAssignmentExpressionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ResourceParameterBindingTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ResourceParameterTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ResourceRoleTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ResourceTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/RootElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ScriptTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SendTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SequenceFlowTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ServiceTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SignalEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SignalTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/StandardLoopCharacteristicsTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/StartEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SubChoreographyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SubConversationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/SubProcessTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/TaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/TerminateEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/TextAnnotationTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/ThrowEventTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/TimerEventDefinitionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/TransactionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/bpmn2/tests/UserTaskTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/BoundsTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/DcExample.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/DcTests.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/DocumentRootTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/FontTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/dc/tests/PointTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/DiExample.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/DiTests.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/DiagramElementTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/DiagramTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/DocumentRootTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/EdgeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/LabelTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/LabeledEdgeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/LabeledShapeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/NodeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/PlaneTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/ShapeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/dd/di/tests/StyleTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/ActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/ActivityActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/ActivityAuthorizationConstraintTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/AtomicActivityActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/AtomicItemAwareElementActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/AtomicProcessActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/AuthorizationConstraintTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/BindingOfDutyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/CompositeActivityActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/CompositeItemAwareElementActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/CompositeProcessActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/GroupTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/ItemAwareElementActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/NeedToKnowTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/PermissionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/ProcessActionTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/RoleTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/Securebpmn2Example.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/Securebpmn2Tests.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/SecurityFlowNodeTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/SecurityFlowTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/SeparationOfDutyTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/SubjectTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/UserTest.java create mode 100644 src/org.activiti.designer.model.tests/src/org/eclipse/securebpmn2/tests/bpmn2AllTests.java create mode 100644 src/org.activiti.designer.model/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.model/build.properties create mode 100644 src/org.activiti.designer.model/model/BPMN20.ecore create mode 100644 src/org.activiti.designer.model/model/BPMN20.genmodel create mode 100644 src/org.activiti.designer.model/model/BPMNDI.ecore create mode 100644 src/org.activiti.designer.model/model/DC.ecore create mode 100644 src/org.activiti.designer.model/model/DI.ecore create mode 100644 src/org.activiti.designer.model/model/SecureBPMN20.ecore create mode 100644 src/org.activiti.designer.model/plugin.properties create mode 100644 src/org.activiti.designer.model/plugin.xml create mode 100644 src/org.activiti.designer.model/pom.xml create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ActivitiListener.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Activity.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AdHocOrdering.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AdHocSubProcess.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AlfrescoMailTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AlfrescoScriptBase.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AlfrescoScriptTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AlfrescoStartEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AlfrescoUserTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Artifact.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Assignment.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Association.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/AssociationDirection.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Auditing.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/BaseElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/BoundaryEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Bpmn2Factory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Bpmn2Package.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/BusinessRuleTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CallActivity.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CallChoreography.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CallConversation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CallableElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CancelEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CandidateGroup.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CandidateUser.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CatchEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Category.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CategoryValue.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Choreography.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ChoreographyActivity.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ChoreographyLoopType.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ChoreographyTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Collaboration.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CompensateEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ComplexBehaviorDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ComplexDataType.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ComplexGateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ConditionalEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Conversation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ConversationAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ConversationLink.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ConversationNode.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CorrelationKey.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CorrelationProperty.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CorrelationPropertyBinding.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CorrelationPropertyRetrievalExpression.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CorrelationSubscription.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/CustomProperty.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataGrid.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataGridField.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataGridRow.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataInput.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataInputAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataObject.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataObjectReference.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataOutput.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataOutputAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataState.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataStore.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DataStoreReference.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Definitions.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/DocumentRoot.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Documentation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EndEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EndPoint.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Error.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ErrorEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Escalation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EscalationEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Event.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EventBasedGateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EventBasedGatewayType.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/EventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ExclusiveGateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Expression.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Extension.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ExtensionAttributeDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ExtensionAttributeValue.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ExtensionDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FieldExtension.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FlowElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FlowElementsContainer.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FlowNode.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FormProperty.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FormValue.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/FormalExpression.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Gateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GatewayDirection.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalBusinessRuleTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalChoreographyTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalConversation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalManualTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalScriptTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/GlobalUserTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Group.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/HumanPerformer.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/IOParameter.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ImplicitThrowEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Import.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/InclusiveGateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/InputOutputBinding.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/InputOutputSpecification.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/InputSet.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/InteractionNode.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Interface.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/IntermediateCatchEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/IntermediateThrowEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ItemAwareElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ItemDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ItemKind.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Lane.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/LaneSet.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/LinkEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/LoopCharacteristics.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MailTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ManualTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Message.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MessageEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MessageFlow.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MessageFlowAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Monitoring.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MultiInstanceBehavior.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/MultiInstanceLoopCharacteristics.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Operation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/OutputSet.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ParallelGateway.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Participant.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ParticipantAssociation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ParticipantMultiplicity.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/PartnerEntity.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/PartnerRole.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Performer.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/PotentialOwner.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Process.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ProcessType.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Property.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ReceiveTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Relationship.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/RelationshipDirection.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Rendering.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Resource.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ResourceAssignmentExpression.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ResourceParameter.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ResourceParameterBinding.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ResourceRole.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/RootElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ScriptTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SendTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SequenceFlow.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ServiceTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Signal.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SignalEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/StandardLoopCharacteristics.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/StartEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SubChoreography.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SubConversation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/SubProcess.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Task.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/TerminateEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/TextAnnotation.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/ThrowEvent.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/TimerEventDefinition.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/Transaction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/UserTask.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNDiagram.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNEdge.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNLabel.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNLabelStyle.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNPlane.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BPMNShape.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BpmnDiFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/BpmnDiPackage.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/DocumentRoot.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/MessageVisibleKind.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/ParticipantBandKind.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNDiagramImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNEdgeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNLabelImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNLabelStyleImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNPlaneImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BPMNShapeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BpmnDiFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/BpmnDiPackageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/impl/DocumentRootImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/util/BpmnDiAdapterFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/util/BpmnDiResourceFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/util/BpmnDiResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/util/BpmnDiSwitch.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/di/util/BpmnDiXMLProcessor.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ActivitiListenerImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ActivityImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AdHocSubProcessImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AlfrescoMailTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AlfrescoScriptBaseImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AlfrescoScriptTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AlfrescoStartEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AlfrescoUserTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ArtifactImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AssignmentImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/AuditingImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/BaseElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/BoundaryEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/Bpmn2FactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/Bpmn2PackageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/BusinessRuleTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CallActivityImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CallChoreographyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CallConversationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CallableElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CancelEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CandidateGroupImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CandidateUserImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CatchEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CategoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CategoryValueImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ChoreographyActivityImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ChoreographyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ChoreographyTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CollaborationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CompensateEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ComplexBehaviorDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ComplexDataTypeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ComplexGatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ConditionalEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ConversationAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ConversationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ConversationLinkImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ConversationNodeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CorrelationKeyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CorrelationPropertyBindingImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CorrelationPropertyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CorrelationPropertyRetrievalExpressionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CorrelationSubscriptionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/CustomPropertyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataGridFieldImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataGridImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataGridRowImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataInputAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataInputImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataObjectImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataObjectReferenceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataOutputAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataOutputImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataStateImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataStoreImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DataStoreReferenceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DefinitionsImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DocumentRootImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/DocumentationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EndEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EndPointImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ErrorEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ErrorImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EscalationEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EscalationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EventBasedGatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/EventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExclusiveGatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExpressionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExtensionAttributeDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExtensionAttributeValueImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExtensionDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ExtensionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FieldExtensionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FlowElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FlowElementsContainerImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FlowNodeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FormPropertyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FormValueImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/FormalExpressionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalBusinessRuleTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalChoreographyTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalConversationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalManualTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalScriptTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GlobalUserTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/GroupImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/HumanPerformerImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/IOParameterImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ImplicitThrowEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ImportImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InclusiveGatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InputOutputBindingImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InputOutputSpecificationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InputSetImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InteractionNodeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/InterfaceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/IntermediateCatchEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/IntermediateThrowEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ItemAwareElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ItemDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/LaneImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/LaneSetImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/LinkEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/LoopCharacteristicsImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MailTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ManualTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MessageEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MessageFlowAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MessageFlowImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MessageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MonitoringImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/MultiInstanceLoopCharacteristicsImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/OperationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/OutputSetImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ParallelGatewayImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ParticipantAssociationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ParticipantImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ParticipantMultiplicityImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/PartnerEntityImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/PartnerRoleImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/PerformerImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/PotentialOwnerImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ProcessImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/PropertyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ReceiveTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/RelationshipImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/RenderingImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ResourceAssignmentExpressionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ResourceParameterBindingImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ResourceParameterImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ResourceRoleImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/RootElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ScriptTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SendTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SequenceFlowImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ServiceTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SignalEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SignalImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/StandardLoopCharacteristicsImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/StartEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SubChoreographyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SubConversationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/SubProcessImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/TaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/TerminateEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/TextAnnotationImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/ThrowEventImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/TimerEventDefinitionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/TransactionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/UserTaskImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/impl/bpmn2.ecore create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/util/Bpmn2AdapterFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/util/Bpmn2ResourceFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/util/Bpmn2ResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/util/Bpmn2Switch.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/bpmn2/util/Bpmn2XMLProcessor.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/Bounds.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/DcFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/DcPackage.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/DocumentRoot.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/Font.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/Point.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/BoundsImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/DcFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/DcPackageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/DocumentRootImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/FontImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/impl/PointImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcAdapterFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcResourceFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcSwitch.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcValidator.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/dc/util/DcXMLProcessor.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/DiFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/DiPackage.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Diagram.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/DiagramElement.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/DocumentRoot.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Edge.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Label.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/LabeledEdge.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/LabeledShape.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Node.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Plane.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Shape.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/Style.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/DiFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/DiPackageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/DiagramElementImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/DiagramImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/DocumentRootImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/EdgeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/LabelImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/LabeledEdgeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/LabeledShapeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/NodeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/PlaneImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/ShapeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/impl/StyleImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiAdapterFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiResourceFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiSwitch.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiValidator.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/dd/di/util/DiXMLProcessor.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Action.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/ActivityAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/ActivityAuthorizationConstraint.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/AtomicActivityAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/AtomicItemAwareElementAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/AtomicProcessAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/AuthorizationConstraint.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/BindingOfDuty.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/CompositeActivityAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/CompositeItemAwareElementAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/CompositeProcessAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Group.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/ItemAwareElementAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/NeedToKnow.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Permission.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/ProcessAction.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Role.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Securebpmn2Factory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Securebpmn2Package.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/SecurityFlow.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/SecurityFlowNode.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/SeparationOfDuty.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/Subject.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/User.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/ActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/ActivityActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/ActivityAuthorizationConstraintImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/AtomicActivityActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/AtomicItemAwareElementActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/AtomicProcessActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/AuthorizationConstraintImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/BindingOfDutyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/CompositeActivityActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/CompositeItemAwareElementActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/CompositeProcessActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/GroupImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/ItemAwareElementActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/NeedToKnowImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/PermissionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/ProcessActionImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/RoleImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/Securebpmn2FactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/Securebpmn2PackageImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/SecurityFlowImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/SecurityFlowNodeImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/SeparationOfDutyImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/SubjectImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/UserImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/impl/securebpmn2.ecore create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/util/Securebpmn2AdapterFactory.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/util/Securebpmn2ResourceFactoryImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/util/Securebpmn2ResourceImpl.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/util/Securebpmn2Switch.java create mode 100644 src/org.activiti.designer.model/src/main/java/org/eclipse/securebpmn2/util/Securebpmn2XMLProcessor.java create mode 100644 src/org.activiti.designer.model/src/main/resources/org/eclipse/bpmn2/impl/bpmn2.ecore create mode 100644 src/org.activiti.designer.parent/.classpath create mode 100644 src/org.activiti.designer.parent/.project create mode 100644 src/org.activiti.designer.parent/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/org.activiti.designer.parent/pom.xml create mode 100644 src/org.activiti.designer.updatesite/index.html create mode 100644 src/org.activiti.designer.updatesite/pom.xml create mode 100644 src/org.activiti.designer.updatesite/site.xml create mode 100644 src/org.activiti.designer.updatesite/web/assets/images/activiti_logo.png create mode 100644 src/org.activiti.designer.updatesite/web/assets/images/drive_web.png create mode 100644 src/org.activiti.designer.updatesite/web/assets/styles/site.css create mode 100644 src/org.activiti.designer.updatesite/web/site.xsl create mode 100644 src/org.activiti.designer.updatesite/work/site.css create mode 100644 src/org.activiti.designer.updatesite/work/site.xsl create mode 100644 src/org.activiti.designer.util/.settings/org.eclipse.jdt.core.prefs create mode 100644 src/org.activiti.designer.util/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.util/build.properties create mode 100644 src/org.activiti.designer.util/pom.xml create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/Activator.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/eclipse/ActivitiUiUtil.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/editor/ModifiableListEditor.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/features/AbstractCreateBPMNFeature.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSEnum.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSUtil.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/preferences/Preferences.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/property/ActivitiPropertySection.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/style/StyleUtil.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/workspace/ActivitiWorkspaceUtil.java create mode 100644 src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/workspace/BpmnProcessParser.java create mode 100644 src/org.activiti.designer.validation.bpmn20/META-INF/MANIFEST.MF create mode 100644 src/org.activiti.designer.validation.bpmn20/build.properties create mode 100644 src/org.activiti.designer.validation.bpmn20/plugin.xml create mode 100644 src/org.activiti.designer.validation.bpmn20/pom.xml create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/bundle/Activator.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/bundle/PluginConstants.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/BPMN20ProcessValidator.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/ProcessValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/ProcessValidationWorkerInfo.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/ProcessValidationWorkerMarker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/ScriptTaskValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/SequenceFlowValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/ServiceTaskValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/SubProcessValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/UserTaskValidationWorker.java create mode 100644 src/org.activiti.designer.validation.bpmn20/src/main/java/org/activiti/designer/validation/bpmn20/validation/worker/impl/ValidationCode.java diff --git a/CITATION b/CITATION new file mode 100644 index 0000000..3da2c6c --- /dev/null +++ b/CITATION @@ -0,0 +1,162 @@ +To cite the SecureBPMN lanuage in publications, please use + + Achim D. Brucker. Integrating Security Aspects into Business Process + Models. In it - Information Technology, 55 (6), pages 239-246, + 2013. + doi:10.1524/itit.2013.2004 + +A BibTeX entry for LaTeX users is + +@Article{ brucker:securebpmn:2013, + abstract = {Modern enterprise systems are often process-driven and, + thus, rely heavily on process-aware information systems. In + such systems, high-level process-models play an important + role both for communicating business requirements between + domain experts and system experts as well as basis for the + system implementation. Since several years, enterprise + system need to fulfil an increasing number of the security + and compliance requirements. Thus, there is an increasing + demand for integrating high-level security and compliance + requirements into process models, \ie, a common language + for domain experts, system experts, and security + experts.\\\\We present a security modelling language, + called SecureBPMN, that can easily be integrated into + business process modelling languages. In this paper, we + exemplary integrate SecureBPMN into BPMN and, thus, present + a common language for describing business process models + together with their security and compliance requirements.}, + abstract_de = {Moderne Unternehmensanwendungen m{\"u}ssen die Unternehmen + dabei unterst{\"u}tzen, ihre Gesch{\"a}ftsprozesse + effizient auszuf{\"u}hren. In solchen Anwendungen spielen + abstrakte Gesch{\"a}ftsprozessmodelle eine zentrale Rolle. + Die Gesch{\"a}ftsprozessmodelle werden f{\"u}r die + Kommunikation zwischen Gesch{\"a}fts- und IT-Experten + genutzt und dienen dar{\"u}ber hinaus als Basis f{\"u}r die + Implementierung der Unternehmensanwendungen. Seit einigen + Jahren m{\"u}ssen Unternehmensanwendungen einer steigenden + Anzahl von Sicherheits- und Compliance-Anforderungen + gen{\"u}gen. Hieraus ergibt sich ein gesteigerte + Bed{\"u}rfnis nach der Integration von Sicherheits- und + Compliance-Anforderungen in die + Gesch{\"a}ftsprozessmodelle.\\\\In diesem Artikel stellen + wir die Modellierungssprache SecureBPMN vor, welche es + erlaubt, Sicherheitsanforderungen im Kontext von + Gesch{\"a}ftsprozessmodelle zu spezifizieren.}, + author = {Achim D. Brucker}, + doi = {10.1524/itit.2013.2004}, + issn = {2196-7032}, + journal = {it - Information Technology}, + keywords = {Management of Computing and Information Systems, + SecureBPMN, BPMN, Break-Glass, Break-the-Glass}, + language = {USenglish}, + month = {dec}, + note = {Special Issue on ``Security in Business Processes.''}, + number = {6}, + pages = {239--246}, + pdf = {http://www.brucker.ch/bibliography/download/2013/brucker-securebpmn-2013.pdf}, + publisher = {Oldenbourg Wissenschaftsverlag}, + title = {Integrating Security Aspects into Business Process + Models}, + title_de = {Integration von Sicherheitsaspekten in + Gesch{\"a}ftsprozessmodelle}, + url = {http://www.brucker.ch/bibliography/abstract/brucker-securebpmn-2013}, + volume = {55}, + year = {2013} +} + +To cite the formal analysis of SecureBPMN models, please use + + Achim D. Brucker, Luca Compagna, and Pierre Guilleminot. Compliance + Validation of Secure Service Compositions. In Secure and Trustworthy + Service Composition: The Aniketos Approach. Lecture Notes in + Computer Science: State of the Art Surveys (8900), pages 136-149, + Springer-Verlag, 2014. + doi:10.1145/2295136.2295160 + +A BibTeX entry for LaTeX users is + +@InCollection{ brucker.ea:aniketos-compliance:2014, + abstract = {The Aniketos Secure Composition Framework supports the + specification of secure and trustworthy composition plans + in term of BPMN\@. The diversity of security and trust + properties that is supported by the Aniketos framework + allows, on the one hand, for expressing a large number of + security and compliance requirements. On the other hand, + the resulting expressiveness results in the risk that + high-level compliance requirements (\eg, separation of + duty) are not implemented by low-level security means (\eg, + role-based access control configurations).\\\\In this + chapter, we present the Composition Security Validation + Module (CSVM). The CSVM provides a service for checking the + compliance of secure and trustworthy composition plans to + the service designer. As proof-of-concept we created a + prototype in which the CSVM module is deployed on the SAP + NetWeaver Cloud and two CSVM Connectors are built + supporting two well-known BPMN tools: SAP NetWeaver BPM and + Activiti Designer.}, + address = {Heidelberg}, + author = {Achim D. Brucker and Luca Compagna and Pierre + Guilleminot}, + booktitle = {Secure and Trustworthy Service Composition: The Aniketos + Approach}, + doi = {10.1007/978-3-319-13518-2_10}, + editor = {Achim D. Brucker and Fabiano Dalpiaz and Paolo Giorgini + and Per H{\aa}kon Meland and Erkuden {Rios}}, + isbn = {978-3-319-13517-5}, + keywords = {Validation, Security, BPMN, SecureBPMN, Compliance}, + number = {8900}, + pages = {136--149}, + pdf = {http://www.brucker.ch/bibliography/download/2014/brucker.ea-aniketos-compliance-2014.pdf}, + publisher = {Springer-Verlag}, + series = {Lecture Notes in Computer Science: State of the Art + Surveys}, + title = {Compliance Validation of Secure Service Compositions}, + url = {http://www.brucker.ch/bibliography/abstract/brucker.ea-aniketos-compliance-2014}, + year = {2014} +} + +To cite the SecureBPMN tool-chain, please use + + Achim D. Brucker, Isabelle Hang, Gero Lückemeyer, and Raj + Ruparel. SecureBPMN: Modeling and Enforcing Access Control + Requirements in Business Processes. In ACM symposium on access + control models and technologies (SACMAT). , pages 123-126, ACM + Press, 2012. + doi:10.1145/2295136.2295160 + +A BibTeX entry for LaTeX users is + +@InProceedings{ brucker.ea:securebpmn:2012, + abstract = {Modern enterprise systems have to comply to regulations + such as Basel III resulting in complex security + requirements. These requirements need to be modeled at + design-time and enforced at runtime. Moreover, modern + enterprise systems are often business-process driven, i. + e., the system behavior is described as high-level business + processes that are executed by a business process execution + engine.\\\\Consequently, there is a need for an integrated + and tool-supported methodology that allows for specifying + and enforcing compliance and security requirements for + business process-driven enterprise systems.\\\\In this + paper, we present a tool chain supporting both the + design-time modeling as well as the run-time enforcement of + security requirements for business process-driven systems.}, + address = {New York, NY, USA}, + author = {Achim D. Brucker and Isabelle Hang and Gero L{\"u}ckemeyer + and Raj Ruparel}, + booktitle = {ACM symposium on access control models and technologies + (SACMAT)}, + copyright = {ACM}, + doi = {10.1145/2295136.2295160}, + isbn = {978-1-4503-1295-0}, + language = {USenglish}, + location = {Newark, USA}, + mycopyrighturl= {http://dl.acm.org/authorize?6705782}, + pages = {123--126}, + pdf = {http://www.brucker.ch/bibliography/download/2012/brucker.ea-securebpmn-2012.pdf}, + publisher = {ACM Press}, + title = {{SecureBPMN}: Modeling and Enforcing Access Control + Requirements in Business Processes}, + url = {http://www.brucker.ch/bibliography/abstract/brucker.ea-securebpmn-2012}, + year = {2012} +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e5969a7 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# SecureBPMN +[SecureBPMN](https://www.brucker.ch/projects/securebpmn/index.en.html) +is a domain-specific modeling language that allows to model security +aspects (e.g., access control, separation of duty, +confidentiality). SecurePBPMN is defined as a meta-model that can +easily be integrated into BPMN and, thus, can be used for modeling +secure and business processes as well as secure service compositions. + +## Installation +### Prerequisites +* Eclipse Helios + +### Preparing the Eclipse environment +To initialize the Eclipse project structure, please do + cd src/com.sun.xacml + mvn install + cd ../org.activiti.designer.parent + mvn clean eclipse:clean + mvn eclipse:eclipse + +After this, all projects can be imported into a fresh Eclipse +workspace using `File -> Import -> Existing Projects into Workspace`. + +### Generate Model Classes +1. Open the folder `model` in the project `org.activiti.designer.model` +2. Open `BPMN20.genmodel` +3. Select the top level node (`bpmn2`) +4. Select `Generator -> Reload...` from the top-level menu, select + `Ecore model` and complete the wizard. While doing this, ensure + that all packages are select in the `Package Selection` screen. +5. Select the top level node (`bpmn2`) +6. Select `Generator -> Generate all` from the top-level menu + +### Start Eclipse Application +Select the project `org.activiti.designer.eclipse` and select `Run as +-> Eclipse application` in the context menu (right click). + +## Team +Main developer: [Achim D. Brucker](http://www.brucker.ch/) + +### Contributors +* Jan Alexander +* Matthias Klink +* Raj Ruparel diff --git a/examples/CaseStudyC/Get Civil.activiti b/examples/CaseStudyC/Get Civil.activiti new file mode 100644 index 0000000..e7d2acd --- /dev/null +++ b/examples/CaseStudyC/Get Civil.activiti @@ -0,0 +1,739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/Get Civil.png b/examples/CaseStudyC/Get Civil.png new file mode 100644 index 0000000000000000000000000000000000000000..a10711b725054fd49c099b15a336952eea11bbf3 GIT binary patch literal 26009 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/Get Legal Info.png b/examples/CaseStudyC/Get Legal Info.png new file mode 100644 index 0000000000000000000000000000000000000000..0dfde91b64ca9fa55e1c1adfd2b6e579070215a9 GIT binary patch literal 15562 zcmeHuXH=8f{;o3~bu7TlID&}EC;}qQ5do<=XB1JY(jh=Znh+pJfDlUJ97P5Y5Tw^p zdP$Iy1V};@M5GG=LQ5jOClE>qA>_X3%sF%J|J)Dv!~JsCuvl3xdD-u8Kl@joXA^zL z%uwXWsU!RL?Gw3u>xRX?efwqi?fW|Yo3DZYnHYFO+qX|Q@%D{>ScPOS(~tU`=0?c- z7d`aG)%~blAW zBeUYPCv)|`Bn`zR4eB|cD*XCB)!RplqgEzeeWq2^*COV=ed&E;(TG$Z2i0x?!lT}i zmDCZnHQUKT>2Ezg+1>4mK&=UT5NREB?BDi1N^jsa?%%i1*NpM?zF&?1`uGcj|K#Hjh`y85$R5jc-=A z{Xn990B;1d#w5MP&BjJy6hW>N@#f~T4syZD6TdRl{M}Gv1pldsRMSs~J^dLi8M#R~ z$Gru7Esav2Ia4o@Z!$7}m{@rqCq=8Uhp)6emN(Do_a5yqbQbmWzjiH3OuCzR=S6bG zw2{W~LZ2*)YPa>w!3A}Wjls2tVWFXZqoIp!mh!b3BWDndhvShFXRrDH$PP$Ru)fVBo|NdNcjt&BAzxIn|acgaTEoiqB zO_?tODVw#Of{Do7-P~+5M{!=n5oS>PbZXqxdif(o$x4#sq7z|pB!rK>-zQU2Ndjsb~k7cN(6uN^24_WB*ubh-RSVC#IVWfAK{Z0fOfM#?J8Vs^yt6$99WLPnF5WbzTZysaDUVam%(E`J`gA3khd*=t4{w1wJ=mXeKATma2Ot zRd*{ifSc6@(cfAxDo261)Qf4GTMRwm3)pBneD34R%gJLATs_11(}$0zIRy`Q7{+Jo z26;C>HGcvTI~%@=qs2!?16auBWD+>a!zSyEcm;Q#Vd2DymFp>~xz5yAfM*!lU>$j# zYUbJ65xUUvvT&u_@d@&kxn|B<8Bbz)XyWz=HjnQq5pj?H(z5OC@wT^`FZR2(eVCtO zH*&4E1II%S;ayu3RKWO(A7wi{82-&7v$uaP@dN*yo$P`G!pTIKYp^b-Nr zAD)djiT4d`E;AcEX=HoiWcOPrwjNI)Xl6@FI0fGA)t|xHgzl1Ue8*{%#V_(<7vy`a z#J`E)A0>p(n+s{mhtL+gL$#KZZEfq>sIArFg~8>L)XDl$yK0kb=Mqk9osz>+cDH@n zq+q0`CZ)E`E&?mmqozVO~hP= z2i8^(4cJ0*_%9dVBz4_jL$fSY8Zw#&zc<9bzn;T?OM^Pp(mG+>bC)(YH~knSr1R}^ zykJ0ra#H*D!^WPArP;*%0dZ7>t1i;LV#jfOTJwcdf~bIK%@!7-SFs2s;Vfi(n@P^N z&}w#}GVfyL)~8&<#k~VUFfvKQJB**w%^5*_CnC(EK$s5@l~wKsgoz|{D;bRkw5tq|H$-A zE|_J_Q$gkUiVNfG5gS&Vniu1e&81O!`mYxvBpf+9!ui7EZRV{>Y44Nr<&*q3^|wCc z2Q3C$b!fr{7%wE8LtG-Z&kq{sw>Du2egf}wXM!KyP@j`{`Qc=orrfmHT&SSWST$l+ zhgpwcGseW64yArcSpna5$@(a}Pi1PrtRXg)kDAP zIV_Q-9bB<9gMp#evg)N9M3uhev+4U8VM7kvAFQSD9t{f7!c*y=F~t%oyqTiOv!tx#qijF5kU6SoXME?>=X{wREZsEN zwEg$B;FXr^Y!m{)LR%{VQ62wa%~xv{lNn}_gP!Tkh*fErqwLVkh5P}^aXG*G=~RdS z$9kD45NL$l07> zMR3^WlBB87wn|Y@y#Ul?8;K6V$Dn&a+rq_}D)hXsb%737yN|m(ot=tHR6Gi{XFFGa zutsz)?xtT`&c3ytDZZ>;!`9DkToaUFkmPr``zTP|J9qd*F!DV%j6)meJ?&2#0o8du- z-~76p92#<704X!Gujo(xlElP&dNOKwX6m0QN0fL<#;f`aIjntm)%3)nfL
  • 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/Get Lots.png b/examples/CaseStudyC/Get Lots.png new file mode 100644 index 0000000000000000000000000000000000000000..e65e8e3ded8d67268334412ee67020dd43d90df6 GIT binary patch literal 9184 zcmeI2X;_n4vVfWCR%S${yHQaQ=x#?55Ym8vtm#%8Y!^`3WQ{FKK$ai`17sVAMh6g3 z*<_7~fDlNOEkYn^L7^c+1PozIB4CIKCV}h;S#I=RXYPIO@B8CEkAJ`C`_6Z&>QvQR zRVU|+pYN7UyEhpa7;O3F__1>a247ei82tI(U;eCrvi$8=JOhKhjlUfGDKNc?&)9Oi zSdN^&I`|~sGoUcGDr~p>XAbw!#lgg5m+F6PG#N{beiRW7efu>yZlhD(x7c6o;@x-M z92pP)Vqf`eA2cERZyPalXEU$ex*0r?bN+}=*O`AteUz>j4Gg{xG&T6~ zOWFp5uYOAVlfkjikN$sag65c&mBnB%%+1aDe12kLV!(bZlr_2c2eej=!{M%9zaCt; z@1NW?HaC3@X7+&zKxFZ`WH!j;Q^**)~k|8)W>! a-Mkky;9AMST>m;MmvmT9xU?H=w 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 literal 0 HcmV?d00001 diff --git a/examples/CaseStudyC/Get Solicitor.activiti b/examples/CaseStudyC/Get Solicitor.activiti new file mode 100644 index 0000000..05ce04f --- /dev/null +++ b/examples/CaseStudyC/Get Solicitor.activiti @@ -0,0 +1,739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/Get Solicitor.png b/examples/CaseStudyC/Get Solicitor.png new file mode 100644 index 0000000000000000000000000000000000000000..dd7eda5864153c1e643f926f3e21a768f56a9e90 GIT binary patch literal 25562 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 f__%@Sfp-mk2{?=&M(#I!68js{W + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/PublishLot.png b/examples/CaseStudyC/PublishLot.png new file mode 100644 index 0000000000000000000000000000000000000000..501c3c33d10c0d56d50e6d6432b39ce57bff6847 GIT binary patch literal 17740 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 z z%87Vg^=rHFAX4=__s+d~RW4y5LgyHn0j*+z5kazMf!!K_uZDi*djP(&9=@t}_uWiq zqJ1SuMGd1Dq;g*HaM67Rg@G{fKSL3A@WLZJd8@psh?G~N~$<3 zAoN$8J8bF})2sH!>A;{~AP#>}Xb0fF(h%%Zd_(ZUHr#cS^aiuHiw)E{V~MWVy1K>` zdDGlPM2lBBaAz?M5?8r}R-w*_Y>TPnUevCptkW;L>Pq*;%F%QPblp;Gp#2C3+7Bg4 zo0Awh?QFn<(7TX6D+U5K!)T|N&80602oQh#DA4lPldjtx!JUU4mG68BJAg|79e1wh zqDbU$m6N$|3E1DxPKc=(C~X$Hh7;3x1e*ZLq7@VOJ{y3n4f6QY(kL%X4P}NKN=y@N zyjOF)uB;FgegJM~$HM@jVxy1irA`0{9~st$Ew6MNPBo=Lhm>f~UlScrZUmu9x zQ(c`moS#3w7d!l@ZMma4+(00M=OLueo-yBH#(YIBq$6ghfNt{b45Z{Ug-^-9n3gCv z$8Kr-i%DBD-*3prgvir|0SuD?a^9QsoKm_DezF9;Mq{2z?(TD}2#94lP0WWOg(F*SyPkUZ1ql%%)+ZBL&T$ zzW0jxGt^T0+oQi)y?q{s}5F?gVTTfT(Bkpmq)%j!FFGx)1o#+BD8&Ib^=ZG%E;iev4J6c z)e3W=KSwA9MgW9Iosd@zOUlHH{QNq83Fgx7*bn>)%J+q`Gi=-AULX+2@NkgV&a(1l zKpZqkijSc#(P(19!OB=dd74A)f-DCRA7J$v`iu^7F> z+t`kejg5W%3UQm1_QJ5;2}NN$*(|AgCrPyFcC9m?c5Ydj{gCHwMG?$(@RPQIfdRme0oWqqupmKlvG&?qkB>q=tlL8R&J4hgG}1&CF1Y(V%j{Op2nCEX8@B+s@I52uM@ z4RX82ifn|mX321^zw{dawXz!qg(@+`V1|^WJlLXC=6J0i#Cz_Q0QI|ELkXS8AF{vI zB@s`ft{P*w3BTL-A++r@4~KizD2uM$m)96_0?5&w|11U9P`;krX*lK44x1>k(O?K9 z^7mptr7H!LPQC>Ac`OFdXZTq{H^1TVw7o+LNdv|&?|$ikv^#3W2G@O0Lr!fG($JFO z1%FNbFXi|`^Gt=n#8%E3OL+kyyJoiDP=KG%0H^aDbOz(0NP$!a_C@oG>wD}Z|g>BQ%Y6W*b-O9I2|vlX;nO#;XfZ0s7UcD=%;9mrqP z{&Pfi7{9{SKpF%Q;l`^1m7ka4kgW>dmR)@9^GgI$17Kt;c>-z5ez(3XuVkK_nK$>J zGxtAqiBN6%f1v8lBmRx5V_02?9Yh)LYXDeYrI0#z@r~V4*xPg&=)BI2r*&ZiQ`r z!O{24PeKsPknXTi`)2QxB&97tJ_DXFD;)smPmsR8I0{hDIw)?;?#P#!83_%!kZn0w zSy7Qh&88KtOCUof_;!ut?c0G%8Gf`~E4t5Wkr)4joM`Z=bHD6xo7ESRBzmwtU+qqP zEFaV$-@LQ4^Y6?Y@u0UCUglu}T@C_2X0T};EIY0*!%&HC>M06--ba|m3m&Xnrsl(L0rf0u3>0vOMP5(Fz>lA9ybwC z(R>2@3#K=~0bj5q_+S}0tN>$mp57J3d|qH5FJkOT-rxVS(U~?gJUD~R%dDktb-`8% zME}v}ARMgurSASW66;U$uk!`egCc|ouv0o9$%V|xU00jY03Bc*W_P?jD$U%g1$Rdk zfJ2zr@Q+i#uC1)D22wZM2dAUjBGsDz_vG}v-;fg`DOG?4HTVN|Vpp2V_J7!e(zF2P zT=A_0ALww0ExY(VRpKkKJ~4a)cC8N3xwI*rFNpl9rV9)VY-?*9V9bCuWU2S?qj^Wk z%}zMrAerebMRf|4eggwz%iTt27{RJOP>AX;RCk*_F7uS$jlXHQ=OP?NZhO%Z4gPA- z+Z)3x?AUs%2`^*s+M*&N8b(3q@SyP_K_b-GGiHF*F*GUAwp2JP-=jkxU{fab90kXETgkMX8YaE3oCDNGA+p| zw$OW~SOgB2f!eATf4IK66sMJWJHfU^P6rV(`$ga?{pi;6@^XnyyXs|*Pjr2>F9qlW z0HG`9p93eF2akR{!`&-jfGoTLZ;I*>2ZLZV>S9kC9Zx4N(veG}**uwa>Joh==yscM zCMDOZVRnCWZed&>mSI*K4BU^Jz+&GZ@n5r#G31aHx1^=J&<;SZN3L^nr%Fi=fhl&#V0$~e_s1B(BaMI}em|9Urj+pWra?A9+q`fB(mO}r)%uS{X0AQnpL8jez7$o163Csf zL|8Jw^?13v-#qZMwfzW%@N&m}W~}Kr0XIQl?rCfI?c(15qSWU$;^nq{j4WI{#WI1e zz;UI<1|KbT1-fQ{Xwsy;o4Oqq7MU@Hov8KGxe-8IX2E8>$`RF}ZawwnciHIbco&(4 zoWnpaaB@EyaKw`j_H_NoTe|=m(bcoJ(3szQhVc-XUvFgln!<=hrGO*!7rGROiO!K0N1CZJr#u{g`(#ENrgD9TpIH z`I?Y0ty*%Hsi4pl8)?nj?av$@r}ey$xWSP(xe zk=7k>_|&iUoe!#@TtXTF+^7Rgi?E_x|Hn%aUL}y;Y4?Rly+zSUohI{{y|?U3#y-Zp zOhoQg@d5&MzHn*^9hWrv9$w(Tz zjHrq}*7}le@4bAW+8k>sfcBg$05twGV@9cO%ZZaF9O9#2w9CdC`u!Q#^gJB=-FlE` zh)nIfOK;!F%A5XmF{Pz)rzOge5UDnUo_%_@uh_Nk<-NBY@6#Q4EjHX2o{!F*vJ;dp zFrXv>m!9yckR4C8cVPDO;PDV7$L{s>;7>7@0)DSVxI=)i4STqsH!fXIE`+x1BL8jq ztVKSAi!NpkID|tW@8W?*Lco2>+)nXMOTHmPdtc>@L&$UYN}R(-sH(NT1jP9WD>cXQ z3fRl=GGN_#!J^j#7XT1YPg2k^=VSf(?u#-#O$wR@d#BwfJGy>DA4siqp~4jJ$j`^- z_6kj8S>bB~pPsl_IVkojl?m~E2;BcG(4dGH9Nlcc&-S>| z_{-(DD(;sWzVm<|PUM=mUON$18T=s#x9;CtmC5n@!uodW`55C;f7dn2$6JH{+=cfh zxa-i|5AMYh+83v|t?tyx)nt4`?<)$L&9%suOt$C?W^GK*-#5dJU}vdtp4O8l^6b?W z@@D5G=XT!-cq;=p=B$+`{5*PKQ+cK2`{<-zcA~i4!pk_l({T9lShLmXto5oV(XJLQ zBTY=qUT$K+SX;lN2tA_-F77_yjv7)jE6c-Bi6|n?QSpG1G;7n$FDXi3jj=jS_yr>8?!hitsOK)OiaKIE^k^y`~n^6>Pu zAk)Hp;Kk(-XY^l32nhFbdw2z|hN9IXfjC%2S(y~j-9+!X5`YP@Gi5y|OjJ0x$EE3m zPTM2bxf_C?KE3oGAJG1%O51DZnxXx_sk9yNBW{4NWSub`?|n(|nt5mlJ}i0z0w6W* zTCCCCpP}{DDR_UUot<4^pbC%|t->}!^DTh(aQO!mNJB>*^llA}R9HS;*n0ULxCtywTYfmyK+eGh_jUmgmLBj@4x>xSHJ%|UPu3*IsLc%F9H9v qE&sDE|2_YI#sA+u^A9@c-9TJ%JBW=P_%A6(9^TVYN2xx2`F{ay20T^( literal 0 HcmV?d00001 diff --git a/examples/CaseStudyC/RequestLot.activiti b/examples/CaseStudyC/RequestLot.activiti new file mode 100644 index 0000000..f3da29c --- /dev/null +++ b/examples/CaseStudyC/RequestLot.activiti @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/RequestLot.png b/examples/CaseStudyC/RequestLot.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f58d2075f0d20c0f1e04e92d523cb45aaa3d41 GIT binary patch literal 24490 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 xAm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/CaseStudyC/Select Lot.png b/examples/CaseStudyC/Select Lot.png new file mode 100644 index 0000000000000000000000000000000000000000..65762a3f38d6d07d1c5b145b0a0179e6490159a5 GIT binary patch literal 18193 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/JobApplication/JobApplication.png b/examples/JobApplication/JobApplication.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9bb98576d9c1cbffa6373af187e853bf6e1dd1 GIT binary patch literal 85670 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 literal 0 HcmV?d00001 diff --git a/examples/JobApplication/generated/JobApplication.aslan b/examples/JobApplication/generated/JobApplication.aslan new file mode 100644 index 0000000..ba4d307 --- /dev/null +++ b/examples/JobApplication/generated/JobApplication.aslan @@ -0,0 +1,101 @@ +section signature: + + user_to_role : user * role -> fact + poto : userORrole * taskName -> fact + task_to_data : taskName * set * set -> fact + aknows : entity * data -> fact + mc_pair : data * data -> data + contains : set * data -> fact + task : taskName * nat -> taskInstance + canExecute : user * role * humanTaskName -> fact + granted : user * role * taskInstance -> fact + executed : user * taskInstance -> fact + ready : taskInstance -> fact + done : taskInstance -> fact + entity > organization + entity > user + data > object + data > set + userORrole > user + userORrole > role + taskName > automatedTaskName + taskName > humanTaskName + +section types: + + parallelgateway1_to_usertask7,parallelgateway1_to_servicetask3,parallelgateway2_to_servicetask4,start_event_startevent2: fact + HT,usertask1,usertask2,usertask3,usertask4,usertask5,usertask6,usertask7,usertask8,usertask9: humanTaskName + IN,OUT,in_usertask1,out_usertask1,in_servicetask1,out_servicetask1,in_usertask2,out_usertask2,in_servicetask2,out_servicetask2,in_usertask3,out_usertask3,in_usertask4,out_usertask4,in_usertask5,out_usertask5,in_usertask6,out_usertask6,in_usertask7,out_usertask7,in_servicetask3,out_servicetask3,in_servicetask4,out_servicetask4,in_usertask8,out_usertask8,in_usertask9,out_usertask9,in_servicetask5,out_servicetask5: set + manager,supervisor,clerk,R: role + N,N0,N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12,N13,N14,N15,N16,N17,N18,N19,N20,N21,N22,N23,N24,N25,N26,N27,N28,N29,N30,N31,N32,N33,N34: nat + AT,servicetask1,servicetask2,servicetask3,servicetask4,servicetask5: automatedTaskName + user1_manager,user2_manager,user1_supervisor,user2_supervisor,user1_clerk,user2_clerk,A,U0,U1: user + +section inits: + + initial_state init_1 := + + user_to_role(user1_manager,manager). + user_to_role(user2_manager,manager). + user_to_role(user1_supervisor,supervisor). + user_to_role(user2_supervisor,supervisor). + user_to_role(user1_clerk,clerk). + user_to_role(user2_clerk,clerk). + task_to_data(usertask1,in_usertask1,out_usertask1). + task_to_data(servicetask1,in_servicetask1,out_servicetask1). + task_to_data(usertask2,in_usertask2,out_usertask2). + task_to_data(servicetask2,in_servicetask2,out_servicetask2). + task_to_data(usertask3,in_usertask3,out_usertask3). + task_to_data(usertask4,in_usertask4,out_usertask4). + task_to_data(usertask5,in_usertask5,out_usertask5). + task_to_data(usertask6,in_usertask6,out_usertask6). + task_to_data(usertask7,in_usertask7,out_usertask7). + task_to_data(servicetask3,in_servicetask3,out_servicetask3). + task_to_data(servicetask4,in_servicetask4,out_servicetask4). + task_to_data(usertask8,in_usertask8,out_usertask8). + task_to_data(usertask9,in_usertask9,out_usertask9). + task_to_data(servicetask5,in_servicetask5,out_servicetask5). + start_event_startevent2 + +section hornClauses: + + hc rbac_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(R,HT) + hc direct_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(A,HT) + hc poto_usertask1:= poto(clerk,usertask1) + hc poto_usertask2:= poto(clerk,usertask2) + hc poto_usertask3:= poto(manager,usertask3) + hc poto_usertask4:= poto(manager,usertask4) + hc poto_usertask5:= poto(clerk,usertask5) + hc poto_usertask6:= poto(manager,usertask6) + hc poto_usertask7:= poto(clerk,usertask7) + hc poto_usertask8:= poto(supervisor,usertask8) + hc poto_usertask9:= poto(supervisor,usertask9) + +section rules: + + step authorizeTaskExecution(A,R,HT,N) := canExecute(A,R,HT). ready(task(HT,N)) => granted(A,R,task(HT,N)) + step h_taskExecution(A,R,HT,N,IN,OUT) := granted(A,R,task(HT,N)). task_to_data(HT,IN,OUT) => executed(A,task(HT,N)). done(task(HT,N)). task_to_data(HT,IN,OUT). aknows(A,IN). aknows(A,OUT) + step atask_execution(AT,N,IN,OUT) := ready(task(AT,N)). task_to_data(AT,IN,OUT) => done(task(AT,N)). task_to_data(AT,IN,OUT) + step w_usertask1(N0) := start_event_startevent2=[exists N0] => ready(task(usertask1,N0)) + step w_servicetask1(N2,N1) := done(task(usertask1,N2))=[exists N1] => ready(task(servicetask1,N1)) + step w_usertask2(N4,N3) := done(task(servicetask1,N4))=[exists N3] => ready(task(usertask2,N3)) + step w_servicetask2(N6,N5) := done(task(usertask2,N6))=[exists N5] => ready(task(servicetask2,N5)) + step w_usertask3(N8,N7) := done(task(servicetask2,N8))=[exists N7] => ready(task(usertask3,N7)) + step w_usertask4(N10,N9) := done(task(usertask3,N10))=[exists N9] => ready(task(usertask4,N9)) + step w_usertask5(N12,N11) := done(task(usertask4,N12))=[exists N11] => ready(task(usertask5,N11)) + step w_usertask6(N14,N13) := done(task(usertask5,N14))=[exists N13] => ready(task(usertask6,N13)) + step w_parallelgateway1(N15) := done(task(usertask6,N15)) => parallelgateway1_to_usertask7. parallelgateway1_to_servicetask3 + step w_usertask7(N16) := parallelgateway1_to_usertask7=[exists N16] => ready(task(usertask7,N16)) + step w_servicetask3(N17) := parallelgateway1_to_servicetask3=[exists N17] => ready(task(servicetask3,N17)) + step w_parallelgateway2(N18,N19) := done(task(usertask7,N18)). done(task(servicetask3,N19)) => parallelgateway2_to_servicetask4 + step w_servicetask4(N20) := parallelgateway2_to_servicetask4=[exists N20] => ready(task(servicetask4,N20)) + step w_usertask8(N22,N21) := done(task(servicetask4,N22))=[exists N21] => ready(task(usertask8,N21)) + step w_usertask9(N24,N23) := done(task(usertask8,N24))=[exists N23] => ready(task(usertask9,N23)) + step w_servicetask5(N26,N25) := done(task(usertask9,N26))=[exists N25] => ready(task(servicetask5,N25)) + +section goals: + + attack_state sod_securitySod1_1(U0,N27,N28):= executed(U0,task(usertask9,N27)). executed(U0,task(usertask2,N28)) + attack_state sod_securitySod2_1(U0,N29,N30):= executed(U0,task(usertask4,N29)). executed(U0,task(usertask3,N30)) + attack_state bod_securityBod1_1(U0,U1,N31,N32):= executed(U0,task(usertask8,N31)). executed(U1,task(usertask9,N32))& not(equal(U0,U1)) + attack_state bod_securityBod1_2(U0,U1,N33,N34):= executed(U0,task(usertask9,N33)). executed(U1,task(usertask8,N34))& not(equal(U0,U1)) diff --git a/examples/JobApplication/generated/JobApplication.res b/examples/JobApplication/generated/JobApplication.res new file mode 100644 index 0000000..f3d481d --- /dev/null +++ b/examples/JobApplication/generated/JobApplication.res @@ -0,0 +1,455 @@ +% PARAMETERS: + + Protocol: JobApplication + Problem category: if + + Compound types: on + Step compression: on + Intruder Knowledge As Axioms: off + Weak Type-Flaws (iff newgp): off + + Technique: Graphplan-based Encoding using the EFA schema + Min Steps: 0 + Max Steps: 80 + Delta Steps: 1 + Level Mutex: 0 + Solver: minisat + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% SATE file generated in 0.1 sec... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: INIT + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Initial Facts: 63 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 1 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 0 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 2 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 1 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 3 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 2 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 4 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 3 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 5 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 4 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 6 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 5 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 7 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 6 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 8 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 7 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 9 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 8 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 10 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 9 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 11 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 10 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 12 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 11 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 13 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 12 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 14 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 13 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 15 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 14 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 16 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 15 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Goals: 25 0.0 + Refinement Schema: 0 0.0 + Horn Clauses Axioms: 1728 0.14 + User Axioms: 0 0.0 + Ape Schema: 15270 1.2 + Explanatory Frame Schema: 5335 0.94 + ------ + Total: 2.28 + +* SUB-PHASE: Solver SAT formula Updated + + STATISTICS + Depth: 16 + Atoms: 6388 + Clauses: 22421 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 17 + +* SUB-PHASE: Search for SAT models.. + + Found 1 models in 0.0 sec. + +* SUB-PHASE: Models into Partial Order Plans (POPs) + + STATISTICS RUNTIME(sec) + model2pop 1 3.0 + ------ + Total: 3.0 + +* SUB-PHASE: Partial Order Plans (POPs) validations + + STATISTICS VALID RUNTIME(sec) + POP 1: true 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Partial Order Plans (POPs) printing + + -------------------------------------------------------------------- + pop 1: + + GOALS: [sod_securitySod2_1(user1_manager,fnat(n9,0,0),fnat(n7,0,0))] + + Step 0: [sc_w_usertask1_1(0)] + Step 1: [sc_authorizeTaskExecution_1(user1_clerk,clerk,usertask1,fnat(n0,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 2: [sc_h_taskExecution_1(user1_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 3: [sc_w_servicetask1_1(fnat(n0,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 4: [sc_atask_execution_1(servicetask1,fnat(n1,0,0),in_servicetask1,out_servicetask1),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 5: [sc_w_usertask2_1(fnat(n1,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 6: [sc_authorizeTaskExecution_1(user1_clerk,clerk,usertask2,fnat(n3,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 7: [sc_h_taskExecution_1(user1_clerk,clerk,usertask2,fnat(n3,0,0),in_usertask2,out_usertask2),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 8: [sc_w_servicetask2_1(fnat(n3,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 9: [sc_atask_execution_1(servicetask2,fnat(n5,0,0),in_servicetask2,out_servicetask2),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 10: [sc_w_usertask3_1(fnat(n5,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 11: [sc_authorizeTaskExecution_1(user1_manager,manager,usertask3,fnat(n7,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 12: [sc_h_taskExecution_1(user1_manager,manager,usertask3,fnat(n7,0,0),in_usertask3,out_usertask3),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 13: [sc_w_usertask4_1(fnat(n7,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 14: [sc_authorizeTaskExecution_1(user1_manager,manager,usertask4,fnat(n9,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 15: [sc_h_taskExecution_1(user1_manager,manager,usertask4,fnat(n9,0,0),in_usertask4,out_usertask4),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + Step 16: [rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9)] + -------------------------------------------------------------------- + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +RESULTS + +Attacks Found: true +Stop Condition Reached: false +Formula statistics: + Graph Construction Time: 0.4 + Graph Leveled Off: no + Graph2SAT Time (sec): 2.28 + Encoding Time (sec): 2.679 + Depth: 16 + Atoms: 6388 + Clauses: 22421 +Solving statistics: + Total Solving Time (sec): 0.0 + Last Solving Time (sec): 0.0 +Abstraction/Refinement statistics: + Validation Time (sec): 0.0 + Models into POPs Time (sec): 3.0 + Refinement iterations: 0 + +Total Time: 5.679 + + diff --git a/examples/JobApplication/generated/JobApplication.result b/examples/JobApplication/generated/JobApplication.result new file mode 100644 index 0000000..2c8eb56 --- /dev/null +++ b/examples/JobApplication/generated/JobApplication.result @@ -0,0 +1,77 @@ +INPUT JobApplication.aslan +SUMMARY ATTACK_FOUND + GOAL: sod_securitySod2_1(user1_manager,fnat(n9,0,0),fnat(n7,0,0)) + +DETAILS + STRONGLY_TYPED_MODEL + BOUNDED_NUMBER_OF_SESSIONS + BOUNDED_SEARCH_DEPTH + BOUNDED_MESSAGE_DEPTH + +BACKEND SATMC VERSION 3.3.1_(September_2011) + +STATISTICS TIME 2779 ms + upperBoundReached false boolean + graphLeveledOff no boolean + satSolver minisat solver + maxStepsNumber 80 steps + stepsNumber 16 steps + atomsNumber 6388 atoms + clausesNumber 22421 clauses + encodingTime 2.679 seconds + solvingTime 0.0 seconds + if2sateCompilationTime 0.1 seconds + +TRACE: +0 + CLAUSES:{ } + RULES: w_usertask1(fnat(n0,0,0)) +1 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: authorizeTaskExecution(user1_clerk,clerk,usertask1,fnat(n0,0,0)) +2 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: h_taskExecution(user1_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1) +3 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: w_servicetask1(fnat(n0,0,0),fnat(n1,0,0)) +4 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: atask_execution(servicetask1,fnat(n1,0,0),in_servicetask1,out_servicetask1) +5 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: w_usertask2(fnat(n1,0,0),fnat(n3,0,0)) +6 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: authorizeTaskExecution(user1_clerk,clerk,usertask2,fnat(n3,0,0)) +7 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: h_taskExecution(user1_clerk,clerk,usertask2,fnat(n3,0,0),in_usertask2,out_usertask2) +8 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: w_servicetask2(fnat(n3,0,0),fnat(n5,0,0)) +9 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: atask_execution(servicetask2,fnat(n5,0,0),in_servicetask2,out_servicetask2) +10 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: w_usertask3(fnat(n5,0,0),fnat(n7,0,0)) +11 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: authorizeTaskExecution(user1_manager,manager,usertask3,fnat(n7,0,0)) +12 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: h_taskExecution(user1_manager,manager,usertask3,fnat(n7,0,0),in_usertask3,out_usertask3) +13 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: w_usertask4(fnat(n7,0,0),fnat(n9,0,0)) +14 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: authorizeTaskExecution(user1_manager,manager,usertask4,fnat(n9,0,0)) +15 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } + RULES: h_taskExecution(user1_manager,manager,usertask4,fnat(n9,0,0),in_usertask4,out_usertask4) +16 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9) } +CLOSED_FINAL_STATE: +{ counter_w_servicetask1(s(0)),counter_w_servicetask2(s(0)),counter_w_servicetask3(0),counter_w_servicetask4(0),counter_w_servicetask5(0),counter_w_usertask1(s(0)),counter_w_usertask2(s(0)),counter_w_usertask3(s(0)),counter_w_usertask4(s(0)),counter_w_usertask5(0),counter_w_usertask6(0),counter_w_usertask7(0),counter_w_usertask8(0),counter_w_usertask9(0),done(task(usertask4,fnat(n9,0,0))),initial_state(init_1),aknows(user1_clerk,in_usertask1),aknows(user1_clerk,in_usertask2),aknows(user1_clerk,out_usertask1),aknows(user1_clerk,out_usertask2),aknows(user1_manager,in_usertask3),aknows(user1_manager,in_usertask4),aknows(user1_manager,out_usertask3),aknows(user1_manager,out_usertask4),executed(user1_clerk,task(usertask1,fnat(n0,0,0))),executed(user1_clerk,task(usertask2,fnat(n3,0,0))),executed(user1_manager,task(usertask3,fnat(n7,0,0))),executed(user1_manager,task(usertask4,fnat(n9,0,0))),poto(clerk,usertask1),poto(clerk,usertask2),poto(clerk,usertask5),poto(clerk,usertask7),poto(manager,usertask3),poto(manager,usertask4),poto(manager,usertask6),poto(supervisor,usertask8),poto(supervisor,usertask9),user_to_role(user1_clerk,clerk),user_to_role(user1_manager,manager),user_to_role(user1_supervisor,supervisor),user_to_role(user2_clerk,clerk),user_to_role(user2_manager,manager),user_to_role(user2_supervisor,supervisor),canExecute(user1_clerk,clerk,usertask1),canExecute(user1_clerk,clerk,usertask2),canExecute(user1_clerk,clerk,usertask5),canExecute(user1_clerk,clerk,usertask7),canExecute(user1_manager,manager,usertask3),canExecute(user1_manager,manager,usertask4),canExecute(user1_manager,manager,usertask6),canExecute(user1_supervisor,supervisor,usertask8),canExecute(user1_supervisor,supervisor,usertask9),canExecute(user2_clerk,clerk,usertask1),canExecute(user2_clerk,clerk,usertask2),canExecute(user2_clerk,clerk,usertask5),canExecute(user2_clerk,clerk,usertask7),canExecute(user2_manager,manager,usertask3),canExecute(user2_manager,manager,usertask4),canExecute(user2_manager,manager,usertask6),canExecute(user2_supervisor,supervisor,usertask8),canExecute(user2_supervisor,supervisor,usertask9),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask2),rbac_ac(user1_clerk,clerk,usertask5),rbac_ac(user1_clerk,clerk,usertask7),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user1_manager,manager,usertask4),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_supervisor,supervisor,usertask8),rbac_ac(user1_supervisor,supervisor,usertask9),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask2),rbac_ac(user2_clerk,clerk,usertask5),rbac_ac(user2_clerk,clerk,usertask7),rbac_ac(user2_manager,manager,usertask3),rbac_ac(user2_manager,manager,usertask4),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_supervisor,supervisor,usertask8),rbac_ac(user2_supervisor,supervisor,usertask9),sod_securitySod2_1(user1_manager,fnat(n9,0,0),fnat(n7,0,0)),task_to_data(servicetask1,in_servicetask1,out_servicetask1),task_to_data(servicetask2,in_servicetask2,out_servicetask2),task_to_data(servicetask3,in_servicetask3,out_servicetask3),task_to_data(servicetask4,in_servicetask4,out_servicetask4),task_to_data(servicetask5,in_servicetask5,out_servicetask5),task_to_data(usertask1,in_usertask1,out_usertask1),task_to_data(usertask2,in_usertask2,out_usertask2),task_to_data(usertask3,in_usertask3,out_usertask3),task_to_data(usertask4,in_usertask4,out_usertask4),task_to_data(usertask5,in_usertask5,out_usertask5),task_to_data(usertask6,in_usertask6,out_usertask6),task_to_data(usertask7,in_usertask7,out_usertask7),task_to_data(usertask8,in_usertask8,out_usertask8),task_to_data(usertask9,in_usertask9,out_usertask9) } diff --git a/examples/JobApplication/generated/JobApplication.sate b/examples/JobApplication/generated/JobApplication.sate new file mode 100644 index 0000000..d428a19 --- /dev/null +++ b/examples/JobApplication/generated/JobApplication.sate @@ -0,0 +1,727 @@ +% SATE OUTPUT + +% SORTS +sort(hc_axiom). +sort(action). +sort(fresh_const). +sort(fresh_nat). +sort(message). +sort(nat). +sort(set). +sort(set_typed). +sort(humanTaskName). +sort(humanTaskName_temp). +sort(humanTaskName_typed). +sort(role). +sort(role_temp). +sort(role_typed). +sort(automatedTaskName). +sort(automatedTaskName_temp). +sort(automatedTaskName_typed). +sort(user). +sort(user_temp). +sort(user_typed). +sort(data_typed). +sort(taskInstance_typed). +sort(fluent). +sort(userORrole). +sort(taskName). +sort(entity). +sort(data). + +% CONSTANTS +constant(initial_state(initial_state_id),fluent). +constant(fpk(fresh_public_key_id,nat,nat),fresh_public_key_typed). +constant(puk(fresh_public_key_typed),fresh_public_key). +constant(fsk(fresh_symmetric_key_id,nat,nat),fresh_symmetric_key_typed). +constant(sk(fresh_symmetric_key_typed),fresh_symmetric_key). +constant(fn(fresh_nonce_id,nat,nat),fresh_nonce_typed). +constant(nonce(fresh_nonce_typed),fresh_nonce). +constant(fmr(fresh_agent_id,nat,nat),fresh_agent_typed). +constant(mr(fresh_agent_typed),fresh_agent). +constant(ff(fresh_function_id,nat,nat),fresh_function_typed). +constant(fu(fresh_function_typed),fresh_function). +constant(fnat(fresh_nat_id,nat,nat),fresh_nat). +constant(fmsg(fresh_message_id,nat,nat),fresh_message). +constant(f_protocol_id_typed(fresh_protocol_id_typed_id,nat,nat),fresh_protocol_id_typed). +constant(pid(fresh_protocol_id_typed),fresh_protocol_id). +constant(fresh(fresh_const),fluent). +constant(s,nat). +constant(0,nat). +constant(mc_pair,data_typed). +constant(task,taskInstance_typed). +constant(parallelgateway1_to_usertask7,fluent). +constant(parallelgateway1_to_servicetask3,fluent). +constant(parallelgateway2_to_servicetask4,fluent). +constant(start_event_startevent2,fluent). +constant(usertask1,humanTaskName_typed). +constant(usertask2,humanTaskName_typed). +constant(usertask3,humanTaskName_typed). +constant(usertask4,humanTaskName_typed). +constant(usertask5,humanTaskName_typed). +constant(usertask6,humanTaskName_typed). +constant(usertask7,humanTaskName_typed). +constant(usertask8,humanTaskName_typed). +constant(usertask9,humanTaskName_typed). +constant(in_usertask1,set_typed). +constant(out_usertask1,set_typed). +constant(in_servicetask1,set_typed). +constant(out_servicetask1,set_typed). +constant(in_usertask2,set_typed). +constant(out_usertask2,set_typed). +constant(in_servicetask2,set_typed). +constant(out_servicetask2,set_typed). +constant(in_usertask3,set_typed). +constant(out_usertask3,set_typed). +constant(in_usertask4,set_typed). +constant(out_usertask4,set_typed). +constant(in_usertask5,set_typed). +constant(out_usertask5,set_typed). +constant(in_usertask6,set_typed). +constant(out_usertask6,set_typed). +constant(in_usertask7,set_typed). +constant(out_usertask7,set_typed). +constant(in_servicetask3,set_typed). +constant(out_servicetask3,set_typed). +constant(in_servicetask4,set_typed). +constant(out_servicetask4,set_typed). +constant(in_usertask8,set_typed). +constant(out_usertask8,set_typed). +constant(in_usertask9,set_typed). +constant(out_usertask9,set_typed). +constant(in_servicetask5,set_typed). +constant(out_servicetask5,set_typed). +constant(manager,role_typed). +constant(supervisor,role_typed). +constant(clerk,role_typed). +constant(servicetask1,automatedTaskName_typed). +constant(servicetask2,automatedTaskName_typed). +constant(servicetask3,automatedTaskName_typed). +constant(servicetask4,automatedTaskName_typed). +constant(servicetask5,automatedTaskName_typed). +constant(user1_manager,user_typed). +constant(user2_manager,user_typed). +constant(user1_supervisor,user_typed). +constant(user2_supervisor,user_typed). +constant(user1_clerk,user_typed). +constant(user2_clerk,user_typed). +constant(mr(agent_typed),agent). +constant(nonce(nonce_typed),nonce). +constant(sk(sk_typed),symmetric_key). +constant(puk(puk_typed),public_key). +constant(private_key_lb(private_key_typed),private_key). +constant(fu(function_typed),function). +constant(pid(protocol_id_typed),protocol_id). +constant(bool_lb(bool_typed),bool). +constant(set_lb(set_typed),set). +constant(ch(channel_typed),channel). +constant(s(nat),nat). +constant(contains(message,set),fluent). +constant(user_to_role(user,role),fluent). +constant(poto(userORrole,taskName),fluent). +constant(task_to_data(taskName,set,set),fluent). +constant(aknows(entity,data),fluent). +constant(mc_pair(data,data),data_typed). +constant(contains(set,data),fluent). +constant(task(taskName,nat),taskInstance_typed). +constant(canExecute(user,role,humanTaskName),fluent). +constant(granted(user,role,taskInstance),fluent). +constant(executed(user,taskInstance),fluent). +constant(ready(taskInstance),fluent). +constant(done(taskInstance),fluent). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(humanTaskName_lb(humanTaskName_typed),humanTaskName_temp). +constant(userORrole_lb(role_temp),role). +constant(userORrole_lb(role_temp),role). +constant(role_lb(role_typed),role_temp). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(automatedTaskName_lb(automatedTaskName_typed),automatedTaskName_temp). +constant(entity_lb(user_temp),user). +constant(entity_lb(user_temp),user). +constant(user_lb(user_typed),user_temp). +constant(init_1,initial_state_id). +constant(counter_w_usertask1(nat),fluent). +constant(counter_w_servicetask1(nat),fluent). +constant(counter_w_usertask2(nat),fluent). +constant(counter_w_servicetask2(nat),fluent). +constant(counter_w_usertask3(nat),fluent). +constant(counter_w_usertask4(nat),fluent). +constant(counter_w_usertask5(nat),fluent). +constant(counter_w_usertask6(nat),fluent). +constant(counter_w_usertask7(nat),fluent). +constant(counter_w_servicetask3(nat),fluent). +constant(counter_w_servicetask4(nat),fluent). +constant(counter_w_usertask8(nat),fluent). +constant(counter_w_usertask9(nat),fluent). +constant(counter_w_servicetask5(nat),fluent). +constant(n0,fresh_nat_id). +constant(n1,fresh_nat_id). +constant(n3,fresh_nat_id). +constant(n5,fresh_nat_id). +constant(n7,fresh_nat_id). +constant(n9,fresh_nat_id). +constant(n11,fresh_nat_id). +constant(n13,fresh_nat_id). +constant(n16,fresh_nat_id). +constant(n17,fresh_nat_id). +constant(n20,fresh_nat_id). +constant(n21,fresh_nat_id). +constant(n23,fresh_nat_id). +constant(n25,fresh_nat_id). + +% SUPERSORTS +super_sort(puk_typed,fresh_public_key_typed). +super_sort(fresh_const,fresh_public_key). +super_sort(sk_typed,fresh_symmetric_key_typed). +super_sort(fresh_const,fresh_symmetric_key). +super_sort(nonce_typed,fresh_nonce_typed). +super_sort(fresh_const,fresh_nonce). +super_sort(agent_typed,fresh_agent_typed). +super_sort(fresh_const,fresh_agent). +super_sort(function_typed,fresh_function_typed). +super_sort(fresh_const,fresh_function). +super_sort(nat,fresh_nat). +super_sort(fresh_const,fresh_nat). +super_sort(message,fresh_message). +super_sort(fresh_const,fresh_message). +super_sort(protocol_id_typed,fresh_protocol_id_typed). +super_sort(fresh_const,fresh_protocol_id). +super_sort(message,agent). +super_sort(message,nonce). +super_sort(message,symmetric_key). +super_sort(message,public_key). +super_sort(message,private_key). +super_sort(message,function). +super_sort(message,nat). +super_sort(message,protocol_id). +super_sort(message,bool). +super_sort(entity,organization). +super_sort(entity,user). +super_sort(data,object). +super_sort(data,set). +super_sort(userORrole,user). +super_sort(userORrole,role). +super_sort(taskName,automatedTaskName). +super_sort(taskName,humanTaskName). +super_sort(taskName_typed,humanTaskName_temp). +super_sort(userORrole_typed,role_temp). +super_sort(taskName_typed,automatedTaskName_temp). +super_sort(entity_typed,user_temp). + +% INITIAL STATES +facts([initial_state(init_1), + user_to_role(entity_lb(user_lb(user1_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user2_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user1_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user2_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user1_clerk)),userORrole_lb(role_lb(clerk))), + user_to_role(entity_lb(user_lb(user2_clerk)),userORrole_lb(role_lb(clerk))), + task_to_data(taskName_lb(humanTaskName_lb(usertask1)),set_lb(in_usertask1),set_lb(out_usertask1)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask1)),set_lb(in_servicetask1),set_lb(out_servicetask1)), + task_to_data(taskName_lb(humanTaskName_lb(usertask2)),set_lb(in_usertask2),set_lb(out_usertask2)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask2)),set_lb(in_servicetask2),set_lb(out_servicetask2)), + task_to_data(taskName_lb(humanTaskName_lb(usertask3)),set_lb(in_usertask3),set_lb(out_usertask3)), + task_to_data(taskName_lb(humanTaskName_lb(usertask4)),set_lb(in_usertask4),set_lb(out_usertask4)), + task_to_data(taskName_lb(humanTaskName_lb(usertask5)),set_lb(in_usertask5),set_lb(out_usertask5)), + task_to_data(taskName_lb(humanTaskName_lb(usertask6)),set_lb(in_usertask6),set_lb(out_usertask6)), + task_to_data(taskName_lb(humanTaskName_lb(usertask7)),set_lb(in_usertask7),set_lb(out_usertask7)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask3)),set_lb(in_servicetask3),set_lb(out_servicetask3)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask4)),set_lb(in_servicetask4),set_lb(out_servicetask4)), + task_to_data(taskName_lb(humanTaskName_lb(usertask8)),set_lb(in_usertask8),set_lb(out_usertask8)), + task_to_data(taskName_lb(humanTaskName_lb(usertask9)),set_lb(in_usertask9),set_lb(out_usertask9)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask5)),set_lb(in_servicetask5),set_lb(out_servicetask5)), + start_event_startevent2, + counter_w_usertask1(0), + counter_w_servicetask1(0), + counter_w_usertask2(0), + counter_w_servicetask2(0), + counter_w_usertask3(0), + counter_w_usertask4(0), + counter_w_usertask5(0), + counter_w_usertask6(0), + counter_w_usertask7(0), + counter_w_servicetask3(0), + counter_w_servicetask4(0), + counter_w_usertask8(0), + counter_w_usertask9(0), + counter_w_servicetask5(0)]). + + +% RULES +constant(sc_authorizeTaskExecution_1(user_typed,role_typed,humanTaskName_typed,nat),action). +action(sc_authorizeTaskExecution_1(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_h_taskExecution_1(user_typed,role_typed,humanTaskName_typed,nat,set_typed,set_typed),action). +action(sc_h_taskExecution_1(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_atask_execution_1(automatedTaskName_typed,nat,set_typed,set_typed),action). +action(sc_atask_execution_1(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +constant(sc_w_usertask1_1(nat),action). +action(sc_w_usertask1_1(Xvar), + true, + [start_event_startevent2, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent2, + counter_w_usertask1(Xvar)]). + +constant(sc_w_servicetask1_1(nat,nat),action). +action(sc_w_servicetask1_1(N2,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_servicetask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),fnat(n1,Xvar,0)))), + counter_w_servicetask1(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_servicetask1(Xvar)]). + +constant(sc_w_usertask2_1(nat,nat),action). +action(sc_w_usertask2_1(N4,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),N4))), + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n3,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),N4))), + counter_w_usertask2(Xvar)]). + +constant(sc_w_servicetask2_1(nat,nat),action). +action(sc_w_servicetask2_1(N6,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N6))), + counter_w_servicetask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),fnat(n5,Xvar,0)))), + counter_w_servicetask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N6))), + counter_w_servicetask2(Xvar)]). + +constant(sc_w_usertask3_1(nat,nat),action). +action(sc_w_usertask3_1(N8,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N8))), + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n7,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N8))), + counter_w_usertask3(Xvar)]). + +constant(sc_w_usertask4_1(nat,nat),action). +action(sc_w_usertask4_1(N10,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N10))), + counter_w_usertask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),fnat(n9,Xvar,0)))), + counter_w_usertask4(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N10))), + counter_w_usertask4(Xvar)]). + +constant(sc_w_usertask5_1(nat,nat),action). +action(sc_w_usertask5_1(N12,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N12))), + counter_w_usertask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),fnat(n11,Xvar,0)))), + counter_w_usertask5(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N12))), + counter_w_usertask5(Xvar)]). + +constant(sc_w_usertask6_1(nat,nat),action). +action(sc_w_usertask6_1(N14,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N14))), + counter_w_usertask6(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),fnat(n13,Xvar,0)))), + counter_w_usertask6(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N14))), + counter_w_usertask6(Xvar)]). + +constant(sc_w_parallelgateway1_1(nat),action). +action(sc_w_parallelgateway1_1(N15), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N15)))], + [parallelgateway1_to_usertask7, + parallelgateway1_to_servicetask3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N15)))]). + +constant(sc_w_usertask7_1(nat),action). +action(sc_w_usertask7_1(Xvar), + true, + [parallelgateway1_to_usertask7, + counter_w_usertask7(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),fnat(n16,Xvar,0)))), + counter_w_usertask7(s(Xvar))], + [parallelgateway1_to_usertask7, + counter_w_usertask7(Xvar)]). + +constant(sc_w_servicetask3_1(nat),action). +action(sc_w_servicetask3_1(Xvar), + true, + [parallelgateway1_to_servicetask3, + counter_w_servicetask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),fnat(n17,Xvar,0)))), + counter_w_servicetask3(s(Xvar))], + [parallelgateway1_to_servicetask3, + counter_w_servicetask3(Xvar)]). + +constant(sc_w_parallelgateway2_1(nat,nat),action). +action(sc_w_parallelgateway2_1(N18,N19), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N18))), + done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),N19)))], + [parallelgateway2_to_servicetask4], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N18))), + done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),N19)))]). + +constant(sc_w_servicetask4_1(nat),action). +action(sc_w_servicetask4_1(Xvar), + true, + [parallelgateway2_to_servicetask4, + counter_w_servicetask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),fnat(n20,Xvar,0)))), + counter_w_servicetask4(s(Xvar))], + [parallelgateway2_to_servicetask4, + counter_w_servicetask4(Xvar)]). + +constant(sc_w_usertask8_1(nat,nat),action). +action(sc_w_usertask8_1(N22,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),N22))), + counter_w_usertask8(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),fnat(n21,Xvar,0)))), + counter_w_usertask8(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),N22))), + counter_w_usertask8(Xvar)]). + +constant(sc_w_usertask9_1(nat,nat),action). +action(sc_w_usertask9_1(N24,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N24))), + counter_w_usertask9(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),fnat(n23,Xvar,0)))), + counter_w_usertask9(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N24))), + counter_w_usertask9(Xvar)]). + +constant(sc_w_servicetask5_1(nat,nat),action). +action(sc_w_servicetask5_1(N26,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N26))), + counter_w_servicetask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask5)),fnat(n25,Xvar,0)))), + counter_w_servicetask5(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N26))), + counter_w_servicetask5(Xvar)]). + + +% CONSTRAINTS + +% GOALS +goal(sod_securitySod1_1(U0,N27,N28),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N27))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N28)))]). + +goal(sod_securitySod2_1(U0,N29,N30),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N29))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N30)))]). + +goal(bod_securityBod1_1(U0,U1,N31,N32),on_the_fly_conditions([\+entity_lb(user_lb(U0))=entity_lb(user_lb(U1))]), + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N31))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N32)))]). + +goal(bod_securityBod1_2(U0,U1,N33,N34),on_the_fly_conditions([\+entity_lb(user_lb(U0))=entity_lb(user_lb(U1))]), + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N33))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N34)))]). + + +% EQUATIONS + +% USER_AXIOMS + +% HC_AXIOMS +constant(rbac_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(rbac_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(direct_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(direct_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(entity_lb(user_lb(A)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(poto_usertask1,hc_axiom). +hc_axiom(poto_usertask1, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask1)))]). + +constant(poto_usertask2,hc_axiom). +hc_axiom(poto_usertask2, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask2)))]). + +constant(poto_usertask3,hc_axiom). +hc_axiom(poto_usertask3, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask3)))]). + +constant(poto_usertask4,hc_axiom). +hc_axiom(poto_usertask4, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask4)))]). + +constant(poto_usertask5,hc_axiom). +hc_axiom(poto_usertask5, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask5)))]). + +constant(poto_usertask6,hc_axiom). +hc_axiom(poto_usertask6, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask6)))]). + +constant(poto_usertask7,hc_axiom). +hc_axiom(poto_usertask7, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask7)))]). + +constant(poto_usertask8,hc_axiom). +hc_axiom(poto_usertask8, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask8)))]). + +constant(poto_usertask9,hc_axiom). +hc_axiom(poto_usertask9, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask9)))]). + + + +% INVOKED DURING THE LOADING (USEFUL FOR SETTING) +init_sate :- + set(verification_abstraction,off), + set(if2sate_version,2). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% NOTE: these prolog facts are not mandatory and are useful only for +% printing a user-friendly output when the triple_step optimization +% is enabled. The user is invited to neglect these declarations. +triple_step_action(authorizeTaskExecution(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(h_taskExecution(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(atask_execution(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +triple_step_action(w_usertask1(Xvar), + true, + [start_event_startevent2, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent2, + counter_w_usertask1(Xvar)]). + +triple_step_action(w_servicetask1(N2,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_servicetask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),fnat(n1,Xvar,0)))), + counter_w_servicetask1(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_servicetask1(Xvar)]). + +triple_step_action(w_usertask2(N4,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),N4))), + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n3,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),N4))), + counter_w_usertask2(Xvar)]). + +triple_step_action(w_servicetask2(N6,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N6))), + counter_w_servicetask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),fnat(n5,Xvar,0)))), + counter_w_servicetask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N6))), + counter_w_servicetask2(Xvar)]). + +triple_step_action(w_usertask3(N8,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N8))), + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n7,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N8))), + counter_w_usertask3(Xvar)]). + +triple_step_action(w_usertask4(N10,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N10))), + counter_w_usertask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),fnat(n9,Xvar,0)))), + counter_w_usertask4(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N10))), + counter_w_usertask4(Xvar)]). + +triple_step_action(w_usertask5(N12,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N12))), + counter_w_usertask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),fnat(n11,Xvar,0)))), + counter_w_usertask5(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N12))), + counter_w_usertask5(Xvar)]). + +triple_step_action(w_usertask6(N14,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N14))), + counter_w_usertask6(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),fnat(n13,Xvar,0)))), + counter_w_usertask6(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N14))), + counter_w_usertask6(Xvar)]). + +triple_step_action(w_parallelgateway1(N15), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N15)))], + [parallelgateway1_to_usertask7, + parallelgateway1_to_servicetask3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N15)))]). + +triple_step_action(w_usertask7(Xvar), + true, + [parallelgateway1_to_usertask7, + counter_w_usertask7(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),fnat(n16,Xvar,0)))), + counter_w_usertask7(s(Xvar))], + [parallelgateway1_to_usertask7, + counter_w_usertask7(Xvar)]). + +triple_step_action(w_servicetask3(Xvar), + true, + [parallelgateway1_to_servicetask3, + counter_w_servicetask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),fnat(n17,Xvar,0)))), + counter_w_servicetask3(s(Xvar))], + [parallelgateway1_to_servicetask3, + counter_w_servicetask3(Xvar)]). + +triple_step_action(w_parallelgateway2(N18,N19), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N18))), + done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),N19)))], + [parallelgateway2_to_servicetask4], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N18))), + done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask3)),N19)))]). + +triple_step_action(w_servicetask4(Xvar), + true, + [parallelgateway2_to_servicetask4, + counter_w_servicetask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),fnat(n20,Xvar,0)))), + counter_w_servicetask4(s(Xvar))], + [parallelgateway2_to_servicetask4, + counter_w_servicetask4(Xvar)]). + +triple_step_action(w_usertask8(N22,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),N22))), + counter_w_usertask8(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),fnat(n21,Xvar,0)))), + counter_w_usertask8(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask4)),N22))), + counter_w_usertask8(Xvar)]). + +triple_step_action(w_usertask9(N24,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N24))), + counter_w_usertask9(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),fnat(n23,Xvar,0)))), + counter_w_usertask9(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N24))), + counter_w_usertask9(Xvar)]). + +triple_step_action(w_servicetask5(N26,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N26))), + counter_w_servicetask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask5)),fnat(n25,Xvar,0)))), + counter_w_servicetask5(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),N26))), + counter_w_servicetask5(Xvar)]). + +correspondence_between_action_and_step_compressed_rule(Act,SCAct) :- + atom_concat('sc_',Act,TmpAct), + atom_concat(TmpAct,_,SCAct). + +% PREDICATE TO EVALUATE ON_THE_FLY_CONDITIONS +on_the_fly_conditions([]). +on_the_fly_conditions([C|Cs]) :- + call(C), + on_the_fly_conditions(Cs). diff --git a/examples/LoanOrigination/CreditWorthinessService.java b/examples/LoanOrigination/CreditWorthinessService.java new file mode 100644 index 0000000..7d1845a --- /dev/null +++ b/examples/LoanOrigination/CreditWorthinessService.java @@ -0,0 +1,59 @@ +package service.impl; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.activiti.engine.delegate.JavaDelegate; +import org.activiti.engine.delegate.DelegateExecution; + +public class CreditWorthinessService implements JavaDelegate { + + @Override + public void execute(DelegateExecution execution) throws Exception { + + String country = (String) execution.getVariable("user_country"); + + if (country != null && country.equals("Germany")) { + // collect basic information + String lastname = (String) execution.getVariable("user_lastname"); + String firstname = (String) execution.getVariable("user_firstname"); + Date dateOfBirth = (Date) execution.getVariable("user_dateOfBirth"); + String locationOfBirth = (String) execution.getVariable("user_locationOfBirth"); + + // collect additional information + List addInfoList = new ArrayList(); + + addInfoList.add((String) execution.getVariable("user_address")); + + String birthname = (String) execution.getVariable("user_birthname"); + if (birthname != null && birthname.length() > 0) { + addInfoList.add(birthname); + } + + if ((Boolean) execution.getVariable("user_hasAccount")) { + addInfoList.add(((Long) execution.getVariable("user_currentAccountBalance")).toString()); + } + + // Schufa request + String result = executeSchufaRequest(lastname, firstname, dateOfBirth, locationOfBirth, (String[]) addInfoList.toArray()); + execution.createVariableLocal("externalWorthiness", ""); + execution.setVariable("externalWorthiness", result); + + } else { + // unsupported + notifyWrongCountry(country); + } + + } + + private String executeSchufaRequest(String lastname, String firstname, Date dateOfBirth, String locationOfBirth, String[] addInfo) { + // request Schufa information + return "SchufaInfo"; + } + + private void notifyWrongCountry(String country) { + // notify: wrong country provided + } + +} diff --git a/examples/LoanOrigination/LoanOrigination.activiti b/examples/LoanOrigination/LoanOrigination.activiti new file mode 100644 index 0000000..93b3c86 --- /dev/null +++ b/examples/LoanOrigination/LoanOrigination.activiti @@ -0,0 +1,1129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/LoanOrigination/LoanOrigination.png b/examples/LoanOrigination/LoanOrigination.png new file mode 100644 index 0000000000000000000000000000000000000000..495d8b5bf72f032b9ab67da0e16ad9eb81a664f7 GIT binary patch literal 67909 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 s*=Oilf%T*Bo%ORw%R2d2rjfM~8xa fact + poto : userORrole * taskName -> fact + task_to_data : taskName * set * set -> fact + aknows : entity * data -> fact + mc_pair : data * data -> data + contains : set * data -> fact + task : taskName * nat -> taskInstance + canExecute : user * role * humanTaskName -> fact + granted : user * role * taskInstance -> fact + executed : user * taskInstance -> fact + ready : taskInstance -> fact + done : taskInstance -> fact + entity > organization + entity > user + data > object + data > set + userORrole > user + userORrole > role + taskName > automatedTaskName + taskName > humanTaskName + +section types: + + start_event_startevent1,parallelgateway1_to_usertask3,parallelgateway1_to_servicetask2,parallelgateway4_to_usertask5,exclusivegateway1_to_usertask8,exclusivegateway1_to_exclusivegateway2,exclusivegateway2_to_usertask9,exclusivegateway3_to_parallelgateway1,exclusivegateway4_to_usertask7,exclusivegateway4_to_exclusivegateway3: fact + HT,usertask1,usertask2,usertask3,usertask4,usertask5,usertask6,usertask7,usertask8,usertask9: humanTaskName + IN,OUT,in_usertask1,out_usertask1,in_usertask2,out_usertask2,in_usertask3,out_usertask3,in_servicetask2,out_servicetask2,in_usertask4,out_usertask4,in_usertask5,out_usertask5,in_usertask6,out_usertask6,in_usertask7,out_usertask7,in_usertask8,out_usertask8,in_usertask9,out_usertask9: set + manager,supervisor,clerk,R: role + N,N0,N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12,N13,N14,N15,N16,N17,N18,N19,N20,N21,N22,N23,N24,N25,N26,N27,N28,N29,N30,N31,N32,N33,N34,N35,N36,N37,N38,N39,N40,N41,N42: nat + AT,servicetask2: automatedTaskName + user1_manager,user2_manager,user1_supervisor,user2_supervisor,user1_clerk,user2_clerk,A,U0,U1: user + +section inits: + + initial_state init_1 := + + user_to_role(user1_manager,manager). + user_to_role(user2_manager,manager). + user_to_role(user1_supervisor,supervisor). + user_to_role(user2_supervisor,supervisor). + user_to_role(user1_clerk,clerk). + user_to_role(user2_clerk,clerk). + start_event_startevent1. + task_to_data(usertask1,in_usertask1,out_usertask1). + task_to_data(usertask2,in_usertask2,out_usertask2). + task_to_data(usertask3,in_usertask3,out_usertask3). + task_to_data(servicetask2,in_servicetask2,out_servicetask2). + task_to_data(usertask4,in_usertask4,out_usertask4). + task_to_data(usertask5,in_usertask5,out_usertask5). + task_to_data(usertask6,in_usertask6,out_usertask6). + task_to_data(usertask7,in_usertask7,out_usertask7). + task_to_data(usertask8,in_usertask8,out_usertask8). + task_to_data(usertask9,in_usertask9,out_usertask9) + +section hornClauses: + + hc rbac_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(R,HT) + hc direct_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(A,HT) + hc poto_usertask1:= poto(clerk,usertask1) + hc poto_usertask2:= poto(supervisor,usertask2) + hc poto_usertask3:= poto(supervisor,usertask3) + hc poto_usertask4:= poto(supervisor,usertask4) + hc poto_usertask5:= poto(supervisor,usertask5) + hc poto_usertask6:= poto(manager,usertask6) + hc poto_usertask7:= poto(manager,usertask7) + hc poto_usertask8:= poto(clerk,usertask8) + hc poto_usertask9:= poto(clerk,usertask9) + +section rules: + + step authorizeTaskExecution(A,R,HT,N) := canExecute(A,R,HT). ready(task(HT,N)) => granted(A,R,task(HT,N)) + step h_taskExecution(A,R,HT,N,IN,OUT) := granted(A,R,task(HT,N)). task_to_data(HT,IN,OUT) => executed(A,task(HT,N)). done(task(HT,N)). task_to_data(HT,IN,OUT). aknows(A,IN). aknows(A,OUT) + step atask_execution(AT,N,IN,OUT) := ready(task(AT,N)). task_to_data(AT,IN,OUT) => done(task(AT,N)). task_to_data(AT,IN,OUT) + step w_usertask1(N0) := start_event_startevent1=[exists N0] => ready(task(usertask1,N0)) + step w_usertask2(N2,N1) := done(task(usertask1,N2))=[exists N1] => ready(task(usertask2,N1)) + step w_parallelgateway1 := exclusivegateway3_to_parallelgateway1 => parallelgateway1_to_usertask3. parallelgateway1_to_servicetask2 + step w_usertask3(N3) := parallelgateway1_to_usertask3=[exists N3] => ready(task(usertask3,N3)) + step w_servicetask2(N4) := parallelgateway1_to_servicetask2=[exists N4] => ready(task(servicetask2,N4)) + step w_usertask4(N6,N5) := done(task(servicetask2,N6))=[exists N5] => ready(task(usertask4,N5)) + step w_parallelgateway4(N7,N8) := done(task(usertask3,N7)). done(task(usertask4,N8)) => parallelgateway4_to_usertask5 + step w_usertask5(N9) := parallelgateway4_to_usertask5=[exists N9] => ready(task(usertask5,N9)) + step w_usertask6(N11,N10) := done(task(usertask5,N11))=[exists N10] => ready(task(usertask6,N10)) + step w_usertask7(N12) := exclusivegateway4_to_usertask7=[exists N12] => ready(task(usertask7,N12)) + step exclusivegateway1_branch1(N13) := done(task(usertask7,N13)) => exclusivegateway1_to_usertask8 + step exclusivegateway1_branch2(N13) := done(task(usertask7,N13)) => exclusivegateway1_to_exclusivegateway2 + step w_usertask8(N14) := exclusivegateway1_to_usertask8=[exists N14] => ready(task(usertask8,N14)) + step exclusivegateway2_branch1(N15) := done(task(usertask8,N15)) => exclusivegateway2_to_usertask9 + step exclusivegateway2_branch2 := exclusivegateway1_to_exclusivegateway2 => exclusivegateway2_to_usertask9 + step w_usertask9(N16) := exclusivegateway2_to_usertask9=[exists N16] => ready(task(usertask9,N16)) + step exclusivegateway3_branch1(N41) := done(task(usertask2,N41)) => exclusivegateway3_to_parallelgateway1 + step exclusivegateway3_branch2 := exclusivegateway4_to_exclusivegateway3 => exclusivegateway3_to_parallelgateway1 + step exclusivegateway4_branch1(N42) := done(task(usertask6,N42)) => exclusivegateway4_to_usertask7 + step exclusivegateway4_branch2(N42) := done(task(usertask6,N42)) => exclusivegateway4_to_exclusivegateway3 + +section goals: + + attack_state sod_securitySod1_1(U0,N17,N18,N19):= executed(U0,task(usertask5,N17)). executed(U0,task(usertask6,N18)). executed(U0,task(usertask7,N19)) + attack_state sod_securitySod1_2(U0,U1,N20,N21,N22):= executed(U0,task(usertask6,N20)). executed(U0,task(usertask7,N21)). executed(U1,task(usertask5,N22)) + attack_state sod_securitySod1_3(U0,U1,N23,N24,N25):= executed(U0,task(usertask5,N23)). executed(U0,task(usertask6,N24)). executed(U1,task(usertask7,N25)) + attack_state sod_securitySod1_4(U0,U1,N26,N27,N28):= executed(U0,task(usertask5,N26)). executed(U0,task(usertask7,N27)). executed(U1,task(usertask6,N28)) + attack_state sod_securitySod2_1(U0,N29,N30,N31):= executed(U0,task(usertask4,N29)). executed(U0,task(usertask5,N30)). executed(U0,task(usertask3,N31)) + attack_state sod_securitySod2_2(U0,U1,N32,N33,N34):= executed(U0,task(usertask4,N32)). executed(U0,task(usertask3,N33)). executed(U1,task(usertask5,N34)) + attack_state sod_securitySod2_3(U0,U1,N35,N36,N37):= executed(U0,task(usertask4,N35)). executed(U0,task(usertask5,N36)). executed(U1,task(usertask3,N37)) + attack_state sod_securitySod2_4(U0,U1,N38,N39,N40):= executed(U0,task(usertask5,N38)). executed(U0,task(usertask3,N39)). executed(U1,task(usertask4,N40)) diff --git a/examples/LoanOrigination/generated/LoanOrigination.res b/examples/LoanOrigination/generated/LoanOrigination.res new file mode 100644 index 0000000..407d756 --- /dev/null +++ b/examples/LoanOrigination/generated/LoanOrigination.res @@ -0,0 +1,476 @@ +% PARAMETERS: + + Protocol: LoanOrigination + Problem category: if + + Compound types: on + Step compression: on + Intruder Knowledge As Axioms: off + Weak Type-Flaws (iff newgp): off + + Technique: Graphplan-based Encoding using the EFA schema + Min Steps: 0 + Max Steps: 80 + Delta Steps: 1 + Level Mutex: 0 + Solver: minisat + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% SATE file generated in 0.1 sec... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: INIT + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Initial Facts: 55 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 1 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 0 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 2 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 1 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 3 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 2 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 4 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 3 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 5 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 4 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 6 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 5 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 7 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 6 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 8 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 7 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 9 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 8 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 10 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 9 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 11 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 10 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 12 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 11 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 13 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 12 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 14 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 13 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 15 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 14 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 16 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 15 no 0.04 + ------ + Total: 0.04 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.02 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 17 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 16 no 0.06 + ------ + Total: 0.06 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.14 + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Goals: 1961 0.2 + Refinement Schema: 0 0.0 + Horn Clauses Axioms: 1836 0.14 + User Axioms: 0 0.0 + Ape Schema: 15260 0.92 + Explanatory Frame Schema: 6208 0.98 + ------ + Total: 2.24 + +* SUB-PHASE: Solver SAT formula Updated + + STATISTICS + Depth: 17 + Atoms: 7425 + Clauses: 25320 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 18 + +* SUB-PHASE: Search for SAT models.. + + Found 1 models in 0.0 sec. + +* SUB-PHASE: Models into Partial Order Plans (POPs) + + STATISTICS RUNTIME(sec) + model2pop 1 3.68 + ------ + Total: 3.68 + +* SUB-PHASE: Partial Order Plans (POPs) validations + + STATISTICS VALID RUNTIME(sec) + POP 1: true 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Partial Order Plans (POPs) printing + + -------------------------------------------------------------------- + pop 1: + + GOALS: [sod_securitySod2_2(user2_supervisor,user1_supervisor,fnat(n5,0,0),fnat(n3,0,0),fnat(n9,0,0))] + + Step 0: [sc_w_usertask1_1(0)] + Step 1: [sc_authorizeTaskExecution_1(user2_clerk,clerk,usertask1,fnat(n0,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 2: [sc_h_taskExecution_1(user2_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 3: [sc_w_usertask2_1(fnat(n0,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 4: [sc_authorizeTaskExecution_1(user1_supervisor,supervisor,usertask2,fnat(n1,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 5: [sc_h_taskExecution_1(user1_supervisor,supervisor,usertask2,fnat(n1,0,0),in_usertask2,out_usertask2),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 6: [sc_exclusivegateway3_branch1_1(fnat(n1,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 7: [sc_w_parallelgateway1_1,rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 8: [sc_w_servicetask2_1(0),sc_w_usertask3_1(0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 9: [sc_atask_execution_1(servicetask2,fnat(n4,0,0),in_servicetask2,out_servicetask2),sc_authorizeTaskExecution_1(user2_supervisor,supervisor,usertask3,fnat(n3,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 10: [sc_w_usertask4_1(fnat(n4,0,0),0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 11: [sc_authorizeTaskExecution_1(user2_supervisor,supervisor,usertask4,fnat(n5,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 12: [sc_h_taskExecution_1(user2_supervisor,supervisor,usertask3,fnat(n3,0,0),in_usertask3,out_usertask3),sc_h_taskExecution_1(user2_supervisor,supervisor,usertask4,fnat(n5,0,0),in_usertask4,out_usertask4),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 13: [sc_w_parallelgateway4_1(fnat(n3,0,0),fnat(n5,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 14: [sc_w_usertask5_1(0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 15: [sc_authorizeTaskExecution_1(user1_supervisor,supervisor,usertask5,fnat(n9,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 16: [sc_h_taskExecution_1(user1_supervisor,supervisor,usertask5,fnat(n9,0,0),in_usertask5,out_usertask5),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + Step 17: [rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5)] + -------------------------------------------------------------------- + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +RESULTS + +Attacks Found: true +Stop Condition Reached: false +Formula statistics: + Graph Construction Time: 0.4 + Graph Leveled Off: no + Graph2SAT Time (sec): 2.26 + Encoding Time (sec): 2.659 + Depth: 17 + Atoms: 7425 + Clauses: 25320 +Solving statistics: + Total Solving Time (sec): 0.0 + Last Solving Time (sec): 0.0 +Abstraction/Refinement statistics: + Validation Time (sec): 0.0 + Models into POPs Time (sec): 3.68 + Refinement iterations: 0 + +Total Time: 6.339 + + diff --git a/examples/LoanOrigination/generated/LoanOrigination.result b/examples/LoanOrigination/generated/LoanOrigination.result new file mode 100644 index 0000000..eea6584 --- /dev/null +++ b/examples/LoanOrigination/generated/LoanOrigination.result @@ -0,0 +1,80 @@ +INPUT LoanOrigination.aslan +SUMMARY ATTACK_FOUND + GOAL: sod_securitySod2_2(user2_supervisor,user1_supervisor,fnat(n5,0,0),fnat(n3,0,0),fnat(n9,0,0)) + +DETAILS + STRONGLY_TYPED_MODEL + BOUNDED_NUMBER_OF_SESSIONS + BOUNDED_SEARCH_DEPTH + BOUNDED_MESSAGE_DEPTH + +BACKEND SATMC VERSION 3.3.1_(September_2011) + +STATISTICS TIME 2759 ms + upperBoundReached false boolean + graphLeveledOff no boolean + satSolver minisat solver + maxStepsNumber 80 steps + stepsNumber 17 steps + atomsNumber 7425 atoms + clausesNumber 25320 clauses + encodingTime 2.659 seconds + solvingTime 0.0 seconds + if2sateCompilationTime 0.1 seconds + +TRACE: +0 + CLAUSES:{ } + RULES: w_usertask1(fnat(n0,0,0)) +1 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: authorizeTaskExecution(user2_clerk,clerk,usertask1,fnat(n0,0,0)) +2 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: h_taskExecution(user2_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1) +3 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: w_usertask2(fnat(n0,0,0),fnat(n1,0,0)) +4 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: authorizeTaskExecution(user1_supervisor,supervisor,usertask2,fnat(n1,0,0)) +5 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: h_taskExecution(user1_supervisor,supervisor,usertask2,fnat(n1,0,0),in_usertask2,out_usertask2) +6 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: exclusivegateway3_branch1(fnat(n1,0,0)) +7 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: w_parallelgateway1 +8 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: { w_servicetask2(fnat(n4,0,0)),w_usertask3(fnat(n3,0,0)) } +9 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: { atask_execution(servicetask2,fnat(n4,0,0),in_servicetask2,out_servicetask2),authorizeTaskExecution(user2_supervisor,supervisor,usertask3,fnat(n3,0,0)) } +10 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: w_usertask4(fnat(n4,0,0),fnat(n5,0,0)) +11 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: authorizeTaskExecution(user2_supervisor,supervisor,usertask4,fnat(n5,0,0)) +12 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: { h_taskExecution(user2_supervisor,supervisor,usertask3,fnat(n3,0,0),in_usertask3,out_usertask3),h_taskExecution(user2_supervisor,supervisor,usertask4,fnat(n5,0,0),in_usertask4,out_usertask4) } +13 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: w_parallelgateway4(fnat(n3,0,0),fnat(n5,0,0)) +14 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: w_usertask5(fnat(n9,0,0)) +15 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: authorizeTaskExecution(user1_supervisor,supervisor,usertask5,fnat(n9,0,0)) +16 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } + RULES: h_taskExecution(user1_supervisor,supervisor,usertask5,fnat(n9,0,0),in_usertask5,out_usertask5) +17 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5) } +CLOSED_FINAL_STATE: +{ counter_w_servicetask2(s(0)),counter_w_usertask1(s(0)),counter_w_usertask2(s(0)),counter_w_usertask3(s(0)),counter_w_usertask4(s(0)),counter_w_usertask5(s(0)),counter_w_usertask6(0),counter_w_usertask7(0),counter_w_usertask8(0),counter_w_usertask9(0),done(task(usertask5,fnat(n9,0,0))),initial_state(init_1),aknows(user1_supervisor,in_usertask2),aknows(user1_supervisor,in_usertask5),aknows(user1_supervisor,out_usertask2),aknows(user1_supervisor,out_usertask5),aknows(user2_clerk,in_usertask1),aknows(user2_clerk,out_usertask1),aknows(user2_supervisor,in_usertask3),aknows(user2_supervisor,in_usertask4),aknows(user2_supervisor,out_usertask3),aknows(user2_supervisor,out_usertask4),executed(user1_supervisor,task(usertask2,fnat(n1,0,0))),executed(user1_supervisor,task(usertask5,fnat(n9,0,0))),executed(user2_clerk,task(usertask1,fnat(n0,0,0))),executed(user2_supervisor,task(usertask3,fnat(n3,0,0))),executed(user2_supervisor,task(usertask4,fnat(n5,0,0))),poto(clerk,usertask1),poto(clerk,usertask8),poto(clerk,usertask9),poto(manager,usertask6),poto(manager,usertask7),poto(supervisor,usertask2),poto(supervisor,usertask3),poto(supervisor,usertask4),poto(supervisor,usertask5),user_to_role(user1_clerk,clerk),user_to_role(user1_manager,manager),user_to_role(user1_supervisor,supervisor),user_to_role(user2_clerk,clerk),user_to_role(user2_manager,manager),user_to_role(user2_supervisor,supervisor),canExecute(user1_clerk,clerk,usertask1),canExecute(user1_clerk,clerk,usertask8),canExecute(user1_clerk,clerk,usertask9),canExecute(user1_manager,manager,usertask6),canExecute(user1_manager,manager,usertask7),canExecute(user1_supervisor,supervisor,usertask2),canExecute(user1_supervisor,supervisor,usertask3),canExecute(user1_supervisor,supervisor,usertask4),canExecute(user1_supervisor,supervisor,usertask5),canExecute(user2_clerk,clerk,usertask1),canExecute(user2_clerk,clerk,usertask8),canExecute(user2_clerk,clerk,usertask9),canExecute(user2_manager,manager,usertask6),canExecute(user2_manager,manager,usertask7),canExecute(user2_supervisor,supervisor,usertask2),canExecute(user2_supervisor,supervisor,usertask3),canExecute(user2_supervisor,supervisor,usertask4),canExecute(user2_supervisor,supervisor,usertask5),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_clerk,clerk,usertask8),rbac_ac(user1_clerk,clerk,usertask9),rbac_ac(user1_manager,manager,usertask6),rbac_ac(user1_manager,manager,usertask7),rbac_ac(user1_supervisor,supervisor,usertask2),rbac_ac(user1_supervisor,supervisor,usertask3),rbac_ac(user1_supervisor,supervisor,usertask4),rbac_ac(user1_supervisor,supervisor,usertask5),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_clerk,clerk,usertask8),rbac_ac(user2_clerk,clerk,usertask9),rbac_ac(user2_manager,manager,usertask6),rbac_ac(user2_manager,manager,usertask7),rbac_ac(user2_supervisor,supervisor,usertask2),rbac_ac(user2_supervisor,supervisor,usertask3),rbac_ac(user2_supervisor,supervisor,usertask4),rbac_ac(user2_supervisor,supervisor,usertask5),task_to_data(servicetask2,in_servicetask2,out_servicetask2),task_to_data(usertask1,in_usertask1,out_usertask1),task_to_data(usertask2,in_usertask2,out_usertask2),task_to_data(usertask3,in_usertask3,out_usertask3),task_to_data(usertask4,in_usertask4,out_usertask4),task_to_data(usertask5,in_usertask5,out_usertask5),task_to_data(usertask6,in_usertask6,out_usertask6),task_to_data(usertask7,in_usertask7,out_usertask7),task_to_data(usertask8,in_usertask8,out_usertask8),task_to_data(usertask9,in_usertask9,out_usertask9),sod_securitySod2_2(user2_supervisor,user1_supervisor,fnat(n5,0,0),fnat(n3,0,0),fnat(n9,0,0)) } diff --git a/examples/LoanOrigination/generated/LoanOrigination.sate b/examples/LoanOrigination/generated/LoanOrigination.sate new file mode 100644 index 0000000..2e8db8b --- /dev/null +++ b/examples/LoanOrigination/generated/LoanOrigination.sate @@ -0,0 +1,757 @@ +% SATE OUTPUT + +% SORTS +sort(hc_axiom). +sort(action). +sort(fresh_const). +sort(fresh_nat). +sort(message). +sort(nat). +sort(set). +sort(set_typed). +sort(humanTaskName). +sort(humanTaskName_temp). +sort(humanTaskName_typed). +sort(role). +sort(role_temp). +sort(role_typed). +sort(automatedTaskName). +sort(automatedTaskName_temp). +sort(automatedTaskName_typed). +sort(user). +sort(user_temp). +sort(user_typed). +sort(data_typed). +sort(taskInstance_typed). +sort(fluent). +sort(userORrole). +sort(taskName). +sort(entity). +sort(data). + +% CONSTANTS +constant(initial_state(initial_state_id),fluent). +constant(fpk(fresh_public_key_id,nat,nat),fresh_public_key_typed). +constant(puk(fresh_public_key_typed),fresh_public_key). +constant(fsk(fresh_symmetric_key_id,nat,nat),fresh_symmetric_key_typed). +constant(sk(fresh_symmetric_key_typed),fresh_symmetric_key). +constant(fn(fresh_nonce_id,nat,nat),fresh_nonce_typed). +constant(nonce(fresh_nonce_typed),fresh_nonce). +constant(fmr(fresh_agent_id,nat,nat),fresh_agent_typed). +constant(mr(fresh_agent_typed),fresh_agent). +constant(ff(fresh_function_id,nat,nat),fresh_function_typed). +constant(fu(fresh_function_typed),fresh_function). +constant(fnat(fresh_nat_id,nat,nat),fresh_nat). +constant(fmsg(fresh_message_id,nat,nat),fresh_message). +constant(f_protocol_id_typed(fresh_protocol_id_typed_id,nat,nat),fresh_protocol_id_typed). +constant(pid(fresh_protocol_id_typed),fresh_protocol_id). +constant(fresh(fresh_const),fluent). +constant(s,nat). +constant(0,nat). +constant(mc_pair,data_typed). +constant(task,taskInstance_typed). +constant(start_event_startevent1,fluent). +constant(parallelgateway1_to_usertask3,fluent). +constant(parallelgateway1_to_servicetask2,fluent). +constant(parallelgateway4_to_usertask5,fluent). +constant(exclusivegateway1_to_usertask8,fluent). +constant(exclusivegateway1_to_exclusivegateway2,fluent). +constant(exclusivegateway2_to_usertask9,fluent). +constant(exclusivegateway3_to_parallelgateway1,fluent). +constant(exclusivegateway4_to_usertask7,fluent). +constant(exclusivegateway4_to_exclusivegateway3,fluent). +constant(usertask1,humanTaskName_typed). +constant(usertask2,humanTaskName_typed). +constant(usertask3,humanTaskName_typed). +constant(usertask4,humanTaskName_typed). +constant(usertask5,humanTaskName_typed). +constant(usertask6,humanTaskName_typed). +constant(usertask7,humanTaskName_typed). +constant(usertask8,humanTaskName_typed). +constant(usertask9,humanTaskName_typed). +constant(in_usertask1,set_typed). +constant(out_usertask1,set_typed). +constant(in_usertask2,set_typed). +constant(out_usertask2,set_typed). +constant(in_usertask3,set_typed). +constant(out_usertask3,set_typed). +constant(in_servicetask2,set_typed). +constant(out_servicetask2,set_typed). +constant(in_usertask4,set_typed). +constant(out_usertask4,set_typed). +constant(in_usertask5,set_typed). +constant(out_usertask5,set_typed). +constant(in_usertask6,set_typed). +constant(out_usertask6,set_typed). +constant(in_usertask7,set_typed). +constant(out_usertask7,set_typed). +constant(in_usertask8,set_typed). +constant(out_usertask8,set_typed). +constant(in_usertask9,set_typed). +constant(out_usertask9,set_typed). +constant(manager,role_typed). +constant(supervisor,role_typed). +constant(clerk,role_typed). +constant(servicetask2,automatedTaskName_typed). +constant(user1_manager,user_typed). +constant(user2_manager,user_typed). +constant(user1_supervisor,user_typed). +constant(user2_supervisor,user_typed). +constant(user1_clerk,user_typed). +constant(user2_clerk,user_typed). +constant(mr(agent_typed),agent). +constant(nonce(nonce_typed),nonce). +constant(sk(sk_typed),symmetric_key). +constant(puk(puk_typed),public_key). +constant(private_key_lb(private_key_typed),private_key). +constant(fu(function_typed),function). +constant(pid(protocol_id_typed),protocol_id). +constant(bool_lb(bool_typed),bool). +constant(set_lb(set_typed),set). +constant(ch(channel_typed),channel). +constant(s(nat),nat). +constant(contains(message,set),fluent). +constant(user_to_role(user,role),fluent). +constant(poto(userORrole,taskName),fluent). +constant(task_to_data(taskName,set,set),fluent). +constant(aknows(entity,data),fluent). +constant(mc_pair(data,data),data_typed). +constant(contains(set,data),fluent). +constant(task(taskName,nat),taskInstance_typed). +constant(canExecute(user,role,humanTaskName),fluent). +constant(granted(user,role,taskInstance),fluent). +constant(executed(user,taskInstance),fluent). +constant(ready(taskInstance),fluent). +constant(done(taskInstance),fluent). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(humanTaskName_lb(humanTaskName_typed),humanTaskName_temp). +constant(userORrole_lb(role_temp),role). +constant(userORrole_lb(role_temp),role). +constant(role_lb(role_typed),role_temp). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(automatedTaskName_lb(automatedTaskName_typed),automatedTaskName_temp). +constant(entity_lb(user_temp),user). +constant(entity_lb(user_temp),user). +constant(user_lb(user_typed),user_temp). +constant(init_1,initial_state_id). +constant(counter_w_usertask1(nat),fluent). +constant(counter_w_usertask2(nat),fluent). +constant(counter_w_usertask3(nat),fluent). +constant(counter_w_servicetask2(nat),fluent). +constant(counter_w_usertask4(nat),fluent). +constant(counter_w_usertask5(nat),fluent). +constant(counter_w_usertask6(nat),fluent). +constant(counter_w_usertask7(nat),fluent). +constant(counter_w_usertask8(nat),fluent). +constant(counter_w_usertask9(nat),fluent). +constant(n0,fresh_nat_id). +constant(n1,fresh_nat_id). +constant(n3,fresh_nat_id). +constant(n4,fresh_nat_id). +constant(n5,fresh_nat_id). +constant(n9,fresh_nat_id). +constant(n10,fresh_nat_id). +constant(n12,fresh_nat_id). +constant(n14,fresh_nat_id). +constant(n16,fresh_nat_id). + +% SUPERSORTS +super_sort(puk_typed,fresh_public_key_typed). +super_sort(fresh_const,fresh_public_key). +super_sort(sk_typed,fresh_symmetric_key_typed). +super_sort(fresh_const,fresh_symmetric_key). +super_sort(nonce_typed,fresh_nonce_typed). +super_sort(fresh_const,fresh_nonce). +super_sort(agent_typed,fresh_agent_typed). +super_sort(fresh_const,fresh_agent). +super_sort(function_typed,fresh_function_typed). +super_sort(fresh_const,fresh_function). +super_sort(nat,fresh_nat). +super_sort(fresh_const,fresh_nat). +super_sort(message,fresh_message). +super_sort(fresh_const,fresh_message). +super_sort(protocol_id_typed,fresh_protocol_id_typed). +super_sort(fresh_const,fresh_protocol_id). +super_sort(message,agent). +super_sort(message,nonce). +super_sort(message,symmetric_key). +super_sort(message,public_key). +super_sort(message,private_key). +super_sort(message,function). +super_sort(message,nat). +super_sort(message,protocol_id). +super_sort(message,bool). +super_sort(entity,organization). +super_sort(entity,user). +super_sort(data,object). +super_sort(data,set). +super_sort(userORrole,user). +super_sort(userORrole,role). +super_sort(taskName,automatedTaskName). +super_sort(taskName,humanTaskName). +super_sort(taskName_typed,humanTaskName_temp). +super_sort(userORrole_typed,role_temp). +super_sort(taskName_typed,automatedTaskName_temp). +super_sort(entity_typed,user_temp). + +% INITIAL STATES +facts([initial_state(init_1), + user_to_role(entity_lb(user_lb(user1_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user2_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user1_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user2_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user1_clerk)),userORrole_lb(role_lb(clerk))), + user_to_role(entity_lb(user_lb(user2_clerk)),userORrole_lb(role_lb(clerk))), + start_event_startevent1, + task_to_data(taskName_lb(humanTaskName_lb(usertask1)),set_lb(in_usertask1),set_lb(out_usertask1)), + task_to_data(taskName_lb(humanTaskName_lb(usertask2)),set_lb(in_usertask2),set_lb(out_usertask2)), + task_to_data(taskName_lb(humanTaskName_lb(usertask3)),set_lb(in_usertask3),set_lb(out_usertask3)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask2)),set_lb(in_servicetask2),set_lb(out_servicetask2)), + task_to_data(taskName_lb(humanTaskName_lb(usertask4)),set_lb(in_usertask4),set_lb(out_usertask4)), + task_to_data(taskName_lb(humanTaskName_lb(usertask5)),set_lb(in_usertask5),set_lb(out_usertask5)), + task_to_data(taskName_lb(humanTaskName_lb(usertask6)),set_lb(in_usertask6),set_lb(out_usertask6)), + task_to_data(taskName_lb(humanTaskName_lb(usertask7)),set_lb(in_usertask7),set_lb(out_usertask7)), + task_to_data(taskName_lb(humanTaskName_lb(usertask8)),set_lb(in_usertask8),set_lb(out_usertask8)), + task_to_data(taskName_lb(humanTaskName_lb(usertask9)),set_lb(in_usertask9),set_lb(out_usertask9)), + counter_w_usertask1(0), + counter_w_usertask2(0), + counter_w_usertask3(0), + counter_w_servicetask2(0), + counter_w_usertask4(0), + counter_w_usertask5(0), + counter_w_usertask6(0), + counter_w_usertask7(0), + counter_w_usertask8(0), + counter_w_usertask9(0)]). + + +% RULES +constant(sc_authorizeTaskExecution_1(user_typed,role_typed,humanTaskName_typed,nat),action). +action(sc_authorizeTaskExecution_1(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_h_taskExecution_1(user_typed,role_typed,humanTaskName_typed,nat,set_typed,set_typed),action). +action(sc_h_taskExecution_1(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_atask_execution_1(automatedTaskName_typed,nat,set_typed,set_typed),action). +action(sc_atask_execution_1(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +constant(sc_w_usertask1_1(nat),action). +action(sc_w_usertask1_1(Xvar), + true, + [start_event_startevent1, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent1, + counter_w_usertask1(Xvar)]). + +constant(sc_w_usertask2_1(nat,nat),action). +action(sc_w_usertask2_1(N2,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n1,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_usertask2(Xvar)]). + +constant(sc_w_parallelgateway1_1,action). +action(sc_w_parallelgateway1_1, + true, + [exclusivegateway3_to_parallelgateway1], + [parallelgateway1_to_usertask3, + parallelgateway1_to_servicetask2], + [exclusivegateway3_to_parallelgateway1]). + +constant(sc_w_usertask3_1(nat),action). +action(sc_w_usertask3_1(Xvar), + true, + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n3,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)]). + +constant(sc_w_servicetask2_1(nat),action). +action(sc_w_servicetask2_1(Xvar), + true, + [parallelgateway1_to_servicetask2, + counter_w_servicetask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),fnat(n4,Xvar,0)))), + counter_w_servicetask2(s(Xvar))], + [parallelgateway1_to_servicetask2, + counter_w_servicetask2(Xvar)]). + +constant(sc_w_usertask4_1(nat,nat),action). +action(sc_w_usertask4_1(N6,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N6))), + counter_w_usertask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),fnat(n5,Xvar,0)))), + counter_w_usertask4(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N6))), + counter_w_usertask4(Xvar)]). + +constant(sc_w_parallelgateway4_1(nat,nat),action). +action(sc_w_parallelgateway4_1(N7,N8), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N7))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N8)))], + [parallelgateway4_to_usertask5], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N7))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N8)))]). + +constant(sc_w_usertask5_1(nat),action). +action(sc_w_usertask5_1(Xvar), + true, + [parallelgateway4_to_usertask5, + counter_w_usertask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),fnat(n9,Xvar,0)))), + counter_w_usertask5(s(Xvar))], + [parallelgateway4_to_usertask5, + counter_w_usertask5(Xvar)]). + +constant(sc_w_usertask6_1(nat,nat),action). +action(sc_w_usertask6_1(N11,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N11))), + counter_w_usertask6(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),fnat(n10,Xvar,0)))), + counter_w_usertask6(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N11))), + counter_w_usertask6(Xvar)]). + +constant(sc_w_usertask7_1(nat),action). +action(sc_w_usertask7_1(Xvar), + true, + [exclusivegateway4_to_usertask7, + counter_w_usertask7(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),fnat(n12,Xvar,0)))), + counter_w_usertask7(s(Xvar))], + [exclusivegateway4_to_usertask7, + counter_w_usertask7(Xvar)]). + +constant(sc_exclusivegateway1_branch1_1(nat),action). +action(sc_exclusivegateway1_branch1_1(N13), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))], + [exclusivegateway1_to_usertask8], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))]). + +constant(sc_exclusivegateway1_branch2_1(nat),action). +action(sc_exclusivegateway1_branch2_1(N13), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))], + [exclusivegateway1_to_exclusivegateway2], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))]). + +constant(sc_w_usertask8_1(nat),action). +action(sc_w_usertask8_1(Xvar), + true, + [exclusivegateway1_to_usertask8, + counter_w_usertask8(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),fnat(n14,Xvar,0)))), + counter_w_usertask8(s(Xvar))], + [exclusivegateway1_to_usertask8, + counter_w_usertask8(Xvar)]). + +constant(sc_exclusivegateway2_branch1_1(nat),action). +action(sc_exclusivegateway2_branch1_1(N15), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N15)))], + [exclusivegateway2_to_usertask9], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N15)))]). + +constant(sc_exclusivegateway2_branch2_1,action). +action(sc_exclusivegateway2_branch2_1, + true, + [exclusivegateway1_to_exclusivegateway2], + [exclusivegateway2_to_usertask9], + [exclusivegateway1_to_exclusivegateway2]). + +constant(sc_w_usertask9_1(nat),action). +action(sc_w_usertask9_1(Xvar), + true, + [exclusivegateway2_to_usertask9, + counter_w_usertask9(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),fnat(n16,Xvar,0)))), + counter_w_usertask9(s(Xvar))], + [exclusivegateway2_to_usertask9, + counter_w_usertask9(Xvar)]). + +constant(sc_exclusivegateway3_branch1_1(nat),action). +action(sc_exclusivegateway3_branch1_1(N41), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N41)))], + [exclusivegateway3_to_parallelgateway1], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N41)))]). + +constant(sc_exclusivegateway3_branch2_1,action). +action(sc_exclusivegateway3_branch2_1, + true, + [exclusivegateway4_to_exclusivegateway3], + [exclusivegateway3_to_parallelgateway1], + [exclusivegateway4_to_exclusivegateway3]). + +constant(sc_exclusivegateway4_branch1_1(nat),action). +action(sc_exclusivegateway4_branch1_1(N42), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))], + [exclusivegateway4_to_usertask7], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))]). + +constant(sc_exclusivegateway4_branch2_1(nat),action). +action(sc_exclusivegateway4_branch2_1(N42), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))], + [exclusivegateway4_to_exclusivegateway3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))]). + + +% CONSTRAINTS + +% GOALS +goal(sod_securitySod1_1(U0,N17,N18,N19),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N17))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N18))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N19)))]). + +goal(sod_securitySod1_2(U0,U1,N20,N21,N22),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N20))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N21))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N22)))]). + +goal(sod_securitySod1_3(U0,U1,N23,N24,N25),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N23))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N24))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N25)))]). + +goal(sod_securitySod1_4(U0,U1,N26,N27,N28),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N26))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N27))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N28)))]). + +goal(sod_securitySod2_1(U0,N29,N30,N31),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N29))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N30))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N31)))]). + +goal(sod_securitySod2_2(U0,U1,N32,N33,N34),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N32))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N33))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N34)))]). + +goal(sod_securitySod2_3(U0,U1,N35,N36,N37),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N35))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N36))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N37)))]). + +goal(sod_securitySod2_4(U0,U1,N38,N39,N40),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N38))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N39))), + executed(entity_lb(user_lb(U1)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N40)))]). + + +% EQUATIONS + +% USER_AXIOMS + +% HC_AXIOMS +constant(rbac_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(rbac_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(direct_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(direct_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(entity_lb(user_lb(A)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(poto_usertask1,hc_axiom). +hc_axiom(poto_usertask1, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask1)))]). + +constant(poto_usertask2,hc_axiom). +hc_axiom(poto_usertask2, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask2)))]). + +constant(poto_usertask3,hc_axiom). +hc_axiom(poto_usertask3, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask3)))]). + +constant(poto_usertask4,hc_axiom). +hc_axiom(poto_usertask4, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask4)))]). + +constant(poto_usertask5,hc_axiom). +hc_axiom(poto_usertask5, + true, + [], + [poto(userORrole_lb(role_lb(supervisor)),taskName_lb(humanTaskName_lb(usertask5)))]). + +constant(poto_usertask6,hc_axiom). +hc_axiom(poto_usertask6, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask6)))]). + +constant(poto_usertask7,hc_axiom). +hc_axiom(poto_usertask7, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask7)))]). + +constant(poto_usertask8,hc_axiom). +hc_axiom(poto_usertask8, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask8)))]). + +constant(poto_usertask9,hc_axiom). +hc_axiom(poto_usertask9, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask9)))]). + + + +% INVOKED DURING THE LOADING (USEFUL FOR SETTING) +init_sate :- + set(verification_abstraction,off), + set(if2sate_version,2). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% NOTE: these prolog facts are not mandatory and are useful only for +% printing a user-friendly output when the triple_step optimization +% is enabled. The user is invited to neglect these declarations. +triple_step_action(authorizeTaskExecution(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(h_taskExecution(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(atask_execution(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +triple_step_action(w_usertask1(Xvar), + true, + [start_event_startevent1, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent1, + counter_w_usertask1(Xvar)]). + +triple_step_action(w_usertask2(N2,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n1,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N2))), + counter_w_usertask2(Xvar)]). + +triple_step_action(w_parallelgateway1, + true, + [exclusivegateway3_to_parallelgateway1], + [parallelgateway1_to_usertask3, + parallelgateway1_to_servicetask2], + [exclusivegateway3_to_parallelgateway1]). + +triple_step_action(w_usertask3(Xvar), + true, + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n3,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)]). + +triple_step_action(w_servicetask2(Xvar), + true, + [parallelgateway1_to_servicetask2, + counter_w_servicetask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),fnat(n4,Xvar,0)))), + counter_w_servicetask2(s(Xvar))], + [parallelgateway1_to_servicetask2, + counter_w_servicetask2(Xvar)]). + +triple_step_action(w_usertask4(N6,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N6))), + counter_w_usertask4(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),fnat(n5,Xvar,0)))), + counter_w_usertask4(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask2)),N6))), + counter_w_usertask4(Xvar)]). + +triple_step_action(w_parallelgateway4(N7,N8), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N7))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N8)))], + [parallelgateway4_to_usertask5], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N7))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask4)),N8)))]). + +triple_step_action(w_usertask5(Xvar), + true, + [parallelgateway4_to_usertask5, + counter_w_usertask5(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),fnat(n9,Xvar,0)))), + counter_w_usertask5(s(Xvar))], + [parallelgateway4_to_usertask5, + counter_w_usertask5(Xvar)]). + +triple_step_action(w_usertask6(N11,Xvar), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N11))), + counter_w_usertask6(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),fnat(n10,Xvar,0)))), + counter_w_usertask6(s(Xvar))], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask5)),N11))), + counter_w_usertask6(Xvar)]). + +triple_step_action(w_usertask7(Xvar), + true, + [exclusivegateway4_to_usertask7, + counter_w_usertask7(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),fnat(n12,Xvar,0)))), + counter_w_usertask7(s(Xvar))], + [exclusivegateway4_to_usertask7, + counter_w_usertask7(Xvar)]). + +triple_step_action(exclusivegateway1_branch1(N13), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))], + [exclusivegateway1_to_usertask8], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))]). + +triple_step_action(exclusivegateway1_branch2(N13), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))], + [exclusivegateway1_to_exclusivegateway2], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask7)),N13)))]). + +triple_step_action(w_usertask8(Xvar), + true, + [exclusivegateway1_to_usertask8, + counter_w_usertask8(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),fnat(n14,Xvar,0)))), + counter_w_usertask8(s(Xvar))], + [exclusivegateway1_to_usertask8, + counter_w_usertask8(Xvar)]). + +triple_step_action(exclusivegateway2_branch1(N15), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N15)))], + [exclusivegateway2_to_usertask9], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask8)),N15)))]). + +triple_step_action(exclusivegateway2_branch2, + true, + [exclusivegateway1_to_exclusivegateway2], + [exclusivegateway2_to_usertask9], + [exclusivegateway1_to_exclusivegateway2]). + +triple_step_action(w_usertask9(Xvar), + true, + [exclusivegateway2_to_usertask9, + counter_w_usertask9(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask9)),fnat(n16,Xvar,0)))), + counter_w_usertask9(s(Xvar))], + [exclusivegateway2_to_usertask9, + counter_w_usertask9(Xvar)]). + +triple_step_action(exclusivegateway3_branch1(N41), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N41)))], + [exclusivegateway3_to_parallelgateway1], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N41)))]). + +triple_step_action(exclusivegateway3_branch2, + true, + [exclusivegateway4_to_exclusivegateway3], + [exclusivegateway3_to_parallelgateway1], + [exclusivegateway4_to_exclusivegateway3]). + +triple_step_action(exclusivegateway4_branch1(N42), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))], + [exclusivegateway4_to_usertask7], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))]). + +triple_step_action(exclusivegateway4_branch2(N42), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))], + [exclusivegateway4_to_exclusivegateway3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask6)),N42)))]). + +correspondence_between_action_and_step_compressed_rule(Act,SCAct) :- + atom_concat('sc_',Act,TmpAct), + atom_concat(TmpAct,_,SCAct). + +% PREDICATE TO EVALUATE ON_THE_FLY_CONDITIONS +on_the_fly_conditions([]). +on_the_fly_conditions([C|Cs]) :- + call(C), + on_the_fly_conditions(Cs). diff --git a/examples/OrderPlacement/.access^ b/examples/OrderPlacement/.access^ new file mode 100644 index 0000000..e69de29 diff --git a/examples/OrderPlacement/OrderPlacementProcess.activiti b/examples/OrderPlacement/OrderPlacementProcess.activiti new file mode 100644 index 0000000..3aecd89 --- /dev/null +++ b/examples/OrderPlacement/OrderPlacementProcess.activiti @@ -0,0 +1,625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/OrderPlacement/OrderPlacementProcess.bpmn20.xml b/examples/OrderPlacement/OrderPlacementProcess.bpmn20.xml new file mode 100644 index 0000000..f2f0773 --- /dev/null +++ b/examples/OrderPlacement/OrderPlacementProcess.bpmn20.xml @@ -0,0 +1,121 @@ + + + + Place documentation for the 'OrderPlacementProcess' process here. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/OrderPlacement/OrderPlacementProcess.png b/examples/OrderPlacement/OrderPlacementProcess.png new file mode 100644 index 0000000000000000000000000000000000000000..7547f6190823f6b0ece684fcdaf1a4b7dfc65a75 GIT binary patch literal 16036 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 literal 0 HcmV?d00001 diff --git a/examples/TravelApproval/ResultSender.java b/examples/TravelApproval/ResultSender.java new file mode 100644 index 0000000..3070200 --- /dev/null +++ b/examples/TravelApproval/ResultSender.java @@ -0,0 +1,27 @@ +package com.mycompany.bpmn; + +import org.activiti.engine.delegate.JavaDelegate; +import org.activiti.engine.delegate.DelegateExecution; + +import com.mycompany.backend.DBConnection; +import com.mycompany.backend.DBManager; +import com.mycompany.backend.DBConstants; + +public class ResultSender implements JavaDelegate { + + public void execute(DelegateExecution execution) throws Exception { + + DBConnection connection = DBManager.getDBConnection(); + + String userID = (String) execution.getVariable("user_id"); + String userName = (String) execution.getVariable("user_name"); + Double userWage = (Double) execution.getVariable("user_wage"); + Double travelBudget = (Double) execution.getVariable("travel_budget"); + Integer travelDuration = (Integer) execution.getVariable("travel_duration"); + String approvingManagerID1 = (String) execution.getVariable("manager_id_first"); + String approvingManagerID2 = (String) execution.getVariable("manager_id_second"); + + connection.save(DBConstants.TRAVEL_TABLE, userID, userName, userWage, travelBudget, travelDuration, approvingManagerID1, approvingManagerID2); + } + +} diff --git a/examples/TravelApproval/TravelApproval.activiti b/examples/TravelApproval/TravelApproval.activiti new file mode 100644 index 0000000..d00437b --- /dev/null +++ b/examples/TravelApproval/TravelApproval.activiti @@ -0,0 +1,609 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/TravelApproval/TravelApproval.png b/examples/TravelApproval/TravelApproval.png new file mode 100644 index 0000000000000000000000000000000000000000..100f829c508f0852cdccdb4cb683107938f2cd60 GIT binary patch literal 33651 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 literal 0 HcmV?d00001 diff --git a/examples/TravelApproval/generated/TravelApproval.aslan b/examples/TravelApproval/generated/TravelApproval.aslan new file mode 100644 index 0000000..f1d8533 --- /dev/null +++ b/examples/TravelApproval/generated/TravelApproval.aslan @@ -0,0 +1,74 @@ +section signature: + + user_to_role : user * role -> fact + poto : userORrole * taskName -> fact + task_to_data : taskName * set * set -> fact + aknows : entity * data -> fact + mc_pair : data * data -> data + contains : set * data -> fact + task : taskName * nat -> taskInstance + canExecute : user * role * humanTaskName -> fact + granted : user * role * taskInstance -> fact + executed : user * taskInstance -> fact + ready : taskInstance -> fact + done : taskInstance -> fact + entity > organization + entity > user + data > object + data > set + userORrole > user + userORrole > role + taskName > automatedTaskName + taskName > humanTaskName + +section types: + + start_event_startevent1,parallelgateway1_to_usertask2,parallelgateway1_to_usertask3,parallelgateway2_to_servicetask1: fact + HT,usertask1,usertask2,usertask3: humanTaskName + IN,OUT,in_usertask1,out_usertask1,in_usertask2,out_usertask2,in_usertask3,out_usertask3,in_servicetask1,out_servicetask1: set + manager,supervisor,clerk,R: role + N,N0,N1,N2,N3,N4,N5,N6,N7,N8,N9,N10,N11,N12: nat + AT,servicetask1: automatedTaskName + user1_manager,user2_manager,user1_supervisor,user2_supervisor,user1_clerk,user2_clerk,A,U0: user + +section inits: + + initial_state init_1 := + + user_to_role(user1_manager,manager). + user_to_role(user2_manager,manager). + user_to_role(user1_supervisor,supervisor). + user_to_role(user2_supervisor,supervisor). + user_to_role(user1_clerk,clerk). + user_to_role(user2_clerk,clerk). + start_event_startevent1. + task_to_data(usertask1,in_usertask1,out_usertask1). + task_to_data(usertask2,in_usertask2,out_usertask2). + task_to_data(usertask3,in_usertask3,out_usertask3). + task_to_data(servicetask1,in_servicetask1,out_servicetask1) + +section hornClauses: + + hc rbac_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(R,HT) + hc direct_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(A,HT) + hc poto_usertask1:= poto(clerk,usertask1) + hc poto_usertask2:= poto(manager,usertask2) + hc poto_usertask3:= poto(manager,usertask3) + +section rules: + + step authorizeTaskExecution(A,R,HT,N) := canExecute(A,R,HT). ready(task(HT,N)) => granted(A,R,task(HT,N)) + step h_taskExecution(A,R,HT,N,IN,OUT) := granted(A,R,task(HT,N)). task_to_data(HT,IN,OUT) => executed(A,task(HT,N)). done(task(HT,N)). task_to_data(HT,IN,OUT). aknows(A,IN). aknows(A,OUT) + step atask_execution(AT,N,IN,OUT) := ready(task(AT,N)). task_to_data(AT,IN,OUT) => done(task(AT,N)). task_to_data(AT,IN,OUT) + step w_usertask1(N0) := start_event_startevent1=[exists N0] => ready(task(usertask1,N0)) + step w_parallelgateway1(N1) := done(task(usertask1,N1)) => parallelgateway1_to_usertask2. parallelgateway1_to_usertask3 + step w_usertask2(N2) := parallelgateway1_to_usertask2=[exists N2] => ready(task(usertask2,N2)) + step w_usertask3(N3) := parallelgateway1_to_usertask3=[exists N3] => ready(task(usertask3,N3)) + step w_parallelgateway2(N4,N5) := done(task(usertask2,N4)). done(task(usertask3,N5)) => parallelgateway2_to_servicetask1 + step w_servicetask1(N6) := parallelgateway2_to_servicetask1=[exists N6] => ready(task(servicetask1,N6)) + +section goals: + + attack_state sod_securitySod1_1(U0,N7,N8):= executed(U0,task(usertask2,N7)). executed(U0,task(usertask3,N8)) + attack_state sod_securitySod2_1(U0,N9,N10):= executed(U0,task(usertask1,N9)). executed(U0,task(usertask3,N10)) + attack_state sod_securitySod3_1(U0,N11,N12):= executed(U0,task(usertask1,N11)). executed(U0,task(usertask2,N12)) diff --git a/examples/TravelApproval/generated/TravelApproval.res b/examples/TravelApproval/generated/TravelApproval.res new file mode 100644 index 0000000..fb6cafc --- /dev/null +++ b/examples/TravelApproval/generated/TravelApproval.res @@ -0,0 +1,266 @@ +% PARAMETERS: + + Protocol: TravelApproval + Problem category: if + + Compound types: on + Step compression: on + Intruder Knowledge As Axioms: off + Weak Type-Flaws (iff newgp): off + + Technique: Graphplan-based Encoding using the EFA schema + Min Steps: 0 + Max Steps: 80 + Delta Steps: 1 + Level Mutex: 0 + Solver: minisat + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% SATE file generated in 0.06 sec... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: INIT + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Initial Facts: 25 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 1 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 0 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 2 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 1 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 3 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 2 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 4 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 3 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 5 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 4 no 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 6 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 5 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 7 + +* SUB-PHASE: Search for SAT models.. + + Find models procedure skipped. + +* SUB-PHASE: Build Graph + + STATISTICS LAYER LEVELED OFF RUNTIME(sec) + 6 no 0.02 + ------ + Total: 0.02 + +* SUB-PHASE: Assert Possible Goals Instances + + STATISTICS RUNTIME(sec) + Total: 0.0 + +* SUB-PHASE: Schemes Generation and Translation + + STATISTICS CLAUSES RUNTIME(sec) + Goals: 7 0.0 + Refinement Schema: 0 0.0 + Horn Clauses Axioms: 252 0.04 + User Axioms: 0 0.0 + Ape Schema: 768 0.06 + Explanatory Frame Schema: 789 0.08 + ------ + Total: 0.18 + +* SUB-PHASE: Solver SAT formula Updated + + STATISTICS + Depth: 7 + Atoms: 746 + Clauses: 1841 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +PHASE: LOOP ITERATION 8 + +* SUB-PHASE: Search for SAT models.. + + Found 1 models in 0.0 sec. + +* SUB-PHASE: Models into Partial Order Plans (POPs) + + STATISTICS RUNTIME(sec) + model2pop 1 0.06 + ------ + Total: 0.06 + +* SUB-PHASE: Partial Order Plans (POPs) validations + + STATISTICS VALID RUNTIME(sec) + POP 1: true 0.0 + ------ + Total: 0.0 + +* SUB-PHASE: Partial Order Plans (POPs) printing + + -------------------------------------------------------------------- + pop 1: + + GOALS: [sod_securitySod1_1(user1_manager,fnat(n2,0,0),fnat(n3,0,0))] + + Step 0: [sc_w_usertask1_1(0)] + Step 1: [sc_authorizeTaskExecution_1(user1_clerk,clerk,usertask1,fnat(n0,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 2: [sc_h_taskExecution_1(user1_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 3: [sc_w_parallelgateway1_1(fnat(n0,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 4: [sc_w_usertask2_1(0),sc_w_usertask3_1(0),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 5: [sc_authorizeTaskExecution_1(user1_manager,manager,usertask2,fnat(n2,0,0)),sc_authorizeTaskExecution_1(user1_manager,manager,usertask3,fnat(n3,0,0)),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 6: [sc_h_taskExecution_1(user1_manager,manager,usertask2,fnat(n2,0,0),in_usertask2,out_usertask2),sc_h_taskExecution_1(user1_manager,manager,usertask3,fnat(n3,0,0),in_usertask3,out_usertask3),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + Step 7: [rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3)] + -------------------------------------------------------------------- + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +RESULTS + +Attacks Found: true +Stop Condition Reached: false +Formula statistics: + Graph Construction Time: 0.08 + Graph Leveled Off: no + Graph2SAT Time (sec): 0.18 + Encoding Time (sec): 0.26 + Depth: 7 + Atoms: 746 + Clauses: 1841 +Solving statistics: + Total Solving Time (sec): 0.0 + Last Solving Time (sec): 0.0 +Abstraction/Refinement statistics: + Validation Time (sec): 0.0 + Models into POPs Time (sec): 0.06 + Refinement iterations: 0 + +Total Time: 0.32 + + diff --git a/examples/TravelApproval/generated/TravelApproval.result b/examples/TravelApproval/generated/TravelApproval.result new file mode 100644 index 0000000..8ee07fc --- /dev/null +++ b/examples/TravelApproval/generated/TravelApproval.result @@ -0,0 +1,50 @@ +INPUT TravelApproval.aslan +SUMMARY ATTACK_FOUND + GOAL: sod_securitySod1_1(user1_manager,fnat(n2,0,0),fnat(n3,0,0)) + +DETAILS + STRONGLY_TYPED_MODEL + BOUNDED_NUMBER_OF_SESSIONS + BOUNDED_SEARCH_DEPTH + BOUNDED_MESSAGE_DEPTH + +BACKEND SATMC VERSION 3.3.1_(September_2011) + +STATISTICS TIME 320 ms + upperBoundReached false boolean + graphLeveledOff no boolean + satSolver minisat solver + maxStepsNumber 80 steps + stepsNumber 7 steps + atomsNumber 746 atoms + clausesNumber 1841 clauses + encodingTime 0.26 seconds + solvingTime 0.0 seconds + if2sateCompilationTime 0.06 seconds + +TRACE: +0 + CLAUSES:{ } + RULES: w_usertask1(fnat(n0,0,0)) +1 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: authorizeTaskExecution(user1_clerk,clerk,usertask1,fnat(n0,0,0)) +2 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: h_taskExecution(user1_clerk,clerk,usertask1,fnat(n0,0,0),in_usertask1,out_usertask1) +3 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: w_parallelgateway1(fnat(n0,0,0)) +4 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: { w_usertask2(fnat(n2,0,0)),w_usertask3(fnat(n3,0,0)) } +5 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: { authorizeTaskExecution(user1_manager,manager,usertask2,fnat(n2,0,0)),authorizeTaskExecution(user1_manager,manager,usertask3,fnat(n3,0,0)) } +6 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } + RULES: { h_taskExecution(user1_manager,manager,usertask2,fnat(n2,0,0),in_usertask2,out_usertask2),h_taskExecution(user1_manager,manager,usertask3,fnat(n3,0,0),in_usertask3,out_usertask3) } +7 + CLAUSES:{ rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3) } +CLOSED_FINAL_STATE: +{ counter_w_servicetask1(0),counter_w_usertask1(s(0)),counter_w_usertask2(s(0)),counter_w_usertask3(s(0)),done(task(usertask2,fnat(n2,0,0))),done(task(usertask3,fnat(n3,0,0))),initial_state(init_1),aknows(user1_clerk,in_usertask1),aknows(user1_clerk,out_usertask1),aknows(user1_manager,in_usertask2),aknows(user1_manager,in_usertask3),aknows(user1_manager,out_usertask2),aknows(user1_manager,out_usertask3),executed(user1_clerk,task(usertask1,fnat(n0,0,0))),executed(user1_manager,task(usertask2,fnat(n2,0,0))),executed(user1_manager,task(usertask3,fnat(n3,0,0))),poto(clerk,usertask1),poto(manager,usertask2),poto(manager,usertask3),user_to_role(user1_clerk,clerk),user_to_role(user1_manager,manager),user_to_role(user1_supervisor,supervisor),user_to_role(user2_clerk,clerk),user_to_role(user2_manager,manager),user_to_role(user2_supervisor,supervisor),canExecute(user1_clerk,clerk,usertask1),canExecute(user1_manager,manager,usertask2),canExecute(user1_manager,manager,usertask3),canExecute(user2_clerk,clerk,usertask1),canExecute(user2_manager,manager,usertask2),canExecute(user2_manager,manager,usertask3),rbac_ac(user1_clerk,clerk,usertask1),rbac_ac(user1_manager,manager,usertask2),rbac_ac(user1_manager,manager,usertask3),rbac_ac(user2_clerk,clerk,usertask1),rbac_ac(user2_manager,manager,usertask2),rbac_ac(user2_manager,manager,usertask3),sod_securitySod1_1(user1_manager,fnat(n2,0,0),fnat(n3,0,0)),task_to_data(servicetask1,in_servicetask1,out_servicetask1),task_to_data(usertask1,in_usertask1,out_usertask1),task_to_data(usertask2,in_usertask2,out_usertask2),task_to_data(usertask3,in_usertask3,out_usertask3) } diff --git a/examples/TravelApproval/generated/TravelApproval.sate b/examples/TravelApproval/generated/TravelApproval.sate new file mode 100644 index 0000000..bfaf68f --- /dev/null +++ b/examples/TravelApproval/generated/TravelApproval.sate @@ -0,0 +1,427 @@ +% SATE OUTPUT + +% SORTS +sort(hc_axiom). +sort(action). +sort(fresh_const). +sort(fresh_nat). +sort(message). +sort(nat). +sort(set). +sort(set_typed). +sort(humanTaskName). +sort(humanTaskName_temp). +sort(humanTaskName_typed). +sort(role). +sort(role_temp). +sort(role_typed). +sort(automatedTaskName). +sort(automatedTaskName_temp). +sort(automatedTaskName_typed). +sort(user). +sort(user_temp). +sort(user_typed). +sort(data_typed). +sort(taskInstance_typed). +sort(fluent). +sort(userORrole). +sort(taskName). +sort(entity). +sort(data). + +% CONSTANTS +constant(initial_state(initial_state_id),fluent). +constant(fpk(fresh_public_key_id,nat,nat),fresh_public_key_typed). +constant(puk(fresh_public_key_typed),fresh_public_key). +constant(fsk(fresh_symmetric_key_id,nat,nat),fresh_symmetric_key_typed). +constant(sk(fresh_symmetric_key_typed),fresh_symmetric_key). +constant(fn(fresh_nonce_id,nat,nat),fresh_nonce_typed). +constant(nonce(fresh_nonce_typed),fresh_nonce). +constant(fmr(fresh_agent_id,nat,nat),fresh_agent_typed). +constant(mr(fresh_agent_typed),fresh_agent). +constant(ff(fresh_function_id,nat,nat),fresh_function_typed). +constant(fu(fresh_function_typed),fresh_function). +constant(fnat(fresh_nat_id,nat,nat),fresh_nat). +constant(fmsg(fresh_message_id,nat,nat),fresh_message). +constant(f_protocol_id_typed(fresh_protocol_id_typed_id,nat,nat),fresh_protocol_id_typed). +constant(pid(fresh_protocol_id_typed),fresh_protocol_id). +constant(fresh(fresh_const),fluent). +constant(s,nat). +constant(0,nat). +constant(mc_pair,data_typed). +constant(task,taskInstance_typed). +constant(start_event_startevent1,fluent). +constant(parallelgateway1_to_usertask2,fluent). +constant(parallelgateway1_to_usertask3,fluent). +constant(parallelgateway2_to_servicetask1,fluent). +constant(usertask1,humanTaskName_typed). +constant(usertask2,humanTaskName_typed). +constant(usertask3,humanTaskName_typed). +constant(in_usertask1,set_typed). +constant(out_usertask1,set_typed). +constant(in_usertask2,set_typed). +constant(out_usertask2,set_typed). +constant(in_usertask3,set_typed). +constant(out_usertask3,set_typed). +constant(in_servicetask1,set_typed). +constant(out_servicetask1,set_typed). +constant(manager,role_typed). +constant(supervisor,role_typed). +constant(clerk,role_typed). +constant(servicetask1,automatedTaskName_typed). +constant(user1_manager,user_typed). +constant(user2_manager,user_typed). +constant(user1_supervisor,user_typed). +constant(user2_supervisor,user_typed). +constant(user1_clerk,user_typed). +constant(user2_clerk,user_typed). +constant(mr(agent_typed),agent). +constant(nonce(nonce_typed),nonce). +constant(sk(sk_typed),symmetric_key). +constant(puk(puk_typed),public_key). +constant(private_key_lb(private_key_typed),private_key). +constant(fu(function_typed),function). +constant(pid(protocol_id_typed),protocol_id). +constant(bool_lb(bool_typed),bool). +constant(set_lb(set_typed),set). +constant(ch(channel_typed),channel). +constant(s(nat),nat). +constant(contains(message,set),fluent). +constant(user_to_role(user,role),fluent). +constant(poto(userORrole,taskName),fluent). +constant(task_to_data(taskName,set,set),fluent). +constant(aknows(entity,data),fluent). +constant(mc_pair(data,data),data_typed). +constant(contains(set,data),fluent). +constant(task(taskName,nat),taskInstance_typed). +constant(canExecute(user,role,humanTaskName),fluent). +constant(granted(user,role,taskInstance),fluent). +constant(executed(user,taskInstance),fluent). +constant(ready(taskInstance),fluent). +constant(done(taskInstance),fluent). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(taskName_lb(humanTaskName_temp),humanTaskName). +constant(humanTaskName_lb(humanTaskName_typed),humanTaskName_temp). +constant(userORrole_lb(role_temp),role). +constant(userORrole_lb(role_temp),role). +constant(role_lb(role_typed),role_temp). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(taskName_lb(automatedTaskName_temp),automatedTaskName). +constant(automatedTaskName_lb(automatedTaskName_typed),automatedTaskName_temp). +constant(entity_lb(user_temp),user). +constant(entity_lb(user_temp),user). +constant(user_lb(user_typed),user_temp). +constant(init_1,initial_state_id). +constant(counter_w_usertask1(nat),fluent). +constant(counter_w_usertask2(nat),fluent). +constant(counter_w_usertask3(nat),fluent). +constant(counter_w_servicetask1(nat),fluent). +constant(n0,fresh_nat_id). +constant(n2,fresh_nat_id). +constant(n3,fresh_nat_id). +constant(n6,fresh_nat_id). + +% SUPERSORTS +super_sort(puk_typed,fresh_public_key_typed). +super_sort(fresh_const,fresh_public_key). +super_sort(sk_typed,fresh_symmetric_key_typed). +super_sort(fresh_const,fresh_symmetric_key). +super_sort(nonce_typed,fresh_nonce_typed). +super_sort(fresh_const,fresh_nonce). +super_sort(agent_typed,fresh_agent_typed). +super_sort(fresh_const,fresh_agent). +super_sort(function_typed,fresh_function_typed). +super_sort(fresh_const,fresh_function). +super_sort(nat,fresh_nat). +super_sort(fresh_const,fresh_nat). +super_sort(message,fresh_message). +super_sort(fresh_const,fresh_message). +super_sort(protocol_id_typed,fresh_protocol_id_typed). +super_sort(fresh_const,fresh_protocol_id). +super_sort(message,agent). +super_sort(message,nonce). +super_sort(message,symmetric_key). +super_sort(message,public_key). +super_sort(message,private_key). +super_sort(message,function). +super_sort(message,nat). +super_sort(message,protocol_id). +super_sort(message,bool). +super_sort(entity,organization). +super_sort(entity,user). +super_sort(data,object). +super_sort(data,set). +super_sort(userORrole,user). +super_sort(userORrole,role). +super_sort(taskName,automatedTaskName). +super_sort(taskName,humanTaskName). +super_sort(taskName_typed,humanTaskName_temp). +super_sort(userORrole_typed,role_temp). +super_sort(taskName_typed,automatedTaskName_temp). +super_sort(entity_typed,user_temp). + +% INITIAL STATES +facts([initial_state(init_1), + user_to_role(entity_lb(user_lb(user1_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user2_manager)),userORrole_lb(role_lb(manager))), + user_to_role(entity_lb(user_lb(user1_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user2_supervisor)),userORrole_lb(role_lb(supervisor))), + user_to_role(entity_lb(user_lb(user1_clerk)),userORrole_lb(role_lb(clerk))), + user_to_role(entity_lb(user_lb(user2_clerk)),userORrole_lb(role_lb(clerk))), + start_event_startevent1, + task_to_data(taskName_lb(humanTaskName_lb(usertask1)),set_lb(in_usertask1),set_lb(out_usertask1)), + task_to_data(taskName_lb(humanTaskName_lb(usertask2)),set_lb(in_usertask2),set_lb(out_usertask2)), + task_to_data(taskName_lb(humanTaskName_lb(usertask3)),set_lb(in_usertask3),set_lb(out_usertask3)), + task_to_data(taskName_lb(automatedTaskName_lb(servicetask1)),set_lb(in_servicetask1),set_lb(out_servicetask1)), + counter_w_usertask1(0), + counter_w_usertask2(0), + counter_w_usertask3(0), + counter_w_servicetask1(0)]). + + +% RULES +constant(sc_authorizeTaskExecution_1(user_typed,role_typed,humanTaskName_typed,nat),action). +action(sc_authorizeTaskExecution_1(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_h_taskExecution_1(user_typed,role_typed,humanTaskName_typed,nat,set_typed,set_typed),action). +action(sc_h_taskExecution_1(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +constant(sc_atask_execution_1(automatedTaskName_typed,nat,set_typed,set_typed),action). +action(sc_atask_execution_1(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +constant(sc_w_usertask1_1(nat),action). +action(sc_w_usertask1_1(Xvar), + true, + [start_event_startevent1, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent1, + counter_w_usertask1(Xvar)]). + +constant(sc_w_parallelgateway1_1(nat),action). +action(sc_w_parallelgateway1_1(N1), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N1)))], + [parallelgateway1_to_usertask2, + parallelgateway1_to_usertask3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N1)))]). + +constant(sc_w_usertask2_1(nat),action). +action(sc_w_usertask2_1(Xvar), + true, + [parallelgateway1_to_usertask2, + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n2,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [parallelgateway1_to_usertask2, + counter_w_usertask2(Xvar)]). + +constant(sc_w_usertask3_1(nat),action). +action(sc_w_usertask3_1(Xvar), + true, + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n3,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)]). + +constant(sc_w_parallelgateway2_1(nat,nat),action). +action(sc_w_parallelgateway2_1(N4,N5), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N4))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N5)))], + [parallelgateway2_to_servicetask1], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N4))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N5)))]). + +constant(sc_w_servicetask1_1(nat),action). +action(sc_w_servicetask1_1(Xvar), + true, + [parallelgateway2_to_servicetask1, + counter_w_servicetask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),fnat(n6,Xvar,0)))), + counter_w_servicetask1(s(Xvar))], + [parallelgateway2_to_servicetask1, + counter_w_servicetask1(Xvar)]). + + +% CONSTRAINTS + +% GOALS +goal(sod_securitySod1_1(U0,N7,N8),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N7))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N8)))]). + +goal(sod_securitySod2_1(U0,N9,N10),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N9))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N10)))]). + +goal(sod_securitySod3_1(U0,N11,N12),true, + [executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N11))), + executed(entity_lb(user_lb(U0)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N12)))]). + + +% EQUATIONS + +% USER_AXIOMS + +% HC_AXIOMS +constant(rbac_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(rbac_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(direct_ac(user_typed,role_typed,humanTaskName_typed),hc_axiom). +hc_axiom(direct_ac(A,R,HT), + true, + [user_to_role(entity_lb(user_lb(A)),userORrole_lb(role_lb(R))), + poto(entity_lb(user_lb(A)),taskName_lb(humanTaskName_lb(HT)))], + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT)))]). + +constant(poto_usertask1,hc_axiom). +hc_axiom(poto_usertask1, + true, + [], + [poto(userORrole_lb(role_lb(clerk)),taskName_lb(humanTaskName_lb(usertask1)))]). + +constant(poto_usertask2,hc_axiom). +hc_axiom(poto_usertask2, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask2)))]). + +constant(poto_usertask3,hc_axiom). +hc_axiom(poto_usertask3, + true, + [], + [poto(userORrole_lb(role_lb(manager)),taskName_lb(humanTaskName_lb(usertask3)))]). + + + +% INVOKED DURING THE LOADING (USEFUL FOR SETTING) +init_sate :- + set(verification_abstraction,off), + set(if2sate_version,2). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% NOTE: these prolog facts are not mandatory and are useful only for +% printing a user-friendly output when the triple_step optimization +% is enabled. The user is invited to neglect these declarations. +triple_step_action(authorizeTaskExecution(A,R,HT,N), + true, + [canExecute(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskName_lb(humanTaskName_lb(HT))), + ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(h_taskExecution(A,R,HT,N,IN,OUT), + true, + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT))], + [executed(entity_lb(user_lb(A)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N))), + task_to_data(taskName_lb(humanTaskName_lb(HT)),set_lb(IN),set_lb(OUT)), + aknows(entity_lb(user_lb(A)),set_lb(IN)), + aknows(entity_lb(user_lb(A)),set_lb(OUT))], + [granted(entity_lb(user_lb(A)),userORrole_lb(role_lb(R)),taskInstance_lb(task(taskName_lb(humanTaskName_lb(HT)),N)))]). + +triple_step_action(atask_execution(AT,N,IN,OUT), + true, + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [done(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N))), + task_to_data(taskName_lb(automatedTaskName_lb(AT)),set_lb(IN),set_lb(OUT))], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(AT)),N)))]). + +triple_step_action(w_usertask1(Xvar), + true, + [start_event_startevent1, + counter_w_usertask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),fnat(n0,Xvar,0)))), + counter_w_usertask1(s(Xvar))], + [start_event_startevent1, + counter_w_usertask1(Xvar)]). + +triple_step_action(w_parallelgateway1(N1), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N1)))], + [parallelgateway1_to_usertask2, + parallelgateway1_to_usertask3], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask1)),N1)))]). + +triple_step_action(w_usertask2(Xvar), + true, + [parallelgateway1_to_usertask2, + counter_w_usertask2(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),fnat(n2,Xvar,0)))), + counter_w_usertask2(s(Xvar))], + [parallelgateway1_to_usertask2, + counter_w_usertask2(Xvar)]). + +triple_step_action(w_usertask3(Xvar), + true, + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),fnat(n3,Xvar,0)))), + counter_w_usertask3(s(Xvar))], + [parallelgateway1_to_usertask3, + counter_w_usertask3(Xvar)]). + +triple_step_action(w_parallelgateway2(N4,N5), + true, + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N4))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N5)))], + [parallelgateway2_to_servicetask1], + [done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask2)),N4))), + done(taskInstance_lb(task(taskName_lb(humanTaskName_lb(usertask3)),N5)))]). + +triple_step_action(w_servicetask1(Xvar), + true, + [parallelgateway2_to_servicetask1, + counter_w_servicetask1(Xvar)], + [ready(taskInstance_lb(task(taskName_lb(automatedTaskName_lb(servicetask1)),fnat(n6,Xvar,0)))), + counter_w_servicetask1(s(Xvar))], + [parallelgateway2_to_servicetask1, + counter_w_servicetask1(Xvar)]). + +correspondence_between_action_and_step_compressed_rule(Act,SCAct) :- + atom_concat('sc_',Act,TmpAct), + atom_concat(TmpAct,_,SCAct). + +% PREDICATE TO EVALUATE ON_THE_FLY_CONDITIONS +on_the_fly_conditions([]). +on_the_fly_conditions([C|Cs]) :- + call(C), + on_the_fly_conditions(Cs). diff --git a/examples/misc/ASLanSoDDemo.activiti b/examples/misc/ASLanSoDDemo.activiti new file mode 100644 index 0000000..df850f0 --- /dev/null +++ b/examples/misc/ASLanSoDDemo.activiti @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/misc/AdvancedSoDDemo.activiti b/examples/misc/AdvancedSoDDemo.activiti new file mode 100644 index 0000000..1df4f79 --- /dev/null +++ b/examples/misc/AdvancedSoDDemo.activiti @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..16cd310 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,5 @@ +*/target/ +*/bin/ +*/.classpath +*/.project +*/.settings diff --git a/src/com.sun.xacml/.settings/org.eclipse.jdt.core.prefs b/src/com.sun.xacml/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..a0d3e95 --- /dev/null +++ b/src/com.sun.xacml/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Thu Dec 29 14:50:17 CET 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/src/com.sun.xacml/pom.xml b/src/com.sun.xacml/pom.xml new file mode 100644 index 0000000..470c394 --- /dev/null +++ b/src/com.sun.xacml/pom.xml @@ -0,0 +1,66 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + com.sun.xacml + com.sun.xacml + jar + 0.1 + com.sun.xacml + http://maven.apache.org + + + + 2.3.2 + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + + + maven-assembly-plugin + 2.3 + + + jar-with-dependencies + + + + + + + + junit + junit + [4.8,) + test + + + log4j + log4j + [1.2,) + + + + + xalan + xalan + 2.7.1 + + + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/AbstractPolicy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/AbstractPolicy.java new file mode 100644 index 0000000..a7936a7 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/AbstractPolicy.java @@ -0,0 +1,820 @@ + +/* + * @(#)AbstractPolicy.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.combine.CombinerElement; +import com.sun.xacml.combine.CombinerParameter; +import com.sun.xacml.combine.CombiningAlgorithm; +import com.sun.xacml.combine.CombiningAlgFactory; +import com.sun.xacml.combine.PolicyCombiningAlgorithm; +import com.sun.xacml.combine.RuleCombiningAlgorithm; + +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.ctx.PolicyIssuer; +import com.sun.xacml.ctx.Result; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents an instance of an XACML policy. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + * @author Ludwig Seitz + * + */ + + +public abstract class AbstractPolicy implements PolicyTreeElement, Cloneable { + + // atributes associated with this policy + private URI idAttr; + private CombiningAlgorithm combiningAlg; + + /** + * The version number for this policy. This is _not_ the XACML or + * XPath version. This is for versioning policies/policySets. + */ + private String version; + + // the elements in the policy + private String description; + private PolicyIssuer policyIssuer; + private Target target; + + // the default version of XPath + private String defaultVersion; + + // the meta-data associated with this policy + private PolicyMetaData metaData; + + // the child elements under this policy represented simply as the + // PolicyTreeElements... + private List children; + // ...or the CombinerElements that are passed to combining algorithms + private List childElements; + + // any obligations held by this policy + private Set obligations; + + // the list of combiner parameters + private List parameters; + + // the maximum delegation depth authorised by this AbstractPolicy. + private int maxDelegationDepth = Constants.MAX_DELEGATION_DEPTH_UNDEFINED; + + protected RuntimeInfo src; + + /** + * Constructor used by PolicyReference, which supplies + * its own values for the methods in this class. + */ + protected AbstractPolicy() { + // Used by PolicyRefence + } + + /** + * Constructor used to create a policy from concrete components. + * + * @param id the policy id + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the XACML version identifier. + * @param combiningAlg the combining algorithm to use + * @param description describes the policy or null if there is none + * @param issuer the policy's issuer, used for delegation, can be null. + * @param target the policy's target + * @param defaultVersion the XPath version to use for selectors, + * can be null. + * @param obligations the policy's obligations, can be null. + * @param parameters the policy's combiner parameters, can be null. + * @param maxDelegationDepth the maximum depth of delegation authorised + * by this policy. A value of -1 indicates + * that this was not set. + */ + protected AbstractPolicy(URI id, String version, String xacmlVersion, + CombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, + Target target, String defaultVersion, + Set obligations, List parameters, + int maxDelegationDepth) { + this.idAttr = id; + this.combiningAlg = combiningAlg; + this.description = description; + this.target = target; + this.defaultVersion = defaultVersion; + + this.policyIssuer = issuer; + + if (version == null) { + this.version = "1.0"; + } else { + this.version = version; + } + + this.metaData = new PolicyMetaData(xacmlVersion, defaultVersion); + + if (obligations == null) { + this.obligations = Obligation.EMPTY_SET; + } else { + this.obligations = Collections. + unmodifiableSet(new HashSet(obligations)); + } + + if (parameters == null) { + this.parameters = CombinerParameter.EMPTY_LIST; + } else { + this.parameters = Collections. + unmodifiableList(new ArrayList(parameters)); + } + + this.maxDelegationDepth = maxDelegationDepth; + } + + /** + * Constructor used by child classes to initialize the shared data from + * a DOM root node. + * + * @param root the DOM root of the policy + * @param policyPrefix either "Policy" or "PolicySet" + * @param combiningName name of the field naming the combining alg + * + * @throws ParsingException if the policy is invalid + */ + protected AbstractPolicy(Node root, String policyPrefix, + String combiningName) throws ParsingException { + // get the attributes, all of which are common to Policies + NamedNodeMap attrs = root.getAttributes(); + + try { + // get the attribute Id + this.idAttr = new URI(attrs.getNamedItem(policyPrefix + "Id") + .getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error while parsing required " + + "attribute " + policyPrefix + "Id of a " + + policyPrefix, e); + } + + // see if there's a version + Node versionNode = attrs.getNamedItem("Version"); + if (versionNode != null) { + this.version = versionNode.getNodeValue(); + } else { + // assign the default version + this.version = "1.0"; + } + + // see if there's a MaxDelegationDepth + Node depthNode = attrs.getNamedItem("MaxDelegationDepth"); + if (depthNode != null) { + this.maxDelegationDepth + = Integer.parseInt(depthNode.getNodeValue()); + } else { + this.maxDelegationDepth = Constants.MAX_DELEGATION_DEPTH_UNDEFINED; + } + + // now get the combining algorithm... + try { + URI algId = new URI(attrs.getNamedItem(combiningName). + getNodeValue()); + CombiningAlgFactory factory = CombiningAlgFactory.getInstance(); + this.combiningAlg = factory.createAlgorithm(algId); + } catch (URISyntaxException e) { + throw new ParsingException("Error parsing combining algorithm" + + " in " + policyPrefix, e); + } catch (UnknownIdentifierException e) { + throw new ParsingException("Error parsing combining algorithm" + + " in " + policyPrefix, e); + } + + // ...and make sure it's the right kind + if (policyPrefix.equals("Policy")) { + if (! (this.combiningAlg instanceof RuleCombiningAlgorithm)) { + throw new ParsingException("Policy must use a Rule " + + "Combining Algorithm"); + } + } else { + if (! (this.combiningAlg instanceof PolicyCombiningAlgorithm)) { + throw new ParsingException("PolicySet must use a Policy " + + "Combining Algorithm"); + } + } + + // do an initial pass through the elements to pull out the + // defaults, if any, so we can setup the meta-data + NodeList children = root.getChildNodes(); + + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE + && child.getLocalName().equals( + policyPrefix + "Defaults")) { + handleDefaults(child); + } + } + + // with the defaults read, create the meta-data + this.metaData = new PolicyMetaData(root.getNamespaceURI(), + this.defaultVersion); + + // now read the remaining policy elements + this.obligations = new HashSet(); + this.parameters = new ArrayList(); + this.policyIssuer = null; + children = root.getChildNodes(); + + // now read the policy elements + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + String cname = child.getLocalName(); + if (cname.equals("Description")) { + if (child.getFirstChild() != null) { + this.description = child.getFirstChild().getNodeValue(); + } + } else if (cname.equals("PolicyIssuer")) { + parsePolicyIssuerAttributes(child); + } else if (cname.equals("Target")) { + this.target = Target.getInstance(child, this.metaData); + } else if (cname.equals("Obligations")) { + parseObligations(child); + } else if (cname.equals(policyPrefix + "Defaults")) { + handleDefaults(child); + } else if (cname.equals("CombinerParameters")) { + handleParameters(child); + } + } + } + + // finally, make sure the obligations and parameters are immutable + this.obligations = Collections.unmodifiableSet(this.obligations); + this.parameters = Collections.unmodifiableList(this.parameters); + } + + /** + * The clone method. + * FIXME: this does no deep copy on the Lists and Sets. + * + * @return a copy of this object. + */ + public Object clone() { + try { + AbstractPolicy clone = (AbstractPolicy)super.clone(); + clone.idAttr = this.idAttr; + + try { + clone.combiningAlg + = CombiningAlgFactory.getInstance().createAlgorithm( + this.combiningAlg.getIdentifier()); + } catch (UnknownIdentifierException e) { + throw new RuntimeException("Impossible exception: " + + e.getMessage()); + } + clone.version = this.version; + clone.description = this.description; + if (this.policyIssuer != null) { + clone.policyIssuer + = (PolicyIssuer)this.policyIssuer.clone(); + } else { clone.policyIssuer = null; } + clone.target = (Target)this.target.clone(); + clone.defaultVersion = this.defaultVersion; + clone.metaData = this.metaData; + clone.obligations = new HashSet(this.obligations); + clone.parameters = new ArrayList(this.parameters); + clone.maxDelegationDepth = this.maxDelegationDepth; + return clone; + } catch (CloneNotSupportedException e1) {// this should never happen + throw new RuntimeException("Couldn't clone AbstractPolicy"); + } + } + + /** + * Helper routine that parses the PolicyIssuer attributes in + * the policy or policy set + * @param root the root node of PolicyIssuer + * @throws ParsingException + */ + private void parsePolicyIssuerAttributes(Node root) + throws ParsingException { + NodeList nodes = root.getChildNodes(); + Set issuerAttr = new HashSet(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Attribute")) { + List attrs = Attribute.getInstances(node); + issuerAttr.addAll(attrs); + } + } + + this.policyIssuer = new PolicyIssuer(issuerAttr); + } + + /** + * Helper routine to parse the obligation data + * + * @param root The node containing the obligation data. + * + * @throws ParsingException + */ + private void parseObligations(Node root) throws ParsingException { + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Obligation")) { + this.obligations.add(Obligation.getInstance(node)); + } + } + } + + /** + * There used to be multiple things in the defaults type, but now + * there's just the one string that must be a certain value, so it + * doesn't seem all that useful to have a class for this...we could + * always bring it back, however, if it started to do more + * + * @param root The node that contains the XPathVersion. + */ + private void handleDefaults(Node root) throws ParsingException { + this.defaultVersion = null; + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("XPathVersion")) { + if (node.getFirstChild() != null) { + this.defaultVersion = node.getFirstChild().getNodeValue(); + } else { + throw new ParsingException("XPathVersion xml-attribute" + + "didn't have a value"); + + } + } + } + } + + /** + * Handles all the CombinerParameters in the policy or policy set + * + * @param root The node containing the CombinerParameters. + * + * @throws ParsingException + */ + private void handleParameters(Node root) throws ParsingException { + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("CombinerParameter")) { + this.parameters.add(CombinerParameter.getInstance(node)); + } + } + } + + /** + * Returns the id of this policy + * + * @return the policy id + */ + public URI getId() { + return this.idAttr; + } + + /** + * Returns the version of this policy. If this is an XACML 1.x policy + * then this will always return "1.0". + * + * @return the policy version + */ + public String getVersion() { + return this.version; + } + + /** + * Returns the combining algorithm used by this policy + * + * @return the combining algorithm + */ + public CombiningAlgorithm getCombiningAlg() { + return this.combiningAlg; + } + + /** + * Returns the list of input parameters for the combining algorithm. If + * this is an XACML 1.x policy then the list will always be empty. + * + * @return a List of CombinerParameters + */ + public List getCombiningParameters() { + return this.parameters; + } + + /** + * Returns the given description of this policy or null if there is no + * description + * + * @return the description or null + */ + public String getDescription() { + return this.description; + } + + /** + * Returns a PolicyIssuer that represents the + * PolicyIssuer for this policy. + * + * @return a PolicyIssuer or null + */ + public PolicyIssuer getPolicyIssuer() { + return this.policyIssuer; + } + + /** + * Returns the target for this policy + * + * @return the policy's target + */ + public Target getTarget() { + return this.target; + } + + /** + * Returns the XPath version to use or null if none was specified + * + * @return XPath version or null + */ + public String getDefaultVersion() { + return this.defaultVersion; + } + + /** + * Returns the List of children under this node in the + * policy tree. Depending on what kind of policy this node represents + * the children will either be AbstractPolicy objects + * or Rules. + * + * @return a List of child nodes + */ + public List getChildren() { + return this.children; + } + + /** + * Returns the List of CombinerElements that + * is provided to the combining algorithm. This returns the same set + * of children that getChildren provides along with any + * associated combiner parameters. + * + * @return a List of CombinerElements + */ + public List getChildElements() { + return this.childElements; + } + + /** + * Returns the Set of obligations for this policy, which may be empty + * + * @return the policy's obligations + */ + public Set getObligations() { + return this.obligations; + } + + /** + * Returns the meta-data associated with this policy + * + * @return the policy's meta data. + */ + public PolicyMetaData getMetaData() { + return this.metaData; + } + + /** + *@return Returns the maximum delegation depth or + * Integer.MAX_VALUE if there is none. + */ + public int getMaxDelegationDepth() { + return this.maxDelegationDepth; + } + + /** + * Given the input context sees whether or not the request matches this + * policy. This must be called by combining algorithms before they + * evaluate a policy. This is also used in the initial policy finding + * operation to determine which top-level policies might apply to the + * request. + * + * @param context the representation of the request + * + * @return the result of trying to match the policy and the request + */ + public MatchResult match(EvaluationCtx context) { + return this.target.match(context); + } + + /** + * Sets the child policy tree elements for this node, which are passed + * to the combining algorithm on evaluation. The List must + * contain CombinerElements, which in turn will contain + * Rules or AbstractPolicys, but may not + * contain both types of elements. + * + * @param children1 a List of CombinerElements + * representing the child elements used by the combining + * algorithm + */ + protected void setChildren(List children1) { + // we always want a concrete list, since we're going to pass it to + // a combiner that expects a non-null input + if (children1 == null) { + this.children = PolicyTreeElement.EMPTY_LIST; + } else { + // NOTE: since this is only getting called by known child + // classes we don't check that the types are all the same + List list = new ArrayList(); + + for ( CombinerElement element : children1 ) { + list.add(element.getElement()); + } + + this.children = Collections.unmodifiableList(list); + this.childElements = Collections.unmodifiableList(children1); + } + } + + /** + * Tries to evaluate the policy by calling the combining algorithm on + * the given policies or rules. The match method must always + * be called first, and must always return MATCH, before this method + * is called. + * + * @param context the representation of the request + * + * @return the result of evaluation + */ + public Result evaluate(EvaluationCtx context) { + //Need to this as parent policy set if this is a policy set + if (this instanceof PolicySet) { + context.saveParentPolicySet(this); + } + + RuntimeInfo combSrc = null; + // check if runtime info is there and actually used + if ( src != null ) { + //combSrc = RuntimeInfo.getIndirectSourceLocator(src, ELEMENT_TYPE.COMBINING_ALG); + //combSrc = src.getIndirectSourceLocator(ELEMENT_TYPE.COMBINING_ALG); + combSrc = src.getIndirectRuntimeInfo(combiningAlg, ELEMENT_TYPE.COMBINING_ALG); + this.combiningAlg.setRuntimeInfo(combSrc); + } + + //prepare result variable + Result result = this.combiningAlg.combine(context, this.parameters, + this.childElements); + + if ( combSrc != null ) { + this.combiningAlg.unsetRuntimeInfo(combSrc); + } + + if (this instanceof PolicySet) { + context.popParentPolicySet(); + } + + //create a set for collecting obligations + Set collectedObligations = new HashSet(); + + // Do we need to reduce this request to the trustedIssuer? + if (!hasTrustedIssuer()) { + if (result.getDecision() == Result.DECISION_NOT_APPLICABLE) { + // we do not need to process reduction for this result + return null; + } + context.createReductionGraph(); + Result reductionResult = context.getReductionGraph().reduce( + context, result, this.idAttr); + if (reductionResult == null + || reductionResult.getDecision() + == Result.DECISION_INDETERMINATE) { + //The reduction failed so we return this result now. + return reductionResult; + } + //check for obligations + collectedObligations.addAll(reductionResult.getObligations()); + } + + // add the obligations of the current policy + collectedObligations.addAll(this.obligations); + + // if we have no obligations, we're done + if (collectedObligations.size() == 0) { + return result; + } + + // now, see if we should add any obligations to the set + int effect = result.getDecision(); + + if ((effect == Result.DECISION_INDETERMINATE) + || (effect == Result.DECISION_NOT_APPLICABLE)) { + // we didn't permit/deny, so we never return obligations + return result; + } + + Iterator it = collectedObligations.iterator(); + while (it.hasNext()) { + Obligation obligation = it.next(); + if (obligation.getFulfillOn() == effect) { + result.addObligation(obligation.evaluate(context)); + } + } + // finally, return the result + return result; + } + + /** + * Routine used by Policy and PolicySet to + * encode the PolicyIssuer element. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + protected void encodePolicyIssuer(OutputStream output, + String charsetName, Indenter indenter) + throws UnsupportedEncodingException { + + if (this.policyIssuer != null) { + PrintStream out = new PrintStream(output); + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + Iterator>> it = this.policyIssuer.getAttributes().entrySet() + .iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + Iterator it2 = entry.getValue().iterator(); + while (it2.hasNext()) { + Attribute attr = it2.next(); + attr.encode(output, charsetName, indenter); + } + } + + out.println(indent + ""); + indenter.out(); + } + } + + + /** + * Routine used by Policy and PolicySet to + * encode some common elements. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + protected void encodeCommonElements(OutputStream output, + String charsetName, Indenter indenter) + throws UnsupportedEncodingException { + + for ( CombinerElement element : this.childElements ) { + element.encode(output, charsetName, indenter); + } + + if (this.obligations.size() != 0) { + PrintStream out = new PrintStream(output); + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + Iterator oblIt = this.obligations.iterator(); + while (oblIt.hasNext()) { + oblIt.next().encode(output, charsetName, indenter); + } + + out.println(indent + ""); + indenter.out(); + } + } + + /** + * Method for checking if a policy was issued by the trusted issuer + * + * @return True if the PolicyIssuer is the trusted issuer + */ + public boolean hasTrustedIssuer() { + if (this.policyIssuer == null) { + return true; + } + return false; + } + + /** + * Method for getting the issue date of this policy, if it was set in the + * policyIssuer member. Returns null if it has not been set. + * + * @return the date at which this policy was issued or null. + */ + public Date getIssueDate() { + if (this.policyIssuer != null) { + return this.policyIssuer.getIssueDate(); + } + return null; + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + +// public void setSourceLocator(RuntimeInfo src) { +// this.src = src; +// } + + /** + * Returns a copy of this abstract policy with a new isser. + * This is useful when policies are rewritten, for instance after + * a digital signature is verified, in which case the issuer + * is generated based on the signature of the policy. + * Also useful for implementing some models of revocation. + * + * @param issuer The new policy issuer. + * @return A identical copy of the abstract policy with + * a new issuer. + */ + public AbstractPolicy copyWithNewPolicyIssuer(PolicyIssuer issuer) { + AbstractPolicy newPolicy = (AbstractPolicy)clone(); + newPolicy.policyIssuer = issuer; + return newPolicy; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/BasicEvaluationCtx.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/BasicEvaluationCtx.java new file mode 100644 index 0000000..12632af --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/BasicEvaluationCtx.java @@ -0,0 +1,1154 @@ +/* + * @(#)BasicEvaluationCtx.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DecisionAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TimeAttribute; + +import com.sun.xacml.cond.EvaluationResult; + +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.ctx.RequestCtx; +import com.sun.xacml.ctx.RequestElement; +import com.sun.xacml.ctx.Result; + +import com.sun.xacml.finder.AttributeFinder; +import com.sun.xacml.finder.RevocationFinder; +import com.sun.xacml.reduction.ReductionGraph; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; + + +/** + * A basic implementation of EvaluationCtx that is created from + * an XACML Request and falls back on an AttributeFinder if a requested + * value isn't available in the Request. + *

    + * Note that this class can do some optional caching for current date, time, + * and dateTime values (defined by a boolean flag to the constructors). The + * XACML specification requires that these values always be available, but it + * does not specify whether or not they must remain constant over the course + * of an evaluation if the values are being generated by the PDP (if the + * values are provided in the Request, then obviously they will remain + * constant). The default behavior is for these environment values to be + * cached, so that (for example) the current time remains constant over the + * course of an evaluation. + * + * @since 1.2 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class BasicEvaluationCtx implements EvaluationCtx, Cloneable +{ + /** + * the finder to use if a value isn't in the request + */ + private AttributeFinder aFinder; + + /** + * flag that indicates if the attribute finder is deactivated. + */ + private boolean afinderActive = true; + + /** + * the revocation finder to use + */ + private RevocationFinder rFinder; + + /** + * flag that indicates if the revocation finder is deactivated. + */ + private boolean rfinderActive = true; + /** + * the DOM root the original RequestContext document. + */ + private Node requestRoot; + + /** + * The request data. A map of Sets of + * RequestElements keyed by the attribute category + * Strings. + */ + private HashMap> requestElements = null; + + /** + * the cached delegation decision value + */ + private int delegationDecision; + + /** + * the delegation depth value + */ + private int delegationDepth; + + /** + * the resource id + */ + private AttributeValue resourceId; + + /** + * the Set of RequestElements containing + * only the attributes that should be included in the result. + */ + private Set includedAttributes; + + /** + * the resource scope + */ + private int scope; + + /** + * the cached current date, which we may or may + * not be using depending on how this object was constructed + */ + private DateAttribute currentDate; + + /** + * the cached current time, which we may or may + * not be using depending on how this object was constructed + */ + private TimeAttribute currentTime; + + /** + * the cached current dateTime, which we may or may + * not be using depending on how this object was constructed + */ + private DateTimeAttribute currentDateTime; + + /** + * a flag indicating that we should use the cached date/time values. + */ + private boolean useCachedEnvValues; + + /** + * a stack of parent PolicySets. + */ + private Stack parentPolicySets; + + /** + * a stack of ReductionGraphs. + */ + private Stack reductionGraphs; + + /** + * the set of deactivated policies + */ + private Set inactivePolicyIds; + + /** + * the logger we'll use for all messages + */ + private static final Logger logger = + Logger.getLogger(BasicEvaluationCtx.class.getName()); + + /** + * Constructs a new BasicEvaluationCtx based on the given + * request. The resulting context will cache current date, time, and + * dateTime values so they remain constant for this evaluation. + * + * @param request the request + * + * @throws ParsingException if a required attribute is missing, or if there + * are any problems dealing with the request data + */ + public BasicEvaluationCtx(RequestCtx request) + throws ParsingException { + this(request, null, null, true); + } + + /** + * Constructs a new BasicEvaluationCtx based on the given + * request. + * + * @param request the request + * @param cacheEnvValues whether or not to cache the current time, date, + * and dateTime so they are constant for the scope + * of this evaluation + * + * @throws ParsingException if a required attribute is missing, or if there + * are any problems dealing with the request data + */ + public BasicEvaluationCtx(RequestCtx request, boolean cacheEnvValues) + throws ParsingException { + this(request, null, null, cacheEnvValues); + } + + /** + * Constructs a new BasicEvaluationCtx based on the given + * request, and supports looking outside the original request for attribute + * values using the AttributeFinder. The resulting context + * will cache current date, time, and dateTime values so they remain + * constant for this evaluation. + * + * @param request the request + * @param aFinder an AttributeFinder to use in looking for + * attributes that aren't in the request + * @param rFinder an RevocationFinder to use in looking for + * revocations + * + * @throws ParsingException if a required attribute is missing, or if there + * are any problems dealing with the request data + */ + public BasicEvaluationCtx(RequestCtx request, AttributeFinder aFinder, + RevocationFinder rFinder) + throws ParsingException { + this(request, aFinder, rFinder, true); + } + + /** + * Constructs a new BasicEvaluationCtx based on the given + * request, and supports looking outside the original request for attribute + * values using the AttributeFinder. + * + * @param request the request + * @param aFinder an AttributeFinder to use in looking for + * @param rFinder an RevocationFinder to use in looking for + * revocations + * attributes that aren't in the request + * @param cacheEnvValues whether or not to cache the current time, date, + * and dateTime so they are constant for the scope + * of this evaluation + * + * @throws ParsingException if a required attribute is missing, or if there + * are any problems dealing with the request data + */ + public BasicEvaluationCtx(RequestCtx request, AttributeFinder aFinder, + RevocationFinder rFinder, + boolean cacheEnvValues) + throws ParsingException { + // keep track of the attribute finder + this.aFinder = aFinder; + // keep track of the revocation finder + this.rFinder = rFinder; + + // remember the root of the DOM tree for XPath queries + this.requestRoot = request.getDocumentRoot(); + + // initialize the cached date/time values so it's clear we haven't + // retrieved them yet + this.useCachedEnvValues = cacheEnvValues; + this.currentDate = null; + this.currentTime = null; + this.currentDateTime = null; + + // parse the request elements into a map + // and collect the IncludeInResult attributes + this.requestElements = new HashMap>(); + this.includedAttributes = new HashSet(); + Iterator iter = request.getRequestElements().iterator(); + while (iter.hasNext()){ + RequestElement re = iter.next(); + URI category = re.getCategory(); + if (!re.getIncludeInResultSet().isEmpty()) { + this.includedAttributes.add(new RequestElement( + re.getCategory(), re.getIncludeInResultSet())); + } + if (this.requestElements.containsKey(category)) { + this.scope = Constants.SCOPE_MULTIPE_ELEMENTS; + Set set = this.requestElements.get(category); + set.add(re); + } else { + Set set = new HashSet(); + set.add(re); + this.requestElements.put(category, set); + } + } + + //Compatibility code for XACML 2.0 requestId handling + if (request.getXACMLVersion() < Constants.XACML_VERSION_3_0 + && !this.includedAttributes.isEmpty()) { + throw new ParsingException("Can't have included attributes" + + " in XACML < v 3.0"); + } + + //Compatibility code for old Resource handling. + if (this.requestElements.containsKey(Constants.RESOURCE_CAT)) { + Iterator reIt = this.requestElements.get( + Constants.RESOURCE_CAT).iterator(); + while(reIt.hasNext()) { + RequestElement re = (RequestElement)reIt.next(); + checkResource(re.getAttributes()); + } + } + + //this will only be set in administrative requests. + this.delegationDecision = Result.INVALID_DECISION; + this.delegationDepth = 0; + + this.parentPolicySets = new Stack(); + this.reductionGraphs = new Stack(); + + // this is empty when the evaluation context is first created + // it is used during the reduction of untrusted policies + this.inactivePolicyIds = new HashSet(); + } + + /** + * The clone method + * + * @return a copy of this object. + * + */ + public Object clone() { + try { + BasicEvaluationCtx clone = (BasicEvaluationCtx)super.clone(); + if (this.aFinder != null) { + clone.aFinder = (AttributeFinder)this.aFinder.clone(); + } + clone.afinderActive = this.afinderActive; + if(this.rFinder != null) { + clone.rFinder = (RevocationFinder)this.rFinder.clone(); + } + clone.rfinderActive = this.rfinderActive; + if(this.requestRoot != null) { + clone.requestRoot = this.requestRoot.cloneNode(true); + } else { + clone.requestRoot = null; + } + + // deep copy of the requestElements + clone.requestElements = new HashMap>(); + Iterator iter = this.requestElements.keySet().iterator(); + while(iter.hasNext()) { + URI key = URI.create(iter.next().toString()); + Set res = new HashSet(); + Iterator iter2 = this.requestElements.get(key).iterator(); + while(iter2.hasNext()) { + res.add((RequestElement)iter2.next().clone()); + } + clone.requestElements.put(key, res); + } + + clone.delegationDecision = this.delegationDecision; + clone.delegationDepth = this.delegationDepth; + clone.resourceId = this.resourceId; + + //deep copy of the included attributes + clone.includedAttributes = new HashSet(); + Iterator iter3 = this.includedAttributes.iterator(); + while(iter3.hasNext()) { + RequestElement element = iter3.next(); + clone.includedAttributes.add( (RequestElement) element.clone()); + } + synchronized (clone) { + clone.scope = this.scope; + clone.currentDate = this.currentDate; + clone.currentTime = this.currentTime; + clone.currentDateTime = this.currentDateTime; + clone.useCachedEnvValues = this.useCachedEnvValues; + } + //clone.parentPolicySets = (Stack) this.parentPolicySets.clone(); // + clone.parentPolicySets = new Stack(); + Collections.copy(parentPolicySets, this.parentPolicySets); + //clone.reductionGraphs = (Stack) this.reductionGraphs.clone(); + clone.reductionGraphs = new Stack(); + Collections.copy(reductionGraphs, this.reductionGraphs); + clone.inactivePolicyIds = new HashSet(this.inactivePolicyIds); + return clone; + } catch (CloneNotSupportedException e) {//This should never happen + throw new RuntimeException("Couldn't clone BasicEvaluationCtx"); + } + } + + /** + * Create a context for an administrative request from this context. + * + * @param decision The decision code corresponding to those in the + * Result class. + * @param delegate The delegate in this request (a set containing a + * single RequestElement). + * + * @return An administrative context for this context. + */ + public EvaluationCtx createAdminCtx(int decision, Set delegate) { + if (decision == Result.INVALID_DECISION + || decision == Result.DECISION_INDETERMINATE + || decision == Result.DECISION_NOT_APPLICABLE) { + throw new ProcessingException("Invalid decision value for an" + + " administrative request"); + } + + //First copy the old context. + BasicEvaluationCtx adminCtx = null; + adminCtx = (BasicEvaluationCtx)this.clone(); + + //Now set the new values ... + adminCtx.delegationDecision = decision; + adminCtx.delegationDepth = this.delegationDepth + 1; + + //... and modify the requestElements accordingly + HashMap> newREmap = new HashMap>(); + + //get out the delegation relevant information + // and remove the old + adminCtx.requestElements.remove(Constants.DELEGATION_INFO); + adminCtx.requestElements.remove(Constants.DELEGATE); + + //modify the rest so category * becomes category + // urn:oasis:names:tc:xacml:3.0:attribute-category:delegated:* + Iterator>> iter = adminCtx.requestElements.entrySet().iterator(); + while(iter.hasNext()) { + Map.Entry> entry = iter.next(); + Set requestElementCategory = entry.getValue(); + Iterator iter2 = requestElementCategory.iterator(); + HashSet newREset = new HashSet(); + URI category = null; + while(iter2.hasNext()) { + RequestElement oldRe = iter2.next(); + category = oldRe.getCategory(); + if (category.toString().startsWith(Constants.DELEGATED)) { + newREset.add(oldRe); + } else { // add the delegated part to the category + category = URI.create(Constants.DELEGATED + + category.toString()); + // this URI must be valid, since the old category was + RequestElement newRe = new RequestElement(category, + oldRe.getAttributes()); + newREset.add(newRe); + } + } + newREmap.put(category, newREset); + } + + //put in the new delegate + newREmap.put(Constants.DELEGATE, delegate); + + //put in the new delegation info + + // then create the correct DelegationInfo category + DecisionAttribute delegationDecision = new DecisionAttribute(decision); + Set delegationInfoAttrs = new HashSet(); + delegationInfoAttrs.add(delegationDecision); + RequestElement delegationInfo = new RequestElement( + Constants.DELEGATION_INFO, delegationInfoAttrs); + Set delegationInfoSet = new HashSet(); + delegationInfoSet.add(delegationInfo); + // and put it into the new request elements map + newREmap.put(Constants.DELEGATION_INFO, delegationInfoSet); + + //now we are done, copy the newREmap to the requestElements + adminCtx.requestElements = newREmap; + + return adminCtx; + } + + /** + * Creates a copy of this context with disabled attribute finder. + * + * @return A copy of this context with disabled attribute finder. + */ + public EvaluationCtx copyWithoutAttributeFinder() { + BasicEvaluationCtx ctx = (BasicEvaluationCtx)this.clone(); + ctx.aFinder = null; + ctx.afinderActive = false; + return ctx; + } + + /** + * This basically does the same thing that the other types need + * to do, except that we also look for a resource-id attribute, not + * because we're going to use, but only to make sure that it's not + * double, and for the optional scope attribute, to see what the scope + * of the attribute is. + * + * @param resourceAttr A Map keyed by attribute id + * URIs, containing Sets + * of Attributes. + * @param xacmlVersion The XACML version number. + * + * @throws ParsingException + * + */ + private void checkResource(Map> resourceAttr) + throws ParsingException { + + // make sure there's only one value for resource-id + Set rSet = resourceAttr.get(Constants.RESOURCE_ID); + if (rSet != null) { + if (rSet.size() > 1) { + System.err.println("Resource may contain " + + "only one resource-id Attribute"); + throw new ParsingException("too many resource-id attrs"); + } + // keep track of the resource-id attribute + this.resourceId = ((Attribute)(rSet.iterator().next())) + .getValue(); + } + + + // see if a resource-scope attribute was included + if (resourceAttr.containsKey(Constants.RESOURCE_SCOPE)) { + Set set = resourceAttr.get(Constants.RESOURCE_SCOPE); + + // make sure there's only one value for resource-scope + if (set.size() > 1) { + System.err.println("Resource may contain " + + "only one resource-scope Attribute"); + throw new ParsingException("too many resource-scope attrs"); + } + + Attribute attr = (Attribute)(set.iterator().next()); + AttributeValue attrValue = attr.getValue(); + + // scope must be a string, so throw an exception otherwise + if (! attrValue.getType().toString(). + equals(StringAttribute.identifier)) { + throw new ParsingException("scope attr must be a string"); + } + + String value = ((StringAttribute)attrValue).getValue(); + + if (value.equals("Immediate")) { + this.scope = Constants.SCOPE_IMMEDIATE; + } else if (value.equals("Children")) { + this.scope = Constants.SCOPE_CHILDREN; + } else if (value.equals("Descendants")) { + this.scope = Constants.SCOPE_DESCENDANTS; + } else if (value.equals("XPath-expression")) { + this.scope = Constants.SCOPE_XPATH_EXPRESSION; + } else if (value.equals("EntireHierarchy")) { + this.scope = Constants.SCOPE_ENTIRE_HIERARCHY; + } else { + System.err.println("Unknown scope type: " + value); + throw new ParsingException("invalid scope type: " + value); + } + } else { + // by default, the scope is always Immediate + this.scope = Constants.SCOPE_IMMEDIATE; + } + } + + /** + * Returns the DOM root of the original RequestType XML document. + * + * @return the DOM root node + */ + public Node getRequestRoot() { + return this.requestRoot; + } + + /** + * Returns the resource scope of the request, which will be one of the + * three fields denoting Immediate, Children, or Descendants. + * + * @return the scope of the resource in the request + */ + public int getScope() { + return this.scope; + } + + /** + * Returns the resource named in the request as resource-id. + * + * @return the resource + */ + public AttributeValue getResourceId() { + return this.resourceId; + } + + /** + * @return The Set of RequestElements + * representing the included attributes. + */ + public Set getIncludedAttributes() { + return this.includedAttributes; + } + + /** + * Changes the value of the resource-id attribute in this context. This + * is useful when you have multiple resources (ie, a scope other than + * IMMEDIATE), and you need to keep changing only the resource-id to + * evaluate the different effective requests. + * + * @param resourceId the new resource-id value + */ + public void setResourceId(AttributeValue resourceId) { + this.resourceId = resourceId; + + // there will always be exactly one value for this attribute + Iterator rIt = this.requestElements.get(Constants.RESOURCE_CAT).iterator(); + while (rIt.hasNext()) { + RequestElement re = rIt.next(); + Map> attrMap = re.getAttributes(); + Set resId = attrMap.get(Constants.RESOURCE_ID); + Attribute attr = (Attribute)(resId.iterator().next()); + // remove the old value... + resId.remove(attr); + Attribute newAttr = new Attribute(attr.getId(), attr.getIssuer(), + resourceId, + attr.getVersion(), + attr.includeInResult()); + // if it was marked to be included in the result remove this too + if (attr.includeInResult()) { + Iterator iter = this.includedAttributes.iterator(); + while (iter.hasNext()) { + RequestElement ire = iter.next(); + if (ire.getCategory().equals(Constants.RESOURCE_CAT)) { + this.includedAttributes.remove(ire); + Map> newAttrs = new HashMap>(); + newAttrs.putAll(ire.getAttributes()); + newAttrs.remove(Constants.RESOURCE_ID); + Set newResourceId = new HashSet(); + newResourceId.add(newAttr); + newAttrs.put(Constants.RESOURCE_ID, newResourceId); + this.includedAttributes.add(new RequestElement( + ire.getCategory(), newAttrs)); + } + } + } + // ...and insert the new value + resId.add(newAttr); + } + } + + /** + * Returns the value for the current time. The current time, current + * date, and current dateTime are consistent, so that they all + * represent the same moment. If this is the first time that one + * of these three values has been requested, and caching is enabled, + * then the three values will be resolved and stored. + *

    + * Note that the value supplied here applies only to dynamically + * resolved values, not those supplied in the Request. In other words, + * this always returns a dynamically resolved value local to the PDP, + * even if a different value was supplied in the Request. This is + * handled correctly when the value is requested by its identifier. + * + * @return the current time + */ + public synchronized TimeAttribute getCurrentTime() { + long millis = dateTimeHelper(); + if (this.useCachedEnvValues) { + return this.currentTime; + } + return new TimeAttribute(new Date(millis)); + } + + /** + * Returns the value for the current date. The current time, current + * date, and current dateTime are consistent, so that they all + * represent the same moment. If this is the first time that one + * of these three values has been requested, and caching is enabled, + * then the three values will be resolved and stored. + *

    + * Note that the value supplied here applies only to dynamically + * resolved values, not those supplied in the Request. In other words, + * this always returns a dynamically resolved value local to the PDP, + * even if a different value was supplied in the Request. This is + * handled correctly when the value is requested by its identifier. + * + * @return the current date + */ + public synchronized DateAttribute getCurrentDate() { + long millis = dateTimeHelper(); + + if (this.useCachedEnvValues) { + return this.currentDate; + } + return new DateAttribute(new Date(millis)); + } + + /** + * Returns the value for the current dateTime. The current time, current + * date, and current dateTime are consistent, so that they all + * represent the same moment. If this is the first time that one + * of these three values has been requested, and caching is enabled, + * then the three values will be resolved and stored. + *

    + * Note that the value supplied here applies only to dynamically + * resolved values, not those supplied in the Request. In other words, + * this always returns a dynamically resolved value local to the PDP, + * even if a different value was supplied in the Request. This is + * handled correctly when the value is requested by its identifier. + * + * @return the current dateTime + */ + public synchronized DateTimeAttribute getCurrentDateTime() { + long millis = dateTimeHelper(); + + if (this.useCachedEnvValues) { + return this.currentDateTime; + } + return new DateTimeAttribute(new Date(millis)); + } + + /** + * Private helper that figures out if we need to resolve new values, + * and returns either the current moment (if we're not caching) or + * -1 (if we are caching) + * + * @return returns the current moment or -1. + */ + private long dateTimeHelper() { + // if we already have current values, then we can stop (note this + // always means that we're caching) + if (this.currentTime != null) { + return -1; + } + + // get the current moment + Date time = new Date(); + long millis = time.getTime(); + + // if we're not caching then we just return the current moment + if (! this.useCachedEnvValues) { + return millis; + } + // we're caching, so resolve all three values, making sure + // to use clean copies of the date object since it may be + // modified when creating the attributes + this.currentTime = new TimeAttribute(time); + this.currentDate = new DateAttribute(new Date(millis)); + this.currentDateTime = new DateTimeAttribute(new Date(millis)); + + return -1; + } + + /** + * Return available attribute values of the selected category. + * + * @param category the category the attribute value(s) must be in + * @param type the type of the attribute value(s) to find + * @param id the id of the attribute value(s) to find + * @param issuer the issuer of the attribute value(s) to find or null + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult getAttribute(URI category, URI type, URI id, + URI issuer) { + Set elements = this.requestElements.get(category); + if (elements == null) { + elements = RequestElement.EMPTY_SET; + } + return getGenericAttributes(category, type, id, issuer, + elements, false); + } + + /** + * Helper function for the resource, action, environment and delegate + * methods to get an attribute. + * + * @param category the category the attribute value(s) must be in + * @param type the type of the attribute value(s) to find + * @param id the id of the attribute value(s) to find + * @param issuer the issuer of the attribute value(s) to find or null + * @param elements a set of RequestElements to search for + * the requested attribute. + * @param local get only local attributes, don't call the + * AttributeFinder. + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result. + * + */ + private EvaluationResult getGenericAttributes(URI category, URI type, + URI id, URI issuer, Set elements, boolean local) { + + Iterator iter = elements.iterator(); + Set attrSet = new HashSet(); + while (iter.hasNext()) { + RequestElement element = iter.next(); + // try to find the id + Map> map = element.getAttributes(); + if (map.containsKey(id)) { + attrSet.addAll(map.get(id)); + } + } + + if (attrSet.isEmpty()) { + if (local) { + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + // the request didn't have an attribute with that id, so we should + // try asking the attribute finder + return callHelper(category, type, id, issuer, elements); + } + + // now go through each, considering each Attribute object + List attributes = new ArrayList(); + Iterator it = attrSet.iterator(); + + while (it.hasNext()) { + Attribute attr = it.next(); + + // make sure the type and issuer are correct + if ((attr.getValue().getType().equals(type)) && + ((issuer == null) || + ((attr.getIssuer() != null) && + (attr.getIssuer().equals(issuer.toString()))))) { + + // if we got here, then we found a match, so we want to pull + // out the values and put them in out list + attributes.add(attr.getValue()); + } + } + + // see if we found any acceptable attributes + if (attributes.size() == 0) { + if (local) { + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + // we failed to find any that matched the type/issuer, or all the + // Attribute types were empty...so ask the finder +// if (logger.isLoggable(Level.FINE)) { +// logger.fine("Attribute not in request: " + id.toString() + +// " ... querying AttributeFinder"); +// } + if (logger.isDebugEnabled()) { + logger.debug("Attribute not in request: " + id.toString() + " category " + category + + " ... querying AttributeFinder"); + } + + return callHelper(category, type, id, issuer, elements); + } + + // if we got here, then we found at least one useful AttributeValue + return new EvaluationResult(new BagAttribute(type, attributes)); + } + + /** + * Protected helper that calls the finder if it's non-null, or else returns + * an empty bag. (Proctected so it can be overridden by subclasses). + * + * @param category the category the attribute value(s) must be in or null + * @param type the type of the attribute value(s) to find or null + * @param id the id of the attribute value(s) to find or null + * @param issuer the issuer of the attribute value(s) to find or null + * @param elements a set of RequestElements to search for the + * requested attribute. + * + * @return an EvaluationResult containing the requested + * attribute or an empty bag. + */ + protected EvaluationResult callHelper(URI category, URI type, URI id, + URI issuer, Set elements) { + if (this.aFinder != null) { + return this.aFinder.findAttribute(category, type, id, issuer, + this); + } + if (this.afinderActive) { + logger.warn("Context tried to invoke AttributeFinder but was " + + "not configured with one"); + } + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + + /** + * Returns the attribute value(s) retrieved using the given XPath + * expression. + * + * @param contextPath the XPath expression to search + * @param namespaceNode the DOM node defining namespace mappings to use, + * or null if mappings come from the context root + * @param type the type of the attribute value(s) to find + * @param xpathVersion the version of XPath to use + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult getAttribute(String contextPath, + Node namespaceNode, URI type, + String xpathVersion) { + if (this.aFinder != null) { + return this.aFinder.findAttribute(contextPath, namespaceNode, + type, this, xpathVersion); + } + logger.warn("Context tried to invoke AttributeFinder but was " + + "not configured with one"); + + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + + /** + * Get the decision. + * + * @return The int value of the decision according to + * the Result class. + */ + public int getDecision() { + return this.delegationDecision; + } + + /** + * Get the delegation depth. + * + * @return The int value specifying the number of nodes + * in the reduction graph until now (not including this one). + */ + public int getDelegationDepth() { + return this.delegationDepth; + } + + /** + * Get a whole category. + * + * @param category The name of the category. If the category does + * not exist return an empty set + * + * @return The Set of RequestElements with + * the matching category. + */ + public Set getCategory(URI category) { + if (this.requestElements.containsKey(category)) { + return new HashSet(this.requestElements.get(category)); + } + return RequestElement.EMPTY_SET; + } + + /** + * @return the Set of RequestElements + * containing the attributes that should be included + * in the result. + */ + public Set getIncludedAttrs() { + return this.includedAttributes; + } + + /** + * @return the Map of RequestElements + * defining this request. + */ + public Map> getRequestElements() { + return Collections.unmodifiableMap(this.requestElements); + } + + /** + * Save the parent PolicySet in this evaluation context + * for doing reduction of delegated policies if that becomes necessary. + * + * @param pps the parent policy set + */ + public void saveParentPolicySet(AbstractPolicy pps) { + if (pps instanceof PolicySet) { + this.parentPolicySets.push(pps); + } else if (pps instanceof PolicyReference) { + PolicyReference pr = (PolicyReference)pps; + if (pr.getReferenceType() != PolicyReference.POLICYSET_REFERENCE) { + //this should never happen + throw new RuntimeException("Tried to save a Reference " + + "to a Policy as a PolicySet"); + } + this.parentPolicySets.push(pps); + } else { + throw new RuntimeException("Tried to save " + + this.getClass().getName() + " as a PolicySet"); + } + } + + + /** + * Create a reduction graph for the current parent PolicySet. + * + */ + public void createReductionGraph() { + this.reductionGraphs.push(new ReductionGraph(getParentPolicySet())); + } + + + /** + * @return The current reduction graph or null if there is none. + */ + public ReductionGraph getReductionGraph() { + if (this.reductionGraphs != null && !this.reductionGraphs.empty()) { + return (ReductionGraph)this.reductionGraphs.peek(); + } + return null; + } + + /** + * Remove the current ReductionGraph from the stack. + */ + public void popReductionGraph() { + if (!this.reductionGraphs.isEmpty()) { + this.reductionGraphs.pop(); + } + } + + /** + * Returns the root PolicySet for this evaluation context. + * If there is none, return null. + * + * @return the root policy set or null. + */ + public AbstractPolicy getParentPolicySet() { + if (!this.parentPolicySets.empty()) { + return (AbstractPolicy) this.parentPolicySets.peek(); + } + return null; + } + + /** + * Remove the current parent PolicySet from the stack + * of parent policy sets. + */ + public void popParentPolicySet() { + if (!this.parentPolicySets.isEmpty()) { + this.parentPolicySets.pop(); + } + } + + /** + * Checks whether a Policy or PolicySet + * supports a revocation of a specific Policy of PolicySet + * in this context. + * + * @param supporting The policy or policy set that could support + * a revocation. + * @param candidate The id of the policy or policy set that is candidate + * for revocation. + * + * @return true if the policy/policy set supports a revocation, + * false otherwise. + */ + public boolean supportsRevocation(AbstractPolicy supporting, + URI candidate) { + if (this.rFinder != null && this.rfinderActive) { + //deactivate revocation finder to avoid infinite loops + // of policies revoking themselves + this.rfinderActive = false; + boolean result = this.rFinder.supportsRevocation(supporting, + candidate, this); + this.rfinderActive = true; + return result; + } + // since there is no revocation finder, no policy can be + // revoked. + logger.warn("Context tried to invoke RevocationFinder but was " + + "not configured with one"); + return false; + } + + /** + * Add new inactive PolicyId to the Map + * @param policyId the id of the new inactive policy + */ + public void addInactivePolicyId(URI policyId) { + this.inactivePolicyIds.add(policyId); + } + + /** + * Return an unmodifiable Set of URIs of + * inactive policies + * @return the inactive policies + */ + public Set getInactivePolicyIds() { + return Collections.unmodifiableSet( + new HashSet(this.inactivePolicyIds)); + } + + /** + * Signal a new event to this EvaluationCtx. + * BasicEvaluationCtx does nothing with this signal. + * + * @param element The new event. + */ + public void newEvent(Object element) { + //BasicEvaluationCtx does nothing with this signal. + } + + /** + * Signal that an event has finished and pass the result. + * BasicEvaluationCtx does nothing with this signal. + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(Result result) { + //BasicEvaluationCtx does nothing with this signal. + } + + /** + * Signal that an event has finished and pass the result. + * BasicEvaluationCtx does nothing with this signal. + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(MatchResult result) { + //BasicEvaluationCtx does nothing with this signal. + } + + /** + * Signal that an event has finished and pass the result + * which is a EvaluationResult + * BasicEvaluationCtx does nothing with this signal. + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(EvaluationResult result) { + //BasicEvaluationCtx does nothing with this signal. + } + + /** + * Signal that an event has finished with a String message. + * BasicEvaluationCtx does nothing with this signal. + * + * @param message The message. + */ + public void closeCurrentEvent(String message) { + //BasicEvaluationCtx does nothing with this signal. + } + + /** + * Signal that an event has finished with no result. + * BasicEvaluationCtx does nothing with this signal. + */ + public void closeCurrentEvent() { + //BasicEvaluationCtx does nothing with this signal. + } +} \ No newline at end of file diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ConfigurationStore.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ConfigurationStore.java new file mode 100644 index 0000000..f657cde --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ConfigurationStore.java @@ -0,0 +1,1408 @@ + +/* + * @(#)ConfigurationStore.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeFactoryProxy; +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.BaseAttributeFactory; +import com.sun.xacml.attr.StandardAttributeFactory; + +import com.sun.xacml.combine.BaseCombiningAlgFactory; +import com.sun.xacml.combine.CombiningAlgFactory; +import com.sun.xacml.combine.CombiningAlgFactoryProxy; +import com.sun.xacml.combine.CombiningAlgorithm; +import com.sun.xacml.combine.StandardCombiningAlgFactory; + +import com.sun.xacml.cond.BaseFunctionFactory; +import com.sun.xacml.cond.BasicFunctionFactoryProxy; +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.FunctionProxy; +import com.sun.xacml.cond.FunctionFactory; +import com.sun.xacml.cond.FunctionFactoryProxy; +import com.sun.xacml.cond.StandardFunctionFactory; + +import com.sun.xacml.cond.cluster.FunctionCluster; + +import com.sun.xacml.finder.AttributeFinder; +import com.sun.xacml.finder.AttributeFinderModule; +import com.sun.xacml.finder.PolicyFinder; +import com.sun.xacml.finder.PolicyFinderModule; +import com.sun.xacml.finder.RequiredAttributesModule; +import com.sun.xacml.finder.ResourceFinder; +import com.sun.xacml.finder.ResourceFinderModule; +import com.sun.xacml.finder.RevocationFinder; +import com.sun.xacml.finder.RevocationFinderModule; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * This class supports run-time loading of configuration data. It loads the + * configurations from an XML file that conforms to the configuration schema. + * By design this class does not get used automatically, nor does it change + * the state of the system directly. A programmer must choose to support this + * mechanism in their program, and then must explicitly use loaded elements. + * This way, the programmer still has full control over their security model, + * but also has the convenience of re-using a common configuration + * mechanism. See http://sunxacml.sourceforge.net/schema/config-0.4.xsd for + * the valid schema. + *

    + * Note that becuase this doesn't tie directly into the rest of the code, you + * are still free to design your own run-time configuration mechanisms. This + * is simply provided as a convenience, and so that all programmers can start + * from a common point. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ConfigurationStore +{ + + /** + * Property used to specify the configuration file. + */ + public static final String PDP_CONFIG_PROPERTY = + "com.sun.xacml.PDPConfigFile"; + + // pdp elements + private PDPConfig defaultPDPConfig; + private HashMap pdpConfigMap; + + // attribute factory elements + private AttributeFactory defaultAttributeFactory; + private HashMap attributeMap; + + // combining algorithm factory elements + private CombiningAlgFactory defaultCombiningFactory; + private HashMap combiningMap; + + // function factory elements + private FunctionFactoryProxy defaultFunctionFactoryProxy; + private HashMap functionMap; + + private Map customAttr = new HashMap(); + + // the classloader we'll use for loading classes + private ClassLoader loader; + +// // directory as base, where all files are searched +// @Deprecated +// private static String static_baseDir; +// + private String baseDir; + + public static final String BASEDIR = "BASEDIR"; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(ConfigurationStore.class.getName()); + + /** + * Default constructor. This constructor uses the + * PDP_CONFIG_PROPERTY property to load the configuration. + * If the property isn't set, if it names a file that can't be accessed, + * or if the file is invalid, then an exception is thrown. + * + * @throws ParsingException if anything goes wrong during the parsing + * of the configuration file, the class loading, + * or the factory and pdp setup + */ + public ConfigurationStore() throws ParsingException { + String configFile = System.getProperty(PDP_CONFIG_PROPERTY); + + // make sure that the right property was set + if (configFile == null) { + logger.warn("A property defining a config file was expected, " + + "but none was provided"); + + throw new ParsingException("Config property " + + PDP_CONFIG_PROPERTY + + " needs to be set"); + } + + try { + //setupConfig(new File(static_baseDir + configFile)); + setupConfig(new File(configFile)); + } catch (ParsingException pe) { + logger.error("Runtime config file (" + configFile + ") couldn't be loaded" + + " so no configurations will be available", pe); + throw pe; + } + } + + /** + * Constructor that explicitly specifies the configuration file to load. + * This is useful if your security model doesn't allow the use of + * properties, if you don't want to use a property to specify a + * configuration file, or if you want to use more then one configuration + * file. If the file can't be accessed, or if the file is invalid, then + * an exception is thrown. + * + * @param configFile The configuration file. + * + * @throws ParsingException if anything goes wrong during the parsing + * of the configuration file, the class loading, + * or the factory and pdp setup + */ + public ConfigurationStore(File configFile) throws ParsingException { + // if there is no baseDir, it is assumed that the rest of the + //configuration files are stored in the same directory as the confFile + // if there is no file.separator, baseDir is set to "" + String absPath = configFile.getAbsolutePath(); + String baseDir = absPath.substring(0, + absPath.lastIndexOf(System.getProperty("file.separator")) + 1 ); + init(configFile, baseDir); + } + + + /** + * Constructor that explicitly specifies the configuration file to load. + * This is useful if your security model doesn't allow the use of + * properties, if you don't want to use a property to specify a + * configuration file, or if you want to use more then one configuration + * file. If the file can't be accessed, or if the file is invalid, then + * an exception is thrown. + * + * @param configFile The configuration file. + * + * @throws ParsingException if anything goes wrong during the parsing + * of the configuration file, the class loading, + * or the factory and pdp setup + */ + public ConfigurationStore(File configFile, String baseDir) throws ParsingException { + init(configFile, baseDir); + } + + public ConfigurationStore(InputStream configFile, String baseDir) throws ParsingException { + init(configFile, baseDir); + } + + public ConfigurationStore(String configuration, Map customAttrs) throws ParsingException { + this.customAttr = customAttrs; + if ( customAttrs.containsKey(BASEDIR)) { + this.baseDir = (String) customAttrs.get(BASEDIR); + } + init(configuration); + } + + private void init(File configFile, String baseDir) throws ParsingException { + setBaseDir(baseDir); + try { + setupConfig(configFile); + } catch (ParsingException pe) { + logger.warn("Runtime config file (" + configFile + ")couldn't be loaded" + + " so no configurations will be available", pe); + throw pe; + } + } + + private void init(InputStream configFile, String baseDir) throws ParsingException { + setBaseDir(baseDir); + try { + setupConfig(configFile); + } catch (ParsingException pe) { + logger.warn("Runtime config file (" + configFile + ")couldn't be loaded" + + " so no configurations will be available", pe); + throw pe; + } + } + + protected void init(String configuration) throws ParsingException { + setBaseDir(""); + try { + setupConfig(configuration); + } catch (ParsingException pe) { + logger.warn("Runtime configuration couldn't be loaded" + + " so no configurations will be available (" + pe.getMessage() + ")", pe); + throw pe; + } + } + + private void setBaseDir(String baseDir) { + if ( baseDir == null ) { + baseDir = ""; + } + this.baseDir = baseDir; + customAttr.put(BASEDIR, baseDir); + } + + private void setupConfig(String configuration) throws ParsingException { + setupConfig(getRootNode(configuration)); + } + + private void setupConfig(InputStream configuration) throws ParsingException { + setupConfig(getRootNode(configuration)); + } + + private void setupConfig(File configFile) throws ParsingException { + setupConfig(getRootNode(configFile)); + } + + /** + * Private helper function used by both constructors to actually load the + * configuration data. This is the root of several private methods used + * to setup all the pdps and factories. + * + * @param configFile The configuration file. + * + * @throws ParsingException + */ + //private void setupConfig(File configFile) throws ParsingException { + private void setupConfig(Node root) throws ParsingException { + logger.info("Loading runtime configuration"); + + // load our classloader + this.loader = getClass().getClassLoader(); + + // get the root node from the configuration file + //Node root = getRootNode(configFile); + + // initialize all the maps + this.pdpConfigMap = new HashMap(); + this.attributeMap = new HashMap(); + this.combiningMap = new HashMap(); + this.functionMap = new HashMap(); + if ( customAttr == null ) { + this.customAttr = new HashMap(); + } + + // get the default names + NamedNodeMap attrs = root.getAttributes(); + String defaultPDP = attrs.getNamedItem("defaultPDP").getNodeValue(); + String defaultAF = getDefaultFactory(attrs, "defaultAttributeFactory"); + String defaultCAF = getDefaultFactory(attrs, + "defaultCombiningAlgFactory"); + String defaultFF = getDefaultFactory(attrs, "defaultFunctionFactory"); + + // loop through all the root-level elements, for each one getting its + // name and then loading the right kind of element + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + String childName = child.getNodeName(); + String elementName = null; + + // get the element's name + if (child.getNodeType() == Node.ELEMENT_NODE && + child.getAttributes().getNamedItem("name") != null ) { + elementName = child.getAttributes(). + getNamedItem("name").getNodeValue(); + } + + // see if this is a pdp or a factory, and load accordingly, + // putting the new element into the respective map...make sure + // that we're never loading something with the same name twice + if (childName.equals("pdp")) { + if (logger.isDebugEnabled()) { + logger.debug("Loading PDP: " + elementName); + } + if (this.pdpConfigMap.containsKey(elementName)) { + throw new ParsingException("more that one pdp with " + + "name \"" + elementName +"\""); + } + this.pdpConfigMap.put(elementName, parsePDPConfig(child)); + } else if (childName.equals("attributeFactory")) { + if (logger.isDebugEnabled()) { + logger.debug("Loading AttributeFactory: " + elementName); + } + if (this.attributeMap.containsKey(elementName)) { + throw new ParsingException("more that one " + + "attributeFactory with name " + + elementName +"\""); + } + this.attributeMap.put(elementName, + parseAttributeFactory(child)); + } else if (childName.equals("combiningAlgFactory")) { + if (logger.isDebugEnabled()) { + logger.debug("Loading CombiningAlgFactory: " + + elementName); + } + if (this.combiningMap.containsKey(elementName)) { + throw new ParsingException("more that one " + + "combiningAlgFactory with " + + "name \"" + elementName +"\""); + } + this.combiningMap.put(elementName, + parseCombiningAlgFactory(child)); + } else if (childName.equals("functionFactory")) { + if (logger.isDebugEnabled()) { + logger.debug("Loading FunctionFactory: " + elementName); + } + if (this.functionMap.containsKey(elementName)) { + throw new ParsingException("more that one functionFactory" + + " with name \"" + + elementName +"\""); + } + this.functionMap.put(elementName, parseFunctionFactory(child)); + } else { + //custom attribtue + if ( child.getNodeType() == Node.ELEMENT_NODE ) { + String key = null, value = null; + if ( child.getFirstChild() != null ) { + key = childName; + if ( child.getFirstChild().getNodeType() == Node.TEXT_NODE ) { + value = child.getFirstChild().getNodeValue().trim(); + } + } else { + NamedNodeMap foo = child.getAttributes(); + if (foo != null ) { + key = foo.getNamedItem("key").getNodeValue(); + value = foo.getNamedItem("value").getNodeValue(); + } + } + if ( key != null && value != null ) { + if (logger.isDebugEnabled()) { + logger.debug("Read custom attribute " + key + " with value " + value); + } + customAttr.put(key, value); + } + } + } + } + + // copy custom attributes to PDP configs + if ( customAttr.size() > 0 ) { + for (String pdpKey : this.pdpConfigMap.keySet()) { + pdpConfigMap.get(pdpKey).addCutomAttrs(customAttr); + } + } + + // finally, extract the default elements + this.defaultPDPConfig = (PDPConfig)(this.pdpConfigMap.get(defaultPDP)); + + this.defaultAttributeFactory = (AttributeFactory) + (this.attributeMap.get(defaultAF)); + if (this.defaultAttributeFactory == null) { + try { + this.defaultAttributeFactory = + AttributeFactory.getInstance(defaultAF); + } catch (Exception e) { + throw new ParsingException("Unknown AttributeFactory", e); + } + } + /* start hack: required to include datatypes configured in pdp configuration */ + AttributeFactoryProxy attrProxy = new AttributeFactoryProxy() { + public AttributeFactory getFactory() { + return defaultAttributeFactory; + } + }; + BaseAttributeFactory.setDefaultFactory(attrProxy); + /* end hack */ + + this.defaultCombiningFactory = (CombiningAlgFactory) + (this.combiningMap.get(defaultCAF)); + if (this.defaultCombiningFactory == null) { + try { + this.defaultCombiningFactory = + CombiningAlgFactory.getInstance(defaultCAF); + } catch (Exception e) { + throw new ParsingException("Unknown CombininAlgFactory", e); + } + } + + this.defaultFunctionFactoryProxy = (FunctionFactoryProxy) + (this.functionMap.get(defaultFF)); + if (this.defaultFunctionFactoryProxy == null) { + try { + this.defaultFunctionFactoryProxy = + FunctionFactory.getInstance(defaultFF); + } catch (Exception e) { + throw new ParsingException("Unknown FunctionFactory", e); + } + } + /* start hack: required to include functions configured in pdp configuration */ + BaseFunctionFactory.setDefaultFactory(defaultFunctionFactoryProxy); + /* end hack */ + } + + /** + * Private helper that gets a default factory identifier, or fills in + * the default value if no identifier is provided. + * + * @param attrs The XML-attributes of the configuration. + * @param factoryName The name of the default factory XML-attribute. + * + * @return The identifier of the default factory. + */ + private String getDefaultFactory(NamedNodeMap attrs, String factoryName) { + Node node = attrs.getNamedItem(factoryName); + if (node != null) { + return node.getNodeValue(); + } + return Constants.XACML_1_0_IDENTIFIER; + } + + private Node getRootNode(File configFile) throws ParsingException { + try { + return getRootNode(new FileInputStream(configFile)); + } catch(IOException ioe) { + throw new ParsingException("failed to load the file ", ioe); + } + } + + private Node getRootNode(InputStream configFile) throws ParsingException { + DocumentBuilder db = createDocumentBuilder(); + + Document doc = null; + try { + doc = db.parse(configFile); + } catch (IOException ioe) { + throw new ParsingException("failed to load the file ", ioe); + } catch (SAXException saxe) { + throw new ParsingException("error parsing the XML tree", saxe); + } catch (IllegalArgumentException iae) { + throw new ParsingException("no data to parse", iae); + } + + return getRootNode(doc); + } + + private Node getRootNode(String configuration) throws ParsingException { + DocumentBuilder db = createDocumentBuilder(); + + Document doc = null; + try { + doc = db.parse(new ByteArrayInputStream(configuration.getBytes())); + } catch (IOException ioe) { + throw new ParsingException("failed to load the configuration from string ", ioe); + } catch (SAXException saxe) { + throw new ParsingException("error parsing the XML tree", saxe); + } catch (IllegalArgumentException iae) { + throw new ParsingException("no data to parse", iae); + } + + return getRootNode(doc); + } + + private DocumentBuilder createDocumentBuilder() throws ParsingException { + DocumentBuilderFactory dbFactory = + DocumentBuilderFactory.newInstance(); + + dbFactory.setIgnoringComments(true); + dbFactory.setNamespaceAware(false); + dbFactory.setValidating(false); + + try { + return dbFactory.newDocumentBuilder(); + } catch (ParserConfigurationException pce) { + throw new ParsingException("couldn't get a document builder", pce); + } + } + + /** + * Private helper that parses the file and sets up the DOM tree. + * + * @param configFile The filename of the configuration file. + * + * @return The DOM-tree containing the configuration. + * + * @throws ParsingException + */ + //private Node getRootNode(File configFile) throws ParsingException { + private Node getRootNode(Document doc) throws ParsingException { + // DocumentBuilderFactory dbFactory = + // DocumentBuilderFactory.newInstance(); + // + // dbFactory.setIgnoringComments(true); + // dbFactory.setNamespaceAware(false); + // dbFactory.setValidating(false); + // + // DocumentBuilder db = null; + // try { + // db = dbFactory.newDocumentBuilder(); + // } catch (ParserConfigurationException pce) { + // throw new ParsingException("couldn't get a document builder", pce); + // } + // + // Document doc = null; + // try { + // doc = db.parse(new FileInputStream(configFile)); + // } catch (IOException ioe) { + // throw new ParsingException("failed to load the file ", ioe); + // } catch (SAXException saxe) { + // throw new ParsingException("error parsing the XML tree", saxe); + // } catch (IllegalArgumentException iae) { + // throw new ParsingException("no data to parse", iae); + // } + + Element root = doc.getDocumentElement(); + + if (! root.getTagName().equals("config")) { + throw new ParsingException("unknown document type: " + + root.getTagName()); + } + + return root; + } + + /** + * Private helper that handles the pdp elements. + * + * @param root The node containing the finder module class names. + * + * @return The PDP configuration object. + * + * @throws ParsingException + */ + private PDPConfig parsePDPConfig(Node root) throws ParsingException { + + // ArrayList attrModules = new ArrayList(); + // HashSet policyModules = new HashSet(); + // ArrayList rsrcModules = new ArrayList(); + // ArrayList revocationModules = new ArrayList(); + // + // PDPConfig pdpConfig = new PDPConfig(); + // + // // go through all elements of the pdp, loading the specified modules + // NodeList children = root.getChildNodes(); + // for (int i = 0; i < children.getLength(); i++) { + // Node child = children.item(i); + // String name = child.getNodeName(); + // + // if (name.equals("policyFinderModule")) { + // policyModules.add(loadClass("module", child)); + // } else if (name.equals("attributeFinderModule")) { + // attrModules.add(loadClass("module", child)); + // } else if (name.equals("resourceFinderModule")) { + // rsrcModules.add(loadClass("module", child)); + // } else if (name.equals("revocationFinderModule")) { + // revocationModules.add(loadClass("module", child)); + // } + // } + // + // // after loading the modules, use the collections to setup a + // // PDPConfig based on this pdp element + // + // AttributeFinder attrFinder = new AttributeFinder(); + // attrFinder.setModules(attrModules); + // + // PolicyFinder policyFinder = new PolicyFinder(); + // policyFinder.setModules(policyModules); + // + // ResourceFinder rsrcFinder = new ResourceFinder(); + // rsrcFinder.setModules(rsrcModules); + // + // RevocationFinder revocationFinder = new RevocationFinder(); + // revocationFinder.setModules(revocationModules); + // + // pdpConfig.setFinder(attrFinder, policyFinder, rsrcFinder, + // revocationFinder); + // + // return pdpConfig; + + + ArrayList attrModules = new ArrayList(); + HashSet policyModules = new HashSet(); + ArrayList rsrcModules = new ArrayList(); + ArrayList revocationModules = new ArrayList(); + ArrayList requiredAttrModules = new ArrayList(); + + // go through all elements of the pdp, loading the specified modules + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + String name = child.getNodeName(); + + if (name.equals("policyFinderModule")) { + policyModules.add((PolicyFinderModule)loadClass("module", child)); + } else if (name.equals("attributeFinderModule")) { + attrModules.add((AttributeFinderModule)loadClass("module", child)); + } else if (name.equals("resourceFinderModule")) { + rsrcModules.add((ResourceFinderModule)loadClass("module", child)); + } else if (name.equals("revocationFinderModule")) { + revocationModules.add((RevocationFinderModule)loadClass("module", child)); + } else if (name.equals("requiredAttributesModule")) { + requiredAttrModules.add((RequiredAttributesModule) loadClass("module", child)); + } + } + + // after loading the modules, use the collections to setup a + // PDPConfig based on this pdp element + + AttributeFinder attrFinder = new AttributeFinder(); + attrFinder.setModules(attrModules); + + PolicyFinder policyFinder = new PolicyFinder(); + policyFinder.setModules(policyModules); + + ResourceFinder rsrcFinder = new ResourceFinder(); + rsrcFinder.setModules(rsrcModules); + + RevocationFinder revocationFinder = new RevocationFinder(); + revocationFinder.setModules(revocationModules); + + AttributeDesignator.setRequiredAttrModules(requiredAttrModules); + + return new PDPConfig(attrFinder, policyFinder, rsrcFinder, + revocationFinder); + } + + /** + * Private helper that handles the attributeFactory elements. + * + * @param root The node containing the attribute factory definition. + * + * @return The attribute factory object. + * + * @throws ParsingException + */ + private AttributeFactory parseAttributeFactory(Node root) + throws ParsingException + { + AttributeFactory factory = null; + + // check if we're starting with the standard factory setup + if (useStandard(root, "useStandardDatatypes")) { + logger.debug("Starting with standard Datatypes"); + + factory = StandardAttributeFactory.getNewFactory(); + } else { + factory = new BaseAttributeFactory(); + } + + // now look for all datatypes specified for this factory, adding + // them as we go + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + + if (child.getNodeName().equals("datatype")) { + // a datatype is a class with an identifier + String identifier = child.getAttributes(). + getNamedItem("identifier").getNodeValue(); + AttributeProxy proxy = + (AttributeProxy)(loadClass("datatype", child)); + + try { + factory.addDatatype(identifier, proxy); + } catch (IllegalArgumentException iae) { + throw new ParsingException("duplicate datatype: " + + identifier, iae); + } + } + } + + return factory; + } + + /** + * Private helper that handles the combiningAlgFactory elements. + */ + private CombiningAlgFactory parseCombiningAlgFactory(Node root) + throws ParsingException + { + CombiningAlgFactory factory = null; + + // check if we're starting with the standard factory setup + if (useStandard(root, "useStandardAlgorithms")) { + logger.debug("Starting with standard Combining Algorithms"); + + factory = StandardCombiningAlgFactory.getNewFactory(); + } else { + factory = new BaseCombiningAlgFactory(); + } + CombiningAlgFactory.setAllFactories(factory); + + + // now look for all algorithms specified for this factory, adding + // them as we go + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + + if (child.getNodeName().equals("algorithm")) { + // an algorithm is a simple class element + CombiningAlgorithm alg = + (CombiningAlgorithm)(loadClass("algorithm", child)); + try { + factory.addAlgorithm(alg); + } catch (IllegalArgumentException iae) { + throw new ParsingException("duplicate combining " + + "algorithm: " + + alg.getIdentifier().toString(), + iae); + } + } + } + + return factory; + } + + /** + * Private helper that handles the functionFactory elements. This one + * is a little more complex than the other two factory helper methods, + * since it consists of three factories (target, condition, and general). + */ + private FunctionFactoryProxy parseFunctionFactory(Node root) + throws ParsingException + { + FunctionFactoryProxy proxy = null; + FunctionFactory generalFactory = null; + FunctionFactory conditionFactory = null; + FunctionFactory targetFactory = null; + + // check if we're starting with the standard factory setup, and + // make sure that the proxy is pre-configured + if (useStandard(root, "useStandardFunctions")) { + logger.debug("Starting with standard Functions"); + + proxy = StandardFunctionFactory.getNewFactoryProxy(); + + targetFactory = proxy.getTargetFactory(); + conditionFactory = proxy.getConditionFactory(); + generalFactory = proxy.getGeneralFactory(); + } else { + generalFactory = new BaseFunctionFactory(); + conditionFactory = new BaseFunctionFactory(generalFactory); + targetFactory = new BaseFunctionFactory(conditionFactory); + + proxy = new BasicFunctionFactoryProxy(targetFactory, + conditionFactory, + generalFactory); + } + + // go through and load the three sections, putting the loaded + // functions into the appropriate factory + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + String name = child.getNodeName(); + + if (name.equals("target")) { + logger.debug("Loading [TARGET] functions"); + functionParserHelper(child, targetFactory); + } else if (name.equals("condition")) { + logger.debug("Loading [CONDITION] functions"); + functionParserHelper(child, conditionFactory); + } else if (name.equals("general")) { + logger.debug("Loading [GENERAL] functions"); + functionParserHelper(child, generalFactory); + } + } + + return proxy; + } + + /** + * Private helper used by the function factory code to load a specific + * target, condition, or general section. + */ + private void functionParserHelper(Node root, FunctionFactory factory) + throws ParsingException + { + // go through all elements in the section + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + String name = child.getNodeName(); + + if (name.equals("function")) { + // a function section is a simple class element + Function function = + (Function)(loadClass("function", child)); + try { + factory.addFunction(function); + } catch (IllegalArgumentException iae) { + throw new ParsingException("duplicate function", iae); + } + } else if (name.equals("abstractFunction")) { + // an abstract function is a class with an identifier + URI identifier = null; + try { + identifier = new URI(child.getAttributes(). + getNamedItem("identifier"). + getNodeValue()); + } catch (URISyntaxException urise) { + throw new ParsingException("invalid function identifier", + urise); + } + + FunctionProxy proxy = + (FunctionProxy)(loadClass("abstract function", child)); + try { + factory.addAbstractFunction(proxy, identifier); + } catch (IllegalArgumentException iae) { + throw new ParsingException("duplicate abstract function", + iae); + } + } else if (name.equals("functionCluster")) { + // a cluster is a class that will give us a collection of + // functions that need to be added one by one into the factory + FunctionCluster cluster = + (FunctionCluster)(loadClass("function cluster", child)); + + Iterator it = cluster.getSupportedFunctions().iterator(); + while (it.hasNext()) { + try { + factory.addFunction(it.next()); + } catch (IllegalArgumentException iae) { + throw new ParsingException("duplicate function", iae); + } + } + } + } + } + + + + /** + * Private helper that is used by all the code to load an instance of + * the given class...this assumes that the class is in the classpath, + * both for simplicity and for stronger security + */ + protected Object loadClass(String prefix, Node root) + throws ParsingException + { + // get the name of the class + String className = + root.getAttributes().getNamedItem("class").getNodeValue(); + + if (logger.isDebugEnabled()) { + logger.debug("Loading [ " + prefix + ": " + className + " ]"); + } + + // load the given class using the local classloader + Class c = null; + try { + c = this.loader.loadClass(className); + } catch (ClassNotFoundException cnfe) { + throw new ParsingException("couldn't load class " + className, + cnfe); + } + Object instance = null; + + // figure out if there are any parameters to the constructor + if (root.hasChildNodes()) { + // parse the arguments to the constructor + List args = null; + try { + args = getArgs(root); + } catch (IllegalArgumentException iae) { + throw new ParsingException("illegal class arguments", iae); + } + int argLength = args.size(); + + // next we need to see if there's a constructor that matches the + // arguments provided...this has to be done by hand since + // Class.getConstructor(Class []) doesn't handle sub-classes and + // generic types (for instance, a constructor taking List won't + // match a parameter list containing ArrayList) + + // get the list of all available constructors + Constructor [] cons = c.getConstructors(); + Constructor constructor = null; + + for (int i = 0; i < cons.length; i++) { + // get the parameters for this constructor + Class [] params = cons[i].getParameterTypes(); + if (params.length == argLength) { + Iterator it = args.iterator(); + int j = 0; + + // loop through the parameters and see if each one is + // assignable from the coresponding input argument + while (it.hasNext()) { + if (! params[j].isAssignableFrom(it.next().getClass())) { + break; + } + j++; + } + + // if we looked at all the parameters, then this + // constructor matches the input + if (j == argLength) { + constructor = cons[i]; + } + } + + // if we've found a matching constructor then stop looping + if (constructor != null) { + break; + } + } + + // make sure we found a matching constructor + if (constructor == null) { + throw new ParsingException("couldn't find a matching " + + "constructor for " + c); + } + + // finally, instantiate the class + try { + instance = constructor.newInstance(args.toArray()); + } catch (InstantiationException ie) { + throw new ParsingException("couldn't instantiate " + className, + ie); + } catch (IllegalAccessException iae) { + throw new ParsingException("couldn't get access to instance " + + "of " + className, iae); + } catch (InvocationTargetException ite) { + throw new ParsingException("couldn't create " + className, + ite); + } + } else { + // we're using a null constructor, so this is easy + try { + instance = c.newInstance(); + } catch (InstantiationException ie) { + throw new ParsingException("couldn't instantiate " + className + + " with empty constructor", ie); + } catch (IllegalAccessException iae) { + throw new ParsingException("couldn't get access to instance " + + "of " + className, iae); + } + } + Method setConfigurationStore = null; + try { + setConfigurationStore = c.getMethod("setConfigurationStore", this.getClass()); + setConfigurationStore.invoke(instance, this); + //logger.debug("set ConfigurationStore to " + c); + } catch ( NoSuchMethodException e) { + logger.debug(c + " does not have a \"setConfigurationStore\" method to retreive the current configuration"); + } catch (Exception e) { + logger.debug("Error at setting the ConfigurationStore to " + c + ": " + e.getClass() + ": " + e.getMessage() + ")"); + e.printStackTrace(); + } + + return instance; + } + + /** + * Private helper that gets the constructor arguments for a given class. + * Right now this just supports String and List, but it's trivial to + * add support for other types should that be needed. Right now, it's not + * clear that there's any need for other types. + */ + private List getArgs(Node root) { + List args = new ArrayList(); + NodeList children = root.getChildNodes(); + + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + String name = child.getNodeName(); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + if (name.equals("string")) { + args.add(child.getFirstChild().getNodeValue()); + } else if (name.equals("list")) { + args.add(getArgs(child)); + } else { + throw new IllegalArgumentException("unkown arg type: " + + name); + } + } + } + return args; + } + + /** + * Private helper used by the three factory routines to see if the + * given factory should be based on the standard setup + */ + private boolean useStandard(Node node, String attributeName) { + NamedNodeMap map = node.getAttributes(); + if (map == null) { + return true; + } + + Node attrNode = map.getNamedItem(attributeName); + if (attrNode == null) { + return true; + } + + return attrNode.getNodeValue().equals("true"); + } + + /** + * Returns the default PDP configuration. If no default was specified + * then this throws an exception. + * + * @return the default PDP configuration + * + * @throws UnknownIdentifierException if there is no default config + */ + public PDPConfig getDefaultPDPConfig() throws UnknownIdentifierException { + if (this.defaultPDPConfig == null) { + throw new UnknownIdentifierException("no default available"); + } + + return this.defaultPDPConfig; + } + + /** + * Returns the PDP configuration with the given name. If no such + * configuration exists then an exception is thrown. + * + * @param name The name of the configuration. + * + * @return the matching PDP configuation + * + * @throws UnknownIdentifierException if the name is unknown + */ + public PDPConfig getPDPConfig(String name) + throws UnknownIdentifierException + { + Object object = this.pdpConfigMap.get(name); + + if (object == null) { + throw new UnknownIdentifierException("unknown pdp: " + name); + } + + return (PDPConfig)object; + } + + /** + * Returns a set of identifiers representing each PDP configuration + * available. + * + * @return a Set of Strings + */ + public Set getSupportedPDPConfigurations() { + return Collections.unmodifiableSet(this.pdpConfigMap.keySet()); + } + + /** + * Returns the default attribute factory. + * + * @return The default attribute factory. + */ + public AttributeFactory getDefaultAttributeFactory() { + return this.defaultAttributeFactory; + } + + /** + * Returns the attribute factory with the given name. If no such + * factory exists then an exception is thrown. + * + * @param name The name of the attribute factory. + * + * @return the matching attribute factory + * + * @throws UnknownIdentifierException if the name is unknown + */ + public AttributeFactory getAttributeFactory(String name) + throws UnknownIdentifierException + { + Object object = this.attributeMap.get(name); + + if (object == null) { + throw new UnknownIdentifierException("unknown factory: " + name); + } + + return (AttributeFactory)object; + } + + /** + * Returns a set of identifiers representing each attribute factory + * available. + * + * @return a Set of Strings + */ + public Set getSupportedAttributeFactories() { + return Collections.unmodifiableSet(this.attributeMap.keySet()); + } + + /** + * Registers all the supported factories with the given identifiers. If + * a given identifier is already in use, then that factory is not + * registered. This method is provided only as a convenience, and + * any registration that may involve identifier clashes should be done + * by registering each factory individually. + */ + public void registerAttributeFactories() { + Iterator it = this.attributeMap.keySet().iterator(); + + while (it.hasNext()) { + String id = it.next(); + AttributeFactory af = this.attributeMap.get(id); + + try { + AttributeFactory.registerFactory(id, new AFProxy(af)); + } catch (IllegalArgumentException iae) { + logger.warn("Couldn't register AttributeFactory:" + + id + " (already in use)", iae); + } + } + } + + /** + * Returns the default combiningAlg factory. + * + * @return the default combiningAlg factory + */ + public CombiningAlgFactory getDefaultCombiningAlgFactory() { + return this.defaultCombiningFactory; + } + + /** + * Returns the combiningAlg factory with the given name. If no such + * factory exists then an exception is thrown. + * + * @param name The name of the combining algorithm factory. + * + * @return the matching combiningAlg factory + * + * @throws UnknownIdentifierException if the name is unknown + */ + public CombiningAlgFactory getCombiningAlgFactory(String name) + throws UnknownIdentifierException + { + Object object = this.combiningMap.get(name); + + if (object == null) { + throw new UnknownIdentifierException("unknown factory: " + name); + } + + return (CombiningAlgFactory)object; + } + + /** + * Returns a set of identifiers representing each combiningAlg factory + * available. + * + * @return a Set of Strings + */ + public SetgetSupportedCombiningAlgFactories() { + return Collections.unmodifiableSet(this.combiningMap.keySet()); + } + + /** + * Registers all the supported factories with the given identifiers. If + * a given identifier is already in use, then that factory is not + * registered. This method is provided only as a convenience, and + * any registration that may involve identifier clashes should be done + * by registering each factory individually. + */ + public void registerCombiningAlgFactories() { + Iterator it = this.combiningMap.keySet().iterator(); + + while (it.hasNext()) { + String id = it.next(); + CombiningAlgFactory cf = this.combiningMap.get(id); + + try { + CombiningAlgFactory.registerFactory(id, new CAFProxy(cf)); + } catch (IllegalArgumentException iae) { + logger.warn("Couldn't register " + + "CombiningAlgFactory: " + id + " (already in use)", + iae); + } + } + } + + /** + * Returns the default function factory proxy. + * + * @return the default function factory proxy + */ + public FunctionFactoryProxy getDefaultFunctionFactoryProxy() { + return this.defaultFunctionFactoryProxy; + } + + /** + * Returns the function factory proxy with the given name. If no such + * proxy exists then an exception is thrown. + * + * @param name The name of the function factory proxy. + * + * @return the matching function factory proxy + * + * @throws UnknownIdentifierException if the name is unknown + */ + public FunctionFactoryProxy getFunctionFactoryProxy(String name) + throws UnknownIdentifierException + { + Object object = this.functionMap.get(name); + + if (object == null) { + throw new UnknownIdentifierException("unknown factory: " + name); + } + + return (FunctionFactoryProxy)object; + } + + /** + * Returns a set of identifiers representing each function factory proxy + * available. + * + * @return a Set of Strings + */ + public Set getSupportedFunctionFactories() { + return Collections.unmodifiableSet(this.functionMap.keySet()); + } + + /** + * Registers all the supported factories with the given identifiers. If + * a given identifier is already in use, then that factory is not + * registered. This method is provided only as a convenience, and + * any registration that may involve identifier clashes should be done + * by registering each factory individually. + */ + public void registerFunctionFactories() { + Iterator it = this.functionMap.keySet().iterator(); + + while (it.hasNext()) { + String id = it.next(); + FunctionFactoryProxy ffp = this.functionMap.get(id); + + try { + FunctionFactory.registerFactory(id, ffp); + } catch (IllegalArgumentException iae) { + logger.warn("Couldn't register FunctionFactory: " + + id + " (already in use)", iae); + } + } + } + + /** + * Uses the default configuration to re-set the default factories used + * by the system (attribute, combining algorithm, and function). If + * a default is not provided for a given factory, then that factory + * will not be set as the system's default. + */ + public void useDefaultFactories() { + logger.debug("Switching to default factories from configuration"); + + // set the default attribute factory, if it exists here + if (this.defaultAttributeFactory != null) { + AttributeFactory.setDefaultFactory( + new AFProxy(this.defaultAttributeFactory)); + } + + // set the default combining algorithm factory, if it exists here + if (this.defaultCombiningFactory != null) { + CombiningAlgFactory.setDefaultFactory( + new CAFProxy(this.defaultCombiningFactory)); + + } + + // set the default function factories, if they exists here + if (this.defaultFunctionFactoryProxy != null) { + FunctionFactory.setDefaultFactory( + this.defaultFunctionFactoryProxy); + } + } + + public String getBaseDir() { + return baseDir; + } + +// public Map getCustumAttrs() { +// return this.customAttr; +// } + + public Object getCustomAttr(String key) { + return this.customAttr.get(key); + } + + /** + * + */ + static class AFProxy implements AttributeFactoryProxy { + private AttributeFactory factory; + + /** + * @param factory + */ + public AFProxy(AttributeFactory factory) { + this.factory = factory; + } + + /** + * @see com.sun.xacml.attr.AttributeFactoryProxy#getFactory() + */ + public AttributeFactory getFactory() { + return this.factory; + } + } + + /** + * + */ + static class CAFProxy implements CombiningAlgFactoryProxy { + private CombiningAlgFactory factory; + + /** + * @param factory + */ + public CAFProxy(CombiningAlgFactory factory) { + this.factory = factory; + } + /** + * @see com.sun.xacml.combine.CombiningAlgFactoryProxy#getFactory() + */ + public CombiningAlgFactory getFactory() { + return this.factory; + } + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Constants.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Constants.java new file mode 100644 index 0000000..ec64dc0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Constants.java @@ -0,0 +1,262 @@ +/* + * @(#)Constants.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.net.URI; + +/** + * A collection of XACML constants used across various classes. + * + * @since 3.0 + * @author Ludwig Seitz + */ +public class Constants { + + /** + * The standard URI for listing a resource's id + */ + public static final URI RESOURCE_ID = + URI.create("urn:oasis:names:tc:xacml:1.0:resource:resource-id"); + + /** + * The standard URI for listing a subject's id + */ + public static final URI SUBJECT_ID = + URI.create("urn:oasis:names:tc:xacml:1.0:subject:subject-id"); + + /** + * The standard URI for listing a subject's id + */ + public static final URI ACTION_ID = + URI.create("urn:oasis:names:tc:xacml:1.0:action:action-id"); + + /** + * The standard URI for listing a resource's scope + */ + public static final URI RESOURCE_SCOPE = + URI.create("urn:oasis:names:tc:xacml:1.0:resource:scope"); + + /** + * The standard Subject category (compatibility code + * for XACML 2.0) + */ + public static final URI SUBJECT_CAT = URI.create( + "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"); + + /** + * The standard Resource category. + */ + public static final URI RESOURCE_CAT = URI.create( + "urn:oasis:names:tc:xacml:3.0:attribute-category:resource"); + + /** + * The standard Resource category. + */ + public static final URI ACTION_CAT = URI.create( + "urn:oasis:names:tc:xacml:3.0:attribute-category:action"); + + /** + * The standard Resource category. + */ + public static final URI ENVIRONMENT_CAT = URI.create( + "urn:oasis:names:tc:xacml:3.0:attribute-category:environment"); + + /** + * Resource scope of Immediate (only the given resource) + */ + public static final int SCOPE_IMMEDIATE = 0; + + /** + * Resource scope of Children (the given resource and its direct + * children) + */ + public static final int SCOPE_CHILDREN = 1; + + /** + * Resource scope of Descendants (the given resource and all descendants + * at any depth or distance) + */ + public static final int SCOPE_DESCENDANTS = 2; + + /** + * Resource scope of XPath-expression (a set of nodes selected by an + * XPath expression) + */ + public static final int SCOPE_XPATH_EXPRESSION = 3; + + /** + * Resource scope of EntireHierarchy (a node and all it's descendants) + */ + public static final int SCOPE_ENTIRE_HIERARCHY = 4; + + /** + * Scope of multiple elements. This applies to requests with multiple + * Resources for XACML versions < 3.0 and to requests with multiple + * Attributes elements of the same category for XACML versions >= 3.0 + */ + public static final int SCOPE_MULTIPE_ELEMENTS = 5; + + /** + * A reserved category for delegate matching + */ + public static final URI DELEGATE = URI.create( + "urn:oasis:names:tc:xacml:3.0:attribute-category:delegate"); + + /** + * A reserved category for delegate information matching + */ + public static final URI DELEGATION_INFO + = URI.create("urn:oasis:names:tc:xacml:3.0:attribute-category:" + + "delegation-info"); + + /** + * The reserved URI prefix for delegated attribute matching + */ + public static final String DELEGATED = + "urn:oasis:names:tc:xacml:3.0:attribute-category:delegated:"; + + /** + * The reserved URI for the delegation decision + */ + public static final URI DECISION = URI.create( + "urn:oasis:names:tc:xacml:3.0:delegation:decision"); + + /** + * The reserved URI for the delegation depth + */ + public static final URI DELEGATION_DEPTH = URI.create( + "urn:oasis:names:tc:xacml:3.0:delegation:depth"); + + + /** + * XACML 1.0 identifier + */ + public static final String XACML_1_0_IDENTIFIER = + "urn:oasis:names:tc:xacml:1.0:policy"; + + /** + * XACML 1.0 context identifier + */ + public static final String XACML_1_0_CTX_ID = + "urn:oasis:names:tc:xacml:1.0:context"; + + /** + * XACML 2.0 identifier + */ + public static final String XACML_2_0_IDENTIFIER = + "urn:oasis:names:tc:xacml:2.0:policy:schema:os"; + + /** + * XACML 1.0 context identifier + */ + public static final String XACML_2_0_CTX_ID = + "urn:oasis:names:tc:xacml:2.0:context:schema:os"; + + + /** + * XACML 3.0 identifier + */ + public static final String XACML_3_0_IDENTIFIER = + "urn:oasis:names:tc:xacml:3.0:schema:os"; + + /** + * Version identifier for XACML 1.0 + */ + public static final int XACML_VERSION_1_0 = 0; + + /** + * Version identifier for XACML 1.1 (which isn't a formal release + * so has no namespace string, but still exists as a separate + * specification) + */ + public static final int XACML_VERSION_1_1 = 1; + + /** + * Version identifier for XACML 1.2 + */ + public static final int XACML_VERSION_2_0 = 2; + + /** + * Version identifier for XACML 3.0 + */ + public static final int XACML_VERSION_3_0 = 3; + + + /** + * The default version of XACML, 3.0, used if no namespace string + * is specified + */ + public static final int XACML_DEFAULT_VERSION = XACML_VERSION_3_0; + + /** + * XPath 1.0 identifier + */ + public static final String XPATH_1_0_IDENTIFIER = + "http://www.w3.org/TR/1999/Rec-xpath-19991116"; + + /** + * Version identifier for an unspecified version of XPath + */ + public static final int XPATH_VERSION_UNSPECIFIED = 0; + + /** + * Version identifier for XPath 1.0 + */ + public static final int XPATH_VERSION_1_0 = 1; + + /** + * Max delegation delegation depth undefined + */ + public static final int MAX_DELEGATION_DEPTH_UNDEFINED = Integer.MAX_VALUE; + + /** + * System specific line separator + */ + public static final String nl = System.getProperty("line.separator"); + + /** + * Key for User Data available from node, describing the start line of the node in the + * xml source file. Feature must be activated. + */ + public static final String LINE_NUMBER = "startLine"; + + /** + * Key for User Data available from node, describing the source file of the node + */ + public static final String SOURCE_FILE = "srcFile"; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/EvaluationCtx.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/EvaluationCtx.java new file mode 100644 index 0000000..05bf2c8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/EvaluationCtx.java @@ -0,0 +1,342 @@ + +/* + * @(#)EvaluationCtx.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.TimeAttribute; + +import com.sun.xacml.cond.EvaluationResult; + +import com.sun.xacml.ctx.RequestElement; +import com.sun.xacml.ctx.Result; + +import com.sun.xacml.reduction.ReductionGraph; + +import java.net.URI; + +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * Manages the context of a single policy evaluation. Typically, an instance + * is instantiated whenever the PDP gets a request and needs to perform an + * evaluation as a result. The BasicEvaluationCtx class + * provides a basic implementation that is used by default. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public interface EvaluationCtx +{ + + /** + * Create a context for an administrative request from an + * existing context. + * + * @param decision The decision code corresponding to those in the + * Result class. + * @param delegate The delegate in this request (a set containing a + * single RequestElement). + * + * @return An administrative context for this context. + */ + public EvaluationCtx createAdminCtx(int decision, Set delegate); + + /** + * Creates a copy of this context with disabled attribute finder. + * + * @return A copy of this context with disabled attribute finder. + */ + public EvaluationCtx copyWithoutAttributeFinder(); + + /** + * Returns the DOM root of the original RequestType XML document, if + * this context is backed by an XACML Request. If this context is not + * backed by an XML representation, then an exception is thrown. + * + * @return the DOM root node + * + * @throws UnsupportedOperationException if the context is not backed + * by an XML representation + */ + public Node getRequestRoot(); + + /** + * Returns the resource scope, which will be one of the five fields + * denoting Immediate, Children, Descendants, XPath-expression or + * EntireHierarchy. + * + * @return the scope of the resource + */ + public int getScope(); + + /** + * Returns the identifier for the resource being requested. + * + * @return the resource + */ + public AttributeValue getResourceId(); + + /** + * Changes the value of the resource-id attribute in this context. This + * is useful when you have multiple resources (ie, a scope other than + * IMMEDIATE), and you need to keep changing only the resource-id to + * evaluate the different effective requests. + * + * @param resourceId the new resource-id value + */ + public void setResourceId(AttributeValue resourceId); + + + /** + * Returns the value for the current time as known by the PDP (if this + * value was also supplied in the Request, this will generally be a + * different value). Details of caching or location-based resolution + * are left to the underlying implementation. + * + * @return the current time + */ + public TimeAttribute getCurrentTime(); + + /** + * Returns the value for the current date as known by the PDP (if this + * value was also supplied in the Request, this will generally be a + * different value). Details of caching or location-based resolution + * are left to the underlying implementation. + * + * @return the current date + */ + public DateAttribute getCurrentDate(); + + /** + * Returns the value for the current dateTime as known by the PDP (if this + * value was also supplied in the Request, this will generally be a + * different value). Details of caching or location-based resolution + * are left to the underlying implementation. + * + * @return the current date + */ + public DateTimeAttribute getCurrentDateTime(); + + /** + * Return available attribute values of the selected category. + * + * @param category the category the attribute value(s) must be in + * @param type the type of the attribute value(s) to find + * @param id the id of the attribute value(s) to find + * @param issuer the issuer of the attribute value(s) to find or null + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult getAttribute(URI category, URI type, URI id, + URI issuer); + + /** + * Returns the attribute value(s) retrieved using the given XPath + * expression. + * + * @param contextPath the XPath expression to search + * @param namespaceNode the DOM node defining namespace mappings to use, + * or null if mappings come from the context root + * @param type the type of the attribute value(s) to find + * @param xpathVersion the version of XPath to use + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult getAttribute(String contextPath, + Node namespaceNode, URI type, + String xpathVersion); + + /** + * Get the decision. + * + * @return The int value of the decision according to + * the Result class. + */ + public int getDecision(); + + /** + * Get the delegation depth. + * + * @return The int value specifying the number of nodes + * in the reduction graph until now (not including this one). + */ + public int getDelegationDepth(); + + /** + * Get a whole category. + * + * @param category The name of the category. + * + * @return The Set of s with + * the matching category. + */ + public Set getCategory(URI category); + + /** + * @return The Set of RequestElements + * describing the attributes to be included in the result. + */ + public Set getIncludedAttributes(); + + /** + * @return the Map of RequestElements + * defining this request. + */ + public Map> getRequestElements(); + + /** + * Save the parent PolicySet in this evaluation context + * for doing reduction of delegated policies if that becomes necessary. + * + * @param pps the parent policy set + */ + public void saveParentPolicySet(AbstractPolicy pps); + + /** + * Create a reduction graph for the current parent PolicySet. + * + */ + public void createReductionGraph(); + + /** + * @return The current reduction graph. + */ + public ReductionGraph getReductionGraph(); + + /** + * Remove the current ReductionGraph from the stack. + */ + public void popReductionGraph(); + + /** + * Get the parent PolicySet for this evaluation context. + * + * @return the parent policy set + */ + public AbstractPolicy getParentPolicySet(); + + /** + * Remove the current parent PolicySet from the stack + * of parent policy sets. + */ + public void popParentPolicySet(); + + /** + * Add new inactive PolicyId to the Map + * @param policyId the id of the new inactive policy + */ + public void addInactivePolicyId(URI policyId); + + /** + * Return an unmodifiable Set of URIs of + * inactive policies + * @return the inactive policies + */ + public Set getInactivePolicyIds(); + + /** + * Checks whether a Policy or PolicySet + * supports a revocation of a specific Policy of PolicySet + * in this context. + * + * @param supporting The policy or policy set that could support + * a revocation. + * @param candidate The id of the policy or policy set that is candidate + * for revocation. + * + * @return true if the policy/policy set supports a revocation, + * false otherwise. + */ + public boolean supportsRevocation(AbstractPolicy supporting, + URI candidate); + + /** + * Signal a new event to this EvaluationCtx. + * + * @param element The new event. + */ + public void newEvent(Object element); + + /** + * Signal that an event has finished and pass the result + * which is a Result + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(Result result); + + /** + * Signal that an event has finished and pass the result + * which is a MatchResult + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(MatchResult result); + + /** + * Signal that an event has finished and pass the result + * which is a EvaluationResult + * + * @param result The result of the finished event. + */ + public void closeCurrentEvent(EvaluationResult result); + + /** + * Signal that an event has finished with a String message. + * + * @param message The message. + */ + public void closeCurrentEvent(String message); + + /** + * Signal that an event has finished with no result. + */ + public void closeCurrentEvent(); + +} + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Indenter.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Indenter.java new file mode 100644 index 0000000..1457411 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Indenter.java @@ -0,0 +1,139 @@ + +/* + * @(#)Indenter.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.util.Arrays; + + +/** + * Provides flexible indenting for XML encoding. This class generates + * strings of spaces to be prepended to lines of XML. The strings are + * formed according to a specified indent width and the given depth. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + */ +public class Indenter +{ + + /** + * The default indentation width + */ + public static final int DEFAULT_WIDTH = 2; + + // The width of one indentation level + private int width; + + // the current depth + private int depth; + + /** + * Constructs an Indenter with the default indent + * width. + */ + public Indenter() { + this(DEFAULT_WIDTH); + } + + /** + * Constructs an Indenter with a user-supplied indent + * width. + * + * @param userWidth the number of spaces to use for each indentation level + */ + public Indenter(int userWidth) { + this.width = userWidth; + this.depth = 0; + } + + /** + * Move in one width. + */ + public void in() { + this.depth += this.width; + } + + /** + * Move out one width. + */ + public void out() { + this.depth -= this.width; + } + + /** + * Create a String of spaces for indentation based on the + * current depth. + * + * @return an indent string to prepend to lines of XML + */ + public String makeString() { + // Return quickly if no indenting + if (this.depth <= 0) { + return ""; + } + + // Make a char array and fill it with spaces + char[] array = new char[this.depth]; + Arrays.fill(array, ' '); + + // Now return a string built from that char array + return new String(array); + } + + /** + * Indent an input that is multilined by adding the indent at + * the beginning of every line. + * + * @param input the unindented string + * + * @return the indented string + */ + public String multilineIndent(String input) { + input = input.replaceAll(Constants.nl, Constants.nl + makeString()); + input = makeString() + input; + return input; + } + + /** + * @return The indentation width. + */ + public int getWidth() { + return this.width; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchElement.java new file mode 100644 index 0000000..3adb2b1 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchElement.java @@ -0,0 +1,11 @@ +package com.sun.xacml; + +import com.sun.xacml.debug.Locatable; + +/** + * + * + */ +public interface MatchElement extends Locatable { + public MatchResult match(EvaluationCtx context); +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchResult.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchResult.java new file mode 100644 index 0000000..cb4e076 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/MatchResult.java @@ -0,0 +1,130 @@ + +/* + * @(#)MatchResult.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.ctx.Status; + + +/** + * This is used as the return value for the various target matching functions. + * It communicates that either the target matches the input request, the + * target doesn't match the input request, or the result is Indeterminate. + * + * @since 1.0 + * @author Seth Proctor + */ +public class MatchResult +{ + + /** + * An integer value indicating the the target matches the request + */ + public static final int MATCH = 0; + + /** + * An integer value indicating that the target doesn't match the request + */ + public static final int NO_MATCH = 1; + + /** + * An integer value indicating the the result is Indeterminate + */ + public static final int INDETERMINATE = 2; + + /** + * The array representing the string values for these results. + */ + public static final String[] MATCH_RESULTS = { "Match", "No_Match", + "Indeterminate"}; + + // + private int result; + private Status status; + + /** + * Constructor that creates a MatchResult with no Status + * + * @param result the applicable result + */ + public MatchResult(int result) { + this(result, null); + } + + /** + * Constructor that creates a MatchResult, including Status + * data + * + * @param result the applicable result + * @param status the error information + * + * @throws IllegalArgumentException if the input result isn't a valid value + */ + public MatchResult(int result, Status status) + throws IllegalArgumentException + { + + // check if input result is a valid value + if ((result != MATCH) && + (result != NO_MATCH) && + (result != INDETERMINATE)) { + throw new IllegalArgumentException("Input result is not a valid" + + "value"); + } + + this.result = result; + this.status = status; + } + + /** + * Returns the applicable result + * + * @return the applicable result + */ + public int getResult() { + return this.result; + } + + /** + * Returns the status if there was an error, or null if no error occurred + * + * @return the error status data or null + */ + public Status getStatus() { + return this.status; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Obligation.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Obligation.java new file mode 100644 index 0000000..76c1979 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Obligation.java @@ -0,0 +1,369 @@ + +/* + * @(#)Obligation.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeValue; + +import com.sun.xacml.cond.EvaluationResult; +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.ctx.Result; +import com.sun.xacml.debug.Locatable; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the ObligationType XML type in XACML. This also stores all the + * AttriubteAssignmentType XML types. + * + * @since 1.0 + * @author Seth Proctor + */ +public class Obligation implements Locatable +{ + + // the obligation id + private URI id; + + // effect to fulfill on, as defined in Result + private int fulfillOn; + + // the attribute assignments + private List assignments; + + // if the obligation has dynamic attribute assignments, i.e., if attribute values are assigned at runtime, default is false + private boolean dynamic_attributes; + + private RuntimeInfo src; + + public static final Set EMPTY_SET = Collections.emptySet(); + + /** + * Constructor that takes all the data associated with an obligation. + * The attribute assignment list contains Attribute objects, + * but only the fields used by the AttributeAssignmentType are used. + * + * @param id the obligation's id + * @param fulfillOn the effect denoting when to fulfill this obligation + * @param assignments a List of Attributes + */ + public Obligation(URI id, int fulfillOn, List assignments) { + init(id, fulfillOn, assignments, false); + } + + public Obligation(URI id, int fulfillOn, List assignments, boolean dynamic) { + init(id, fulfillOn, assignments, dynamic); + + } + + private void init(URI id, int fulfillOn, List assignments, boolean dynamic) { + this.id = id; + this.fulfillOn = fulfillOn; + this.dynamic_attributes = dynamic; + this.assignments = Collections. + unmodifiableList(new ArrayList(assignments)); + } + + private Obligation(URI id, int fulfillOn, boolean dynamic) { + this.id = id; + this.fulfillOn = fulfillOn; + this.dynamic_attributes = dynamic; + } + + /** + * Creates an instance of Obligation based on the DOM root + * node. + * + * @param root the DOM root of the ObligationType XML type + * + * @return an instance of an obligation + * + * @throws ParsingException if the structure isn't valid + */ + public static Obligation getInstance(Node root) throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.OBLIGATION); + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create an Obligation out of" + + " a node that is not an Element node" + + (src != null ? src.getLocationMsgForError() : "")); + } + if (!root.getLocalName().equals("Obligation")) { + throw new ParsingException("Can't create an Obligation with a " + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + URI id; + int fulfillOn = -1; + List assignments = new ArrayList(); + + AttributeFactory attrFactory = AttributeFactory.getInstance(); + NamedNodeMap attrs = root.getAttributes(); + + try { + id = new URI(attrs.getNamedItem("ObligationId").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error parsing required attriubte " + + "ObligationId" + (src != null ? src.getLocationMsgForError() : ""), e); + } + + String effect = null; + + try { + effect = attrs.getNamedItem("FulfillOn").getNodeValue(); + } catch (Exception e) { + throw new ParsingException("Error parsing required attriubte " + + "FulfillOn" + (src != null ? src.getLocationMsgForError() : ""), e); + } + + if (effect.equals(Result.PERMIT)) { + fulfillOn = Result.DECISION_PERMIT; + } else if (effect.equals(Result.DENY)) { + fulfillOn = Result.DECISION_DENY; + } else { + throw new ParsingException("Invlid Effect type: " + effect + + (src != null ? src.getLocationMsgForError() : "")); + } + + boolean dynamic = false; + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("AttributeAssignment")) { + URI attrId = null; + try { + attrId = + new URI(node.getAttributes(). + getNamedItem("AttributeId").getNodeValue()); + AttributeValue attrValue = attrFactory.createValue(node); + dynamic |= attrValue.isDynamic(); + assignments.add(new Attribute(attrId, null, attrValue)); + } catch (URISyntaxException use) { + throw new ParsingException("Error parsing URI: " + use.getMessage() + + (src != null ? src.getLocationMsgForError() : ""), use); + } catch (UnknownIdentifierException uie) { + throw new ParsingException("Unknown AttributeId: " + uie.getMessage() + + (src != null ? src.getLocationMsgForError() : ""), uie); + } catch (Exception e) { + throw new ParsingException("Error parsing attribute " + attrId + + "assignments" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + } + } + + Obligation obligation = new Obligation(id, fulfillOn, assignments, dynamic); + if ( src != null ) { + obligation.src = src; + src.setXACMLObject(obligation); + } + return obligation; + } + + /** + * Returns the id of this obligation + * + * @return the id + */ + public URI getId() { + return this.id; + } + + /** + * Returns effect that will cause this obligation to be included in a + * response + * + * @return the fulfillOn effect + */ + public int getFulfillOn() { + return this.fulfillOn; + } + + + public RuntimeInfo getRuntimeInfo() { + return src; + } + + /** + * Returns the attribute assignment data in this obligation. The + * List contains objects of type Attribute + * with only the correct attribute fields being used. + * + * @return the assignments + */ + public List getAssignments() { + return this.assignments; + } + + /** + * Encodes this Obligation into its XML form and writes this + * out to the provided OutputStream with no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Obligation into its XML form and writes this + * out to the provided OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + + indenter.in(); + + Iterator it = this.assignments.iterator(); + + while (it.hasNext()) { + Attribute attr = it.next(); + out.println(indenter.makeString() + + "" + + attr.getValue().encode() + + ""); + } + + indenter.out(); + + out.println(indent + ""); + } + + /** + * @param indenter + * @return the string representation of this obligation encoded in XML + */ + public String toString(Indenter indenter) { + String indent = indenter.makeString(); + + String result =indent + "" + Constants.nl; + + indenter.in(); + + Iterator it = this.assignments.iterator(); + + while (it.hasNext()) { + Attribute attr = it.next(); + result += indenter.makeString() + + "" + + attr.getValue().encode() + + "" + Constants.nl; + } + + indenter.out(); + + result += indent + "" + Constants.nl; + return result; + } + + public Obligation evaluate(EvaluationCtx context) { + if ( ! dynamic_attributes ) { + return this; + } else { + Obligation obl = new Obligation(this.id, this.fulfillOn, this.dynamic_attributes); + + List tmpAttr = new ArrayList(); + for ( Attribute attr : this.assignments ) { + if ( attr.getValue().isDynamic()) { + EvaluationResult evaluationResult =attr.getValue().evaluate(context); + AttributeValue evaluated = evaluationResult.getAttributeValue(); + tmpAttr.add(new Attribute(attr.getId(), attr.getIssuer(), evaluated)); + } else { + tmpAttr.add(attr); + } + } + obl.assignments = Collections.unmodifiableList(tmpAttr); + // this.assignments = new ArrayList(); + return obl; + } + } + + public boolean isDynamic() { + return dynamic_attributes; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PDP.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PDP.java new file mode 100644 index 0000000..e93ce07 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PDP.java @@ -0,0 +1,480 @@ + +/* + * @(#)PDP.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeValue; + +import com.sun.xacml.ctx.RequestCtx; +import com.sun.xacml.ctx.RequestElement; +import com.sun.xacml.ctx.ResponseCtx; +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; + +import com.sun.xacml.finder.AttributeFinder; +import com.sun.xacml.finder.PolicyFinder; +import com.sun.xacml.finder.PolicyFinderResult; +import com.sun.xacml.finder.ResourceFinder; +import com.sun.xacml.finder.ResourceFinderResult; +import com.sun.xacml.finder.RevocationFinder; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URL; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.apache.log4j.Logger; + + +/** + * This is the core class for the XACML engine, providing the starting point + * for request evaluation. To build an XACML policy engine, you start by + * instantiating this object. + * + * @since 1.0 + * @author Seth Proctor + */ +public class PDP +{ + // the single attribute finder that can be used to find external values + private AttributeFinder attributeFinder; + + // the single policy finder that will be used to resolve policies + private PolicyFinder policyFinder; + + // the single resource finder that will be used to resolve resources + private ResourceFinder resourceFinder; + + // the single revocation finder that will be used to find and validate + // revocations + private RevocationFinder revocationFinder; + + // the logger we'll use for all messages + private static final Logger logger = Logger.getLogger(PDP.class.getName()); + + private static String buildBy; + private static String buildTime; + + static { + Properties manifest = new Properties(); + try { + String classUrl = "/" + PDP.class.getCanonicalName().replaceAll("\\.", "/") + ".class"; + manifest.load(new URL(PDP.class.getResource(classUrl).toString().replace(classUrl, "/META-INF/MANIFEST.MF")).openStream()); + } catch (Exception e) { + // ignore.. well, doesn't work.. + } + if ( manifest.containsKey("Built-By") ) { + buildBy = manifest.getProperty("Built-By"); + } else { + buildBy = "unkown"; + } + if ( manifest.containsKey("Built-Time") ) { + buildTime = manifest.getProperty("Built-Time"); + } else { + buildTime = "unkown"; + } + } + + + /** + * Constructs a new PDP object with the given configuration + * information. + * + * @param config user configuration data defining how to find policies, + * resolve external attributes, etc. + */ + public PDP(PDPConfig config) { + logger.info("creating a PDP (built by " + buildBy + " at " + buildTime + ")"); + + this.attributeFinder = config.getAttributeFinder(); + + this.policyFinder = config.getPolicyFinder(); + this.policyFinder.init(config); + + this.resourceFinder = config.getResourceFinder(); + this.revocationFinder = config.getRevocationFinder(); + } + + /** + * Attempts to evaluate the request against the policies known to this + * PDP. This is really the core method of the entire XACML specification, + * and for most people will provide what you want. If you need any special + * handling, you should look at the version of this method that takes an + * EvaluationCtx. + *

    + * Note that if the request is somehow invalid (it was missing a required + * attribute, it was using an unsupported scope, etc), then the result + * will be a decision of INDETERMINATE. + * + * @param request the request to evaluate + * + * @return a response paired to the request + */ + public ResponseCtx evaluate(RequestCtx request) { + // try to create the EvaluationCtx out of the request + try { + return evaluate(new BasicEvaluationCtx(request, + this.attributeFinder, this.revocationFinder)); + } catch (ParsingException pe) { + logger.info("the PDP receieved an invalid request", pe); + + // there was something wrong with the request, so we return + // Indeterminate with a status of syntax error...though this + // may change if a more appropriate status type exists + ArrayList code = new ArrayList(); + code.add(Status.STATUS_SYNTAX_ERROR); + Status status = new Status(code, pe.getMessage()); + + return new ResponseCtx(new Result(Result.DECISION_INDETERMINATE, + status)); + } + } + + /** + * Uses the given EvaluationCtx against the available + * policies to determine a response. If you are starting with a standard + * XACML Request, then you should use the version of this method that + * takes a RequestCtx. This method should be used only if + * you have a real need to directly construct an evaluation context (or + * if you need to use an EvaluationCtx implementation other + * than BasicEvaluationCtx). + * + * @param context representation of the request and the context used + * for evaluation + * + * @return a response based on the contents of the context + */ + public ResponseCtx evaluate(EvaluationCtx context) { + // see if we need to call the resource finder + if (context.getScope() != Constants.SCOPE_IMMEDIATE) { + AttributeValue parent + = context.getResourceId(); + ResourceFinderResult resourceResult = null; + + if (context.getScope() == Constants.SCOPE_CHILDREN) { + resourceResult = + this.resourceFinder.findChildResources(parent, context); + } else if (context.getScope() == Constants.SCOPE_DESCENDANTS) { + resourceResult = + this.resourceFinder.findDescendantResources(parent, + context); + } else if (context.getScope() + == Constants.SCOPE_XPATH_EXPRESSION) { + resourceResult = + this.resourceFinder.findXPathResources(parent, context); + } else if (context.getScope() + == Constants.SCOPE_ENTIRE_HIERARCHY) { + resourceResult = + this.resourceFinder.findHierarchyResources(parent, + context); + } else if (context.getScope() + == Constants.SCOPE_MULTIPE_ELEMENTS) { + return multipleElementsEval(context); + } + // see if we actually found anything + if (resourceResult == null || resourceResult.isEmpty()) { + // this is a problem, since we couldn't find any resources + // to work on...the spec is not explicit about what kind of + // error this is, so we're treating it as a processing error + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + String msg = "Couldn't find any resources to work on."; + + return new + ResponseCtx(new Result(Result.DECISION_INDETERMINATE, + new Status(code, msg), + context)); + } + + // setup a set to keep track of the results + HashSet results = new HashSet(); + + // at this point, we need to go through all the resources we + // successfully found and start collecting results + Iterator it = resourceResult.getResources().iterator(); + while (it.hasNext()) { + // get the next resource, and set it in the EvaluationCtx + AttributeValue resource = it.next(); + context.setResourceId(resource); + + // do the evaluation, and set the resource in the result + Result result = evaluateContext(context); + result.setResource(resource.encode()); + + // add the result + results.add(result); + } + + // now that we've done all the successes, we add all the failures + // from the finder result + Map failureMap = resourceResult.getFailures(); + Iterator> it2 = failureMap.entrySet().iterator(); + while (it2.hasNext()) { + Map.Entry entry = it2.next(); + // get the next resource, and use it to get its Status data + Status status = entry.getValue(); + + // add a new result + results.add(new Result(Result.DECISION_INDETERMINATE, + status, context)); + } + + // return the set of results + return new ResponseCtx(results); + } + // the scope was IMMEDIATE (or missing), so we can just evaluate + // the request and return whatever we get back + return new ResponseCtx(evaluateContext(context)); + } + + /** + * Protected helper to handle multiple elements of same category in the + * request (generates several requests). + * + * @param context + * @return Collected responses for the multiple elements evaluation. + */ + protected ResponseCtx multipleElementsEval(EvaluationCtx context) { + // Collect the different Maps of request elements here + Map> elements = context.getRequestElements(); + Iterator iter = elements.keySet().iterator(); + Set> setOfsets = new HashSet>(); + while (iter.hasNext()) { + Set reSet = context.getCategory(iter.next()); + //Do the division + if (setOfsets.isEmpty()) { + //Create initial set of sets + Iterator iter2 = reSet.iterator(); + while (iter2.hasNext()) { + RequestElement re = iter2.next(); + Set newSet = new HashSet(); + newSet.add(re); + setOfsets.add(newSet); + } + } else { + Iterator> iter2 = setOfsets.iterator(); + Set> newSetOfSets = new HashSet>(); + while (iter2.hasNext()) { + Set subset = iter2.next(); + Iterator iter3 = reSet.iterator(); + while(iter3.hasNext()) { + RequestElement re = iter3.next(); + Set newSet = new HashSet(); + newSet.addAll(subset); + newSet.add(re); + newSetOfSets.add(newSet); + } + } + setOfsets = newSetOfSets; + } + } + if (setOfsets.size() < 2) { + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + String msg = "Scope set to 'multipe elements' but could" + + " only find one/zero"; + return new ResponseCtx( + new Result(Result.DECISION_INDETERMINATE, + new Status(code, msg), + context)); + } + // setup a set to keep track of the results + HashSet results = new HashSet(); + + // at this point, we need to go through all the sets we + // successfully found and start collecting creating requests + // and collect results + Iterator> it = setOfsets.iterator(); + while (it.hasNext()) { + // get the next set of request elements, and create a + // new request for it. + Set requestElements = it.next(); + RequestCtx request = new RequestCtx(requestElements, null, null); + Result result = null; + try { + context = new BasicEvaluationCtx(request, + this.attributeFinder, this.revocationFinder); + } catch (ParsingException pe) { + logger.info("the PDP receieved an invalid request", + pe); + + // there was something wrong with the request, so we collect + // Indeterminate with a status of syntax error...though this + // may change if a more appropriate status type exists + ArrayList code = new ArrayList(); + code.add(Status.STATUS_SYNTAX_ERROR); + Status status = new Status(code, pe.getMessage()); + result = new Result(Result.DECISION_INDETERMINATE, status); + } + if (result == null) {// do the evaluation if nothing went wrong + result = evaluateContext(context); + } + + // add the result + results.add(result); + } + // return the set of results + return new ResponseCtx(results); + } + + /** + * A protected helper routine that resolves a policy for the given + * context, and then tries to evaluate based on the policy. + * Can be overrider by subclasses. + */ + protected Result evaluateContext(EvaluationCtx context) { + // first off, try to find a policy + PolicyFinderResult finderResult + = this.policyFinder.findPolicy(context); + + // see if there weren't any applicable policies + if (finderResult.notApplicable()) { + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + + // see if there were any errors in trying to get a policy + if (finderResult.indeterminate()) { + return new Result(Result.DECISION_INDETERMINATE, + finderResult.getStatus(), + context); + } + + // we found a valid policy + context.newEvent(finderResult.getPolicy()); + Result result = finderResult.getPolicy().evaluate(context); + context.closeCurrentEvent(result); + if (result == null) { + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + return result; + } + + /** + * A utility method that wraps the functionality of the other evaluate + * method with input and output streams. This is useful if you've got + * a PDP that is taking inputs from some stream and is returning + * responses through the same stream system. If the Request is invalid, + * then this will always return a decision of INDETERMINATE. + * + * @deprecated As of 1.2 this method should not be used. Instead, you + * should do your own stream handling, and then use one of + * the other evaluate methods. The problem + * with this method is that it often doesn't handle stream + * termination correctly (eg, with sockets). + * + * @param input a stream that contains an XML RequestType + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform default character set + * will be used. + * + * @return a stream that contains an XML ResponseType + * @throws UnsupportedEncodingException + */ + public OutputStream evaluate(InputStream input, String charsetName) + throws UnsupportedEncodingException { + RequestCtx request = null; + ResponseCtx response = null; + + try { + request = RequestCtx.getInstance(input); + } catch (Exception pe) { + // the request wasn't formed correctly + ArrayList code = new ArrayList(); + code.add(Status.STATUS_SYNTAX_ERROR); + Status status = new Status(code, "invalid request: " + + pe.getMessage()); + + response = + new ResponseCtx(new Result(Result.DECISION_INDETERMINATE, + status)); + } + + // if we didn't have a problem above, then we should go ahead + // with the evaluation + if (response == null) { + response = evaluate(request); + } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + response.encode(out, charsetName, new Indenter()); + + return out; + } + + /** + * @return The AttributeFinder + * (used by subclasses of the PDP). + */ + protected AttributeFinder getAttributeFinder() { + return this.attributeFinder; + } + + /** + * @return The RevocationFinder + * (used by subclasses of the PDP). + */ + protected RevocationFinder getRevocationFinder() { + return this.revocationFinder; + } + + /** + * @return The PolicyFinder + * (used by subclasses of the PDP). + */ + protected PolicyFinder getPolicyFinder() { + return this.policyFinder; + } + +// public void setEmergencyLevel(EmergencyLevel level) { +// this.curEmgLevel = level; +// } +// +// public EmergencyLevel getEmergencyLevel() { +// return this.curEmgLevel; +// } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PDPConfig.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PDPConfig.java new file mode 100644 index 0000000..ae53fb4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PDPConfig.java @@ -0,0 +1,185 @@ + +/* + * @(#)PDPConfig.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.util.HashMap; +import java.util.Map; + +import com.sun.xacml.finder.AttributeFinder; +import com.sun.xacml.finder.PolicyFinder; +import com.sun.xacml.finder.ResourceFinder; +import com.sun.xacml.finder.RevocationFinder; + + +/** + * This class is used as a container that holds configuration + * information for the PDP, which includes the AttributeFinder, + * PolicyFinder, ResourceFinder, and the + * RevocationFinder that the PDP should use. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + * @author Ludwig Seitz + */ +public class PDPConfig +{ + + // + private AttributeFinder attributeFinder; + + // + private PolicyFinder policyFinder; + + // + private ResourceFinder resourceFinder; + + // + private RevocationFinder revocationFinder; + + private Map customAttr = new HashMap(); + + /** + * Constructor that creates a PDPConfig from components. + * + * @param attributeFinder the AttributeFinder that the PDP + * should use, or null if it shouldn't use any + * @param policyFinder the PolicyFinder that the PDP + * should use, or null if it shouldn't use any + * @param resourceFinder the ResourceFinder that the PDP + * should use, or null if it shouldn't use any + * @param revocationFinder The RevocationFinder that the PDP + * should use, or null if it shouldn't use any + */ + public PDPConfig(AttributeFinder attributeFinder, + PolicyFinder policyFinder, + ResourceFinder resourceFinder, + RevocationFinder revocationFinder) { + if (attributeFinder != null) { + this.attributeFinder = attributeFinder; + } else { + this.attributeFinder = new AttributeFinder(); + } + + if (policyFinder != null) { + this.policyFinder = policyFinder; + } else { + this.policyFinder = new PolicyFinder(); + } + + if (resourceFinder != null) { + this.resourceFinder = resourceFinder; + } else { + this.resourceFinder = new ResourceFinder(); + } + + if (revocationFinder != null) { + this.revocationFinder = revocationFinder; + } else { + this.revocationFinder = new RevocationFinder(); + } + } + + /** + * Returns the AttributeFinder that was configured, or + * null if none was configured + * + * @return the AttributeFinder or null + */ + public AttributeFinder getAttributeFinder() { + return this.attributeFinder; + } + + /** + * Returns the PolicyFinder that was configured, or + * null if none was configured + * + * @return the PolicyFinder or null + */ + public PolicyFinder getPolicyFinder() { + return this.policyFinder; + } + + /** + * Returns the ResourceFinder that was configured, or + * null if none was configured + * + * @return the ResourceFinder or null + */ + public ResourceFinder getResourceFinder() { + return this.resourceFinder; + } + + + /** + * Returns the RevocationFinder that was configured, or + * null if none was configured + * + * @return the RevocationFinder or null + */ + public RevocationFinder getRevocationFinder() { + return this.revocationFinder; + } + + public void setCutomAttrs(Map attrs) { + if ( customAttr != null && customAttr.size() > 0 ) { + throw new RuntimeException("The custom attributes for PDPConfig may not be overwritten, if already values are stored!"); + } + customAttr = attrs; + } + + public void addCutomAttrs(Map attrs) { + if ( customAttr == null ) { + this.customAttr = attrs; + } else { + customAttr.putAll(attrs); + } + } + + public void setCustomAttr(String key, Object value) { + customAttr.put(key, value); + } + + public Object getCustomAttr(String key) { + return customAttr.get(key); + } + + public Map getCustomAttrs() { + return customAttr; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ParsingException.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ParsingException.java new file mode 100644 index 0000000..4f6688a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ParsingException.java @@ -0,0 +1,105 @@ + +/* + * @(#)ParsingException.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + + +/** + * Exception that gets thrown if any general parsing error occurs. + * + * @since 1.0 + * @author Seth Proctor + */ +public class ParsingException extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new ParsingException with no message + * or cause. + */ + public ParsingException() { + //parsing exception with no message or cause. + } + + /** + * Constructs a new ParsingException with a message, + * but no cause. The message is saved for later retrieval by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} + * method. + * + * @param message the detail message (null if nonexistent + * or unknown) + */ + public ParsingException(String message) { + super(message); + } + + /** + * Constructs a new ParsingException with a cause, + * but no message. The cause is saved for later retrieval by the + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * method. + * + * @param cause the cause (null if nonexistent + * or unknown) + */ + public ParsingException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new ParsingException with a message + * and a cause. The message and cause are saved for later retrieval + * by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} and + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * methods. + * + * @param message the detail message (null if nonexistent + * or unknown) + * @param cause the cause (null if nonexistent + * or unknown) + */ + public ParsingException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Policy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Policy.java new file mode 100644 index 0000000..3de1c27 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Policy.java @@ -0,0 +1,819 @@ + +/* + * @(#)Policy.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.combine.CombinerElement; +import com.sun.xacml.combine.CombinerParameter; +import com.sun.xacml.combine.RuleCombinerElement; +import com.sun.xacml.combine.RuleCombiningAlgorithm; + +import com.sun.xacml.cond.VariableDefinition; +import com.sun.xacml.cond.VariableManager; +import com.sun.xacml.ctx.PolicyIssuer; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents one of the two top-level constructs in XACML, the PolicyType. + * This contains rules, which in turn contain most of the logic of + * a policy. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class Policy extends AbstractPolicy { + + /** + * The Set of VariableDefinitions in this policy + */ + private Set definitions; + + /** + * Creates a new Policy with only the required elements. + * + * @param id the policy identifier + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * + * @param target the Target for this policy + */ + public Policy(URI id, RuleCombiningAlgorithm combiningAlg, Target target) { + this(id, null, null, combiningAlg, null, null, target, null, + null, null); + } + + /** + * Creates a new Policy with only the required elements. + * + * @param id the policy identifier + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + */ + public Policy(URI id, RuleCombiningAlgorithm combiningAlg, + PolicyIssuer issuer, Target target) { + this(id, null, null, combiningAlg, null, issuer, target, null, + null, null); + } + + /** + * Creates a new Policy with only the required elements + * plus rules. + * + * @param id the policy identifier + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param target the Target for this policy + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, RuleCombiningAlgorithm combiningAlg, Target target, + List rules) { + this(id, null, null, combiningAlg, null, null, target, null, + rules, null); + } + + /** + * Creates a new Policy with only the required elements + * plus rules. + * + * @param id the policy identifier + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, RuleCombiningAlgorithm combiningAlg, + PolicyIssuer issuer, Target target, List rules) { + this(id, null, null, combiningAlg, null, issuer, target, null, + rules, null); + } + + /** + * Creates a new Policy with the required elements plus + * rules and a String description. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param target the Target for this policy + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, Target target, List rules) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, null, rules, null); + } + + /** + * Creates a new Policy with the required elements plus + * a version, rules, and a String description. Note that the version + * is an XACML 2.0 feature. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this must + * always be null for XACML 1.x policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + List rules) { + this(id, version, xacmlVersion, combiningAlg, description, issuer, + target, null, rules, null); + } + + /** + * Creates a new Policy with the required elements plus + * rules, a String description and policy defaults. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, Target target, String defaultVersion, + List rules) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, defaultVersion, rules, null); + } + + /** + * Creates a new Policy with the required elements plus + * a version, rules, a String description and policy defaults. Note that + * the version is an XACML 2.0 feature. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this must + * always be null for XACML 1.x policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + String defaultVersion, List rules) { + this(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, rules, null); + } + + /** + * Creates a new Policy with the required elements plus + * a version, rules, a String description, policy defaults, and + * obligations. Note that the version is an XACML 2.0 feature. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this must + * always be null for XACML 1.x policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * @param obligations a set of Obligations objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, Target target, String defaultVersion, + List rules, Set obligations) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, defaultVersion, rules, obligations, null); + } + + /** + * Creates a new Policy with the required elements plus + * rules, a String description, policy defaults, and obligations. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * @param obligations a set of Obligations objects + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + String defaultVersion, List rules, Set obligations) { + this(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, rules, obligations, null); + } + + /** + * Creates a new Policy with the required elements plus + * a version, rules, a String description, policy defaults, obligations, + * and variable definitions. Note that the version and definitions are + * XACML 2.0 features. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this must + * always be null for XACML 1.x policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * @param obligations a set of Obligations objects + * @param definitions a set of VariableDefinition objects + * that must provide all definitions referenced by + * all VariableReferences in the policy + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, Target target, String defaultVersion, + List rules, Set obligations, Set definitions) { + this(id, version, xacmlVersion, combiningAlg, description, null, target, + defaultVersion, rules, obligations, definitions); + } + + /** + * Creates a new Policy with the required elements plus + * rules, a String description, policy defaults, obligations, and + * variable definitions. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this policy or null + * if it is the trusted issuer + * @param target the Target for this policy + * @param defaultVersion the XPath version to use + * @param rules a list of Rule objects + * @param obligations a set of Obligations objects + * @param definitions a set of VariableDefinition objects + * that must provide all definitions referenced by + * all VariableReferences in the policy + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + String defaultVersion, List rules, Set obligations, + Set definitions) { + super(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, obligations, null, + Constants.MAX_DELEGATION_DEPTH_UNDEFINED); + + List list = null; + + // check that the list contains only rules + if (rules != null) { + list = new ArrayList(); + Iterator it = rules.iterator(); + while (it.hasNext()) { +// Object o = it.next(); +// if (! (o instanceof Rule)) { +// throw new IllegalArgumentException("non-Rule in rules"); +// } + list.add(new RuleCombinerElement(it.next())); + } + } + + setChildren(list); + + // save the definitions + if (definitions == null) { + this.definitions = VariableDefinition.EMPTY_SET; + } else { + this.definitions = Collections. + unmodifiableSet(new HashSet(definitions)); + } + } + + /** + * Creates a new Policy with the required and optional + * elements. If you need to provide combining algorithm parameters, you + * need to use this constructor. Note that unlike the other constructors + * in this class, the rules list is actually a list of + * CombinerElements used to match a rule with any + * combiner parameters it may have. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this must + * always be null for XACML 1.x policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy or + * null if there is no description + * @param target the Target for this policy + * @param defaultVersion the XPath version to use or null if there is + * no default version + * @param ruleElements a list of RuleCombinerElement objects + * or null if there are no rules + * @param obligations a set of Obligations objects or null + * if there are no obligations + * @param definitions a set of VariableDefinition objects + * that must provide all definitions referenced by + * all VariableReferences in the policy + * @param parameters the List of + * CombinerParameters provided for general + * use by the combining algorithm + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * RuleCombinerElement + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, Target target, String defaultVersion, + List ruleElements, Set obligations, Set definitions, + List parameters) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, defaultVersion, ruleElements, obligations, + definitions, parameters, + Constants.MAX_DELEGATION_DEPTH_UNDEFINED); + } + + /** + * Creates a new Policy with the required and optional + * elements. If you need to provide combining algorithm parameters, you + * need to use this constructor. Note that unlike the other constructors + * in this class, the rules list is actually a list of + * CombinerElements used to match a rule with any + * combiner parameters it may have. + * + * @param id the policy identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy or + * null if there is no description + * @param issuer the PolicyIssuer or null if this is the trusted issuer + * @param target the Target for this policy + * @param defaultVersion the XPath version to use or null if there is + * no default version + * @param ruleElements a list of RuleCombinerElement objects + * or null if there are no rules + * @param obligations a set of Obligations objects or null + * if there are no obligations + * @param definitions a set of VariableDefinition objects + * that must provide all definitions referenced by + * all VariableReferences in the policy + * @param parameters the List of + * CombinerParameters provided for general + * use by the combining algorithm + * @param maxDelegationDepth the maximum delegation depth authorised + * by this policy set. + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * RuleCombinerElement + */ + public Policy(URI id, String version, String xacmlVersion, + RuleCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + String defaultVersion, List ruleElements, Set obligations, + Set definitions, List parameters, int maxDelegationDepth) { + super(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, obligations, parameters, + maxDelegationDepth); + + // check that the list contains only RuleCombinerElements + if (ruleElements != null) { + Iterator it = ruleElements.iterator(); + while (it.hasNext()) { + CombinerElement o = it.next(); + if (! (o instanceof RuleCombinerElement)) { + throw new IllegalArgumentException("non-Rule in rules"); + } + } + } + + setChildren(ruleElements); + + // save the definitions + if (definitions == null) { + this.definitions = VariableDefinition.EMPTY_SET; + } else { + this.definitions = Collections. + unmodifiableSet(new HashSet(definitions)); + } + } + + /** + * Creates a new Policy based on the given root node. This is + * private since every class is supposed to use a getInstance() method + * to construct from a Node, but since we want some common code in the + * parent class, we need this functionality in a constructor. + */ + private Policy(Node root) throws ParsingException { + super(root, "Policy", "RuleCombiningAlgId"); + this.src = RuntimeInfo.getRuntimeInfo(this, root, ELEMENT_TYPE.POLICY); + + List rules = new ArrayList(); + Map> parameters = new HashMap>(); + + Map variableIds = new HashMap(); + PolicyMetaData metaData = getMetaData(); + + // first off, go through and look for any definitions to get their + // identifiers up front, since before we parse any references we'll + // need to know what definitions we support + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE + && child.getLocalName().equals("VariableDefinition")) { + String id = null; + if (child.getAttributes().getNamedItem("VariableId") != null) { + id = child.getAttributes().getNamedItem("VariableId") + .getNodeValue(); + } else { + throw new ParsingException("Error while trying to parse " + + "VariableId in a Policy"); + } + // it's an error to have more than one definition with the + // same identifier + if (variableIds.containsKey(id)) { + throw new ParsingException("multiple definitions for " + + "variable " + id); + } + variableIds.put(id, child); + } + } + + // now create a manager with the defined variable identifiers + VariableManager manager = new VariableManager(variableIds, metaData); + this.definitions = new HashSet(); + + // next, collect the Policy-specific elements + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + String name = child.getLocalName(); + + if (name.equals("Rule")) { + rules.add(Rule.getInstance(child, metaData, manager)); + } else if (name.equals("RuleCombinerParameters")) { + String ref = null; + if (child.getAttributes() != null) { + if (child.getAttributes().getNamedItem("RuleIdRef") + != null) { + ref = child.getAttributes() + .getNamedItem("RuleIdRef") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute" + + " RuleIdRef not found"); + } + } else { + throw new ParsingException("Required xml-attribute" + + " RuleIdRef not found"); + } + + // if we found the parameter before than add it the end of + // the previous paramters, otherwise create a new entry + if (parameters.containsKey(ref)) { + List list = parameters.get(ref); + parseParameters(list, child); + } else { + List list = new ArrayList(); + parseParameters(list, child); + parameters.put(ref, list); + } + } else if (name.equals("VariableDefinition")) { + String id = null; + if (child.getAttributes() != null) { + if (child.getAttributes().getNamedItem("VariableId") + != null) { + id = child.getAttributes() + .getNamedItem("VariableId") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute" + + " VariableId not found"); + } + } else { + throw new ParsingException("Required xml-attribute" + + " VariableId not found"); + } + + // parsing definitions is a little strange, since they can + // contain references to definitions we haven't yet parsed + // or circular references, but we still want to verify the + // references and the types...so, for each definition, we + // ask the manager though getDefinition, which takes care + // of loading any forward references, handles loops, etc. + // It also handles caching definitions, so we don't end + // up parsing the same definitions multiple times + this.definitions.add(manager.getDefinition(id)); + } + } + } + + this.definitions = Collections.unmodifiableSet(this.definitions); + + // now make sure that we can match up any parameters we may have + // found to a cooresponding Rule... + List elements = new ArrayList(); + Iterator it = rules.iterator(); + + while (it.hasNext()) { + Rule rule = it.next(); + String id = rule.getId().toString(); + List list = parameters.remove(id); + + elements.add(new RuleCombinerElement(rule, list)); + } + + // ...and that there aren't extra parameters + if (! parameters.isEmpty()) { + throw new ParsingException("Unmatched parameters in Rule"); + } + // finally, set the list of Rules + setChildren(elements); + } + + /** + * The clone method + * FIXME: this does no deep copy on the Lists and Sets. + * + * @return a copy of this object. + */ + public Object clone() { + Policy clone = (Policy)super.clone(); + clone.definitions = new HashSet(this.definitions); + clone.setChildren(this.getChildElements()); + return clone; + } + + /** + * Helper method that parses out a collection of combiner parameters. + */ + private void parseParameters(List parameters, Node root) + throws ParsingException + { + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("CombinerParameter")) { + parameters.add(CombinerParameter.getInstance(node)); + } + } + } + + /** + * Creates an instance of a Policy object based on a + * DOM node. The node must be the root of PolicyType XML object, + * otherwise an exception is thrown. + * + * @param root the DOM root of a PolicyType XML type + * + * @return A policy object. + * + * @throws ParsingException if the PolicyType is invalid + */ + public static Policy getInstance(Node root) + throws ParsingException { + // first off, check that it's the right kind of node + if (root.getNodeType() != Node.ELEMENT_NODE + || ! root.getLocalName().equals("Policy")) { + throw new ParsingException("Cannot create Policy from root of " + + "type " + root.getLocalName()); + } + + return new Policy(root); + } + + /** + * Returns the variable definitions in this Policy. + * + * @return a Set of VariableDefinitions + */ + public Set getVariableDefinitions() { + return this.definitions; + } + + /** + * Encodes this Policy into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Policy into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + + } else { + out.println(">"); + } + + indenter.in(); + String nextIndent = indenter.makeString(); + + String description = getDescription(); + if (description != null) { + out.println(nextIndent + "" + description + + ""); + } + encodePolicyIssuer(output, charsetName, indenter); + + + String version = getDefaultVersion(); + if (version != null) { + out.println("" + version + + ""); + } + getTarget().encode(output, charsetName, indenter); + + Iterator it = this.definitions.iterator(); + while (it.hasNext()) { + ((VariableDefinition)(it.next())).encode(output, charsetName, + indenter); + } + encodeCommonElements(output, charsetName, indenter); + + indenter.out(); + out.println(indent + ""); + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyMetaData.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyMetaData.java new file mode 100644 index 0000000..33bccec --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyMetaData.java @@ -0,0 +1,306 @@ + +/* + * @(#)PolicyMetaData.java + * + * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeFactoryProxy; + +import com.sun.xacml.combine.CombiningAlgFactory; +import com.sun.xacml.combine.CombiningAlgFactoryProxy; + +import com.sun.xacml.cond.FunctionFactory; +import com.sun.xacml.cond.FunctionFactoryProxy; + + +/** + * This is used to share polcy meta-data throughout the policy tree. Examples + * of common meta-data include the version of XACML or XPath being used in + * a policy. + * + * @since 2.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class PolicyMetaData +{ + // private mapping from XACML version number to identifier string + private static String [] xacmlIdentifiers = { + Constants.XACML_1_0_IDENTIFIER, + Constants.XACML_1_0_IDENTIFIER, + Constants.XACML_2_0_IDENTIFIER, + Constants.XACML_3_0_IDENTIFIER}; + + // private mapping from XPath version number to identifier string + private static String [] xpathIdentifiers = { null, + Constants.XPATH_1_0_IDENTIFIER }; + + // the version of XACML + private int xacmlVersion; + + // the version of XPath, or null if none is specified + private int xpathVersion; + + // the factories used with this policy + private AttributeFactoryProxy afProxy; + private CombiningAlgFactoryProxy cafProxy; + private FunctionFactoryProxy ffProxy; + + /** + * Creates a PolicyMetaData instance with all the parameters + * set to their default values. + */ + public PolicyMetaData() { + this(Constants.XACML_DEFAULT_VERSION, + Constants.XPATH_VERSION_UNSPECIFIED); + } + + /** + * Creates a PolicyMetaData instance with the given + * parameters. The default factories are assumed. + * + * @param xacmlVersion the version of XACML used in a policy + * @param xpathVersion the XPath version to use in any selectors + */ + public PolicyMetaData(int xacmlVersion, int xpathVersion) { + this(xacmlVersion, xpathVersion, null, null, null); + } + + /** + * Creates a PolicyMetaData instance with the given + * parameters. The default factories are assumed. + * + * @param xacmlVersion the version of XACML used in a policy + * @param xpathVersion the XPath version to use in any selectors, or + * null if this is unspecified (ie, not supplied in + * the defaults section of the policy) + * + * @throws IllegalArgumentException if the identifier strings are unknown + */ + public PolicyMetaData(String xacmlVersion, String xpathVersion) { + this(xacmlVersion, xpathVersion, null, null, null); + } + + /** + * Creates a PolicyMetaData instance with the given + * parameters. A proxy value of null implies the default factory. + * + * @param xacmlVersion the version of XACML used in a policy + * @param xpathVersion the XPath version to use in any selectors + * @param attributeFactoryProxy + * @param combiningAlgFactoryProxy + * @param functionFactoryProxy + */ + public PolicyMetaData(int xacmlVersion, int xpathVersion, + AttributeFactoryProxy attributeFactoryProxy, + CombiningAlgFactoryProxy combiningAlgFactoryProxy, + FunctionFactoryProxy functionFactoryProxy) { + this.xacmlVersion = xacmlVersion; + this.xpathVersion = xpathVersion; + + proxySetup(attributeFactoryProxy, combiningAlgFactoryProxy, + functionFactoryProxy); + } + + /** + * Creates a PolicyMetaData instance with the given + * parameters. + * + * @param xacmlVersion the version of XACML used in a policy + * @param xpathVersion the XPath version to use in any selectors, or + * null if this is unspecified (ie, not supplied in + * the defaults section of the policy) + * @param attributeFactoryProxy + * @param combiningAlgFactoryProxy + * @param functionFactoryProxy + * + * @throws IllegalArgumentException if the identifier strings are unknown + */ + public PolicyMetaData(String xacmlVersion, String xpathVersion, + AttributeFactoryProxy attributeFactoryProxy, + CombiningAlgFactoryProxy combiningAlgFactoryProxy, + FunctionFactoryProxy functionFactoryProxy) { + if (xacmlVersion == null) { + this.xacmlVersion = Constants.XACML_DEFAULT_VERSION; + } else if (xacmlVersion.equals(Constants.XACML_1_0_IDENTIFIER)) { + this.xacmlVersion = Constants.XACML_VERSION_1_0; + } else if (xacmlVersion.equals(Constants.XACML_2_0_IDENTIFIER)) { + this.xacmlVersion = Constants.XACML_VERSION_2_0; + } else if (xacmlVersion.equals(Constants.XACML_3_0_IDENTIFIER)) { + this.xacmlVersion = Constants.XACML_VERSION_3_0; + } else if (xacmlVersion.equals(Constants.XACML_1_0_CTX_ID)) { + this.xacmlVersion = Constants.XACML_VERSION_1_0; + } else if (xacmlVersion.equals(Constants.XACML_2_0_CTX_ID)) { + this.xacmlVersion = Constants.XACML_VERSION_2_0; + } else { + throw new IllegalArgumentException("Unknown XACML version " + + "string: " + xacmlVersion); + } + + if (xpathVersion != null) { + if (! xpathVersion.equals(Constants.XPATH_1_0_IDENTIFIER)) { + throw new IllegalArgumentException("Unsupported XPath " + + " version: " + + xpathVersion); + } + this.xpathVersion = Constants.XPATH_VERSION_1_0; + } else { + this.xpathVersion = Constants.XPATH_VERSION_UNSPECIFIED; + } + + proxySetup(attributeFactoryProxy, combiningAlgFactoryProxy, + functionFactoryProxy); + } + + /** + * + */ + private void proxySetup(AttributeFactoryProxy attributeFactoryProxy, + CombiningAlgFactoryProxy combiningAlgFactoryProxy, + FunctionFactoryProxy functionFactoryProxy) { + if (attributeFactoryProxy == null) { + this.afProxy = new AttributeFactoryProxy() { + public AttributeFactory getFactory() { + return AttributeFactory.getInstance(); + } + }; + } else { + this.afProxy = attributeFactoryProxy; + } + if (combiningAlgFactoryProxy == null) { + this.cafProxy = new CombiningAlgFactoryProxy() { + public CombiningAlgFactory getFactory() { + return CombiningAlgFactory.getInstance(); + } + }; + } else { + this.cafProxy = combiningAlgFactoryProxy; + } + if (functionFactoryProxy == null) { + this.ffProxy = FunctionFactory.getInstance(); + } else { + this.ffProxy = functionFactoryProxy; + } + } + + /** + * Returns which version of XACML is specified in this meta-data. + * + * @return the XACML version + */ + public int getXACMLVersion() { + return this.xacmlVersion; + } + + /** + * Returns the identifier string for the specified version of XACML. + * + * @return the identifier string + */ + public String getXACMLIdentifier() { + return xacmlIdentifiers[this.xacmlVersion]; + } + + /** + * Returns which version of XPath is specified in this meta-data. + * + * @return the XPath version or null + */ + public int getXPathVersion() { + return this.xpathVersion; + } + + /** + * Returns the identifier string for the specified version of XPath, or + * null if no version is specified. + * + * @return the identifier string or null + */ + public String getXPathIdentifier() { + return xpathIdentifiers[this.xpathVersion]; + } + + /** + * Returns the AttributeFactory used by the associated + * policy. + * + * @return a AttributeFactory + */ + public AttributeFactory getAttributeFactory() { + return this.afProxy.getFactory(); + } + + /** + * Returns the CombiningAlgFactory used by the associated + * policy. + * + * @return a CombiningAlgFactory + */ + public CombiningAlgFactory getCombiningAlgFactory() { + return this.cafProxy.getFactory(); + } + + /** + * Returns the Target FunctionFactory used by the associated + * policy. + * + * @return a FunctionFactory + */ + public FunctionFactory getTargetFunctionFactory() { + return this.ffProxy.getTargetFactory(); + } + + /** + * Returns the Condition FunctionFactory used by the + * associated policy. + * + * @return a FunctionFactory + */ + public FunctionFactory getConditionFunctionFactory() { + return this.ffProxy.getConditionFactory(); + } + + /** + * Returns the General FunctionFactory used by the associated + * policy. + * + * @return a FunctionFactory + */ + public FunctionFactory getGeneralFunctionFactory() { + return this.ffProxy.getGeneralFactory(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyReference.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyReference.java new file mode 100644 index 0000000..1dfe97e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyReference.java @@ -0,0 +1,647 @@ + +/* + * @(#)PolicyReference.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.combine.CombinerElement; +import com.sun.xacml.combine.CombiningAlgorithm; + +import com.sun.xacml.ctx.PolicyIssuer; +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import com.sun.xacml.finder.PolicyFinder; +import com.sun.xacml.finder.PolicyFinderResult; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.Vector; + +import org.apache.log4j.Logger; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * This class is used as a placeholder for the PolicyIdReference and + * PolicySetIdReference fields in a PolicySetType. When a reference is used + * in a policy set, it is telling the PDP to use an external policy in + * the current policy. Each time the PDP needs to evaluate that policy + * reference, it asks the policy finder for the policy. Typically the policy + * finder will have cached the referenced policy, so this isn't too slow. + *

    + * NOTE: all of the accessor methods, the match method, and the evaluate method + * require this class to ask its PolicyFinder for the referenced + * policy, which can be a slow operation. Care should be taken, therefore in + * calling these methods too often. Also note that it's not safe to cache the + * results of these calls, since the referenced policy may change. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class PolicyReference extends AbstractPolicy { + + /** + * Identifies this as a reference to a Policy + */ + public static final int POLICY_REFERENCE = 0; + + /** + * Identifies this as a reference to a PolicySet + */ + public static final int POLICYSET_REFERENCE = 1; + + // the reference + private URI reference; + + // the reference type + private int policyType; + + // and version constraints on this reference + private VersionConstraints constraints; + + // the finder to use in finding the referenced policy + private PolicyFinder finder; + + // the meta-data for the parent policy + private PolicyMetaData parentMetaData; + + // the referenced policy + private AbstractPolicy referencedPolicy; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(PolicyReference.class.getName()); + + /** + * Creates a new PolicyReference instance. This has no + * constraints on version matching. Note that an XACML 1.x reference may + * not have any constraints. + * + * @param reference the reference to the policy + * @param policyType one of the two fields in this class + * @param finder the PolicyFinder used to handle the reference + * @param parentMetaData the meta-data associated with the containing + * (parent) policy + * + * @throws IllegalArgumentException if the input policyType isn't valid + */ + public PolicyReference(URI reference, int policyType, PolicyFinder finder, + PolicyMetaData parentMetaData) + throws IllegalArgumentException + { + this(reference, policyType, new VersionConstraints(null, null, null), + finder, parentMetaData); + } + + /** + * Creates a new PolicyReference instance with version + * constraints. Note that an XACML 1.x reference may not have any + * constraints. + * + * @param reference the reference to the policy + * @param policyType one of the two fields in this class + * @param constraints any optional constraints on the version of the + * referenced policy (this is never null, but + * it may impose no constraints, and in fact will + * never impose constraints when used from a pre-2.0 + * XACML policy) + * @param finder the PolicyFinder used to handle the reference + * @param parentMetaData the meta-data associated with the containing + * (parent) policy + * + * @throws IllegalArgumentException if the input policyType isn't valid + */ + public PolicyReference(URI reference, int policyType, + VersionConstraints constraints, PolicyFinder finder, + PolicyMetaData parentMetaData) + throws IllegalArgumentException { + + // check if input policyType is a valid value + if ((policyType != POLICY_REFERENCE) && + (policyType != POLICYSET_REFERENCE)) { + throw new IllegalArgumentException("Input policyType is not a" + + "valid value"); + } + this.reference = reference; + this.policyType = policyType; + this.constraints = constraints; + this.finder = finder; + this.parentMetaData = parentMetaData; + } + + /** + * The clone method. + * FIXME: this does no deep copy on the + * contraints, finder and parentMetaData. + * Should probably _not_ do a deep copy on finder. + * + * @return a copy of this object. + */ + public Object clone() { + PolicyReference clone = (PolicyReference)super.clone(); + clone.reference = this.reference; + clone.policyType = this.policyType; + clone.constraints = this.constraints; + clone.finder = this.finder; + clone.parentMetaData = this.parentMetaData; + return clone; + } + + + /** + * Creates an instance of a PolicyReference object based on + * a DOM node. + * + * @deprecated As of 2.0 you should avoid using this method and should + * instead use the version that takes a + * PolicyMetaData instance. This method will + * only work for XACML 1.x policies. + * + * @param root the DOM root of a PolicyIdReference or a + * PolicySetIdReference XML type + * @param finder the PolicyFinder used to handle the reference + * + * @return The PolicyReference object. + * + * @exception ParsingException if the node is invalid + */ + public static PolicyReference getInstance(Node root, PolicyFinder finder) + throws ParsingException + { + return getInstance(root, finder, new PolicyMetaData()); + } + + /** + * Creates an instance of a PolicyReference object based on + * a DOM node. + * + * @param root the DOM root of a PolicyIdReference or a + * PolicySetIdReference XML type + * @param finder the PolicyFinder used to handle the reference + * @param metaData the meta-data associated with the containing policy + * + * @return The PolicyReference object. + * + * @exception ParsingException if the node is invalid + */ + public static PolicyReference getInstance(Node root, PolicyFinder finder, + PolicyMetaData metaData) + throws ParsingException + { + URI reference = null; + int policyType; + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Cannot build a PolicyReference" + + "with a: " + root.getClass().getName() +" XML node" ); + } + // see what type of reference we are + String name = root.getLocalName(); + if (name.equals("PolicyIdReference")) { + policyType = POLICY_REFERENCE; + } else if (name.equals("PolicySetIdReference")) { + policyType = POLICYSET_REFERENCE; + } else { + throw new ParsingException("Unknown reference type: " + name); + } + + // next get the reference + try { + reference = new URI(root.getFirstChild().getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error while parsing Reference", e); + } + + // now get any constraints + NamedNodeMap map = root.getAttributes(); + String versionConstraint = null; + String earlyConstraint = null; + String lateConstraint = null; + + Node versionNode = map.getNamedItem("Version"); + if (versionNode != null) { + versionConstraint = versionNode.getNodeValue(); + } + + Node earlyNode = map.getNamedItem("EarliestVersion"); + if (earlyNode != null) { + earlyConstraint = earlyNode.getNodeValue(); + } + + Node lateNode = map.getNamedItem("LatestVersion"); + if (lateNode != null) { + lateConstraint = lateNode.getNodeValue(); + } + + VersionConstraints constraints = + new VersionConstraints(versionConstraint, earlyConstraint, + lateConstraint); + + // finally, create the reference + PolicyReference policyReference = new PolicyReference( + reference, policyType, constraints, finder, metaData); + policyReference.src = RuntimeInfo.getRuntimeInfo(policyReference, root, ELEMENT_TYPE.POLICY_REFERENCE); + //policyReference.setSourceLocator(RuntimeInfo.getRuntimeInfo(policyReference, root, ELEMENT_TYPE.POLICY_REFERENCE)); + return policyReference; + } + + /** + * Returns the refernce identitfier used to resolve the policy. + * + * @return the reference URI + */ + public URI getReference() { + return this.reference; + } + + /** + * Returns the version constraints associated with this reference. This + * will never be null, though the constraints may be empty. + * + * @return the version constraints + */ + public VersionConstraints getConstraints() { + return this.constraints; + } + + /** + * Returns whether this is a reference to a policy or to a policy set. + * + * @return the reference type, either POLICY_REFERENCE + * or POLICYSET_REFERENCE + */ + public int getReferenceType() { + return this.policyType; + } + + /** + * Returns the id of this policy. If the policy is invalid or can't be + * retrieved, then a runtime exception is thrown. + * + * @return the policy id + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public URI getId() { + return resolvePolicy(null).getId(); + } + + /** + * Returns the version of this policy. If the policy is invalid or can't + * be retrieved, then a runtime exception is thrown. + * + * @return the policy version + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public String getVersion() { + return resolvePolicy(null).getVersion(); + } + + /** + * Returns the combining algorithm used by this policy. If the policy is + * invalid or can't be retrieved, then a runtime exception is thrown. + * + * @return the combining algorithm + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public CombiningAlgorithm getCombiningAlg() { + return resolvePolicy(null).getCombiningAlg(); + } + + /** + * Returns the given description of this policy or null if there is no + * description. If the policy is invalid or can't be retrieved, then a + * runtime exception is thrown. + * + * @return the description or null + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public String getDescription() { + return resolvePolicy(null).getDescription(); + } + + /** + * Returns the PolicyIssuer if present or null if it is the trusted issuer. + * + * @return the PolicyIssuer or null + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public PolicyIssuer getPolicyIssuer() { + return resolvePolicy(null).getPolicyIssuer(); + } + + /** + * Returns the target for this policy. If the policy is invalid or can't be + * retrieved, then a runtime exception is thrown. + * + * @return the policy's target + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public Target getTarget() { + return resolvePolicy(null).getTarget(); + } + + /** + * Returns the default version for this policy. If the policy is + * invalid or can't be retrieved, then a runtime exception is thrown. + * + * @return the policy's default version + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public String getDefaultVersion() { + return resolvePolicy(null).getDefaultVersion(); + } + + /** + * Returns the child policy nodes under this node in the policy tree. If + * the policy is invalid or can't be retrieved, then a runtime exception + * is thrown. + * + * @return the List of child policy nodes + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public List getChildren() { + return resolvePolicy(null).getChildren(); + } + + /** + * Returns the child policy nodes and their associated parameters. If + * the policy is invalid or can't be retrieved, then a runtime exception + * is thrown. + * + * @return a List of CombinerElements + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public List getChildElements() { + return resolvePolicy(null).getChildElements(); + } + + /** + * Returns the Set of obligations for this policy, which may be empty if + * there are no obligations. If the policy is invalid or can't be + * retrieved, then a runtime exception is thrown. + * + * @return the policy's obligations + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public Set getObligations() { + return resolvePolicy(null).getObligations(); + } + + /** + * Returns the meta-data associated with this policy. If the policy is + * invalid or can't be retrieved, then a runtime exception is thrown. + * Note that this is the meta-data for the referenced policy, not the + * meta-data for the parent policy (which is what gets provided to the + * constructors of this class). + * + * @return the policy's meta-data + * + * @throws ProcessingException if the referenced policy can't be retrieved + */ + public PolicyMetaData getMetaData() { + return resolvePolicy(null).getMetaData(); + } + + /** + * Given the input context sees whether or not the request matches this + * policy. This must be called by combining algorithms before they + * evaluate a policy. This is also used in the initial policy finding + * operation to determine which top-level policies might apply to the + * request. If the policy is invalid or can't be retrieved, then a + * runtime exception is thrown. + * + * @param context the representation of the request + * + * @return the result of trying to match the policy and the request + */ + public MatchResult match(EvaluationCtx context) { + try { + return resolvePolicy(context).match(context); + } catch (ProcessingException pe) { + // this means that we couldn't resolve the policy + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + Status status = new Status(code, "couldn't resolve policy ref"); + MatchResult match = new MatchResult(MatchResult.INDETERMINATE, + status); + return match; + } + } + + /** + * Private helper method that tried to resolve the policy + */ + private AbstractPolicy resolvePolicy(EvaluationCtx context) { + if ( referencedPolicy != null ) { + return referencedPolicy; + } + // see if this reference was setup with a finder + if (this.finder == null) { + logger.warn("PolicyReference with id " + + this.reference.toString() + " was queried but " + + "was not configured with a PolicyFinder"); + throw new ProcessingException("couldn't find the policy with " + + "a null finder"); + } + + PolicyFinderResult pfr = this.finder.findPolicy(context, + this.reference, + this.policyType, + this.constraints, + this.parentMetaData); + + if (pfr.notApplicable()) { + throw new ProcessingException("couldn't resolve the policy"); + } + if (pfr.indeterminate()) { + throw new ProcessingException("error resolving the policy"); + } + referencedPolicy = pfr.getPolicy(); + return referencedPolicy; + } + + /** + * Tries to evaluate the policy by calling the combining algorithm on + * the given policies or rules. The match method must always + * be called first, and must always return MATCH, before this method + * is called. + * + * @param context the representation of the request + * + * @return the result of evaluation + */ + public Result evaluate(EvaluationCtx context) { + + try { + resolvePolicy(context); + } catch (ProcessingException pe) { + logger.fatal("Evaluation was called for PolicyReference with not resolved Policy: This should not happen as no target can have been matched!"); + List codes = new Vector(); + codes.add(Status.STATUS_PROCESSING_ERROR); + Status errorStatus = new Status(codes); + return new Result(Result.DECISION_INDETERMINATE, errorStatus, context); + } + + return referencedPolicy.evaluate(context); +// +// // if there is no finder, then we return NotApplicable +// if (this.finder == null) { +// return new Result(Result.DECISION_NOT_APPLICABLE, +// context); +// } +// PolicyFinderResult pfr = this.finder.findPolicy(this.reference, +// this.policyType, +// this.constraints, +// this.parentMetaData); +// +// // if we found nothing, then we return NotApplicable +// if (pfr.notApplicable()) { +// return new Result(Result.DECISION_NOT_APPLICABLE, context); +// } +// // if there was an error, we return that status data +// if (pfr.indeterminate()) { +// return new Result(Result.DECISION_INDETERMINATE, +// pfr.getStatus(), +// context); +// } +// // we must have found a policy +// return pfr.getPolicy().evaluate(context); + } + + /** + * Encodes this PolicyReference into its XML representation + * and writes this encoding to the given OutputStream with + * no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this PolicyReference into its XML representation + * and writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String encoded = indenter.makeString(); + + if (this.policyType == POLICY_REFERENCE) { + out.println(encoded + "" + this.reference.toString() + + ""); + } else { + out.println(encoded + "" + + this.reference.toString() + + ""); + } + } + + /** + * Private helper method that encodes the variable constraints info. Note + * that if this is a pre-2.0 policy the constraints are always null, so + * nothing will be added here. + */ + private String encodeConstraints() { + String str = ""; + VersionConstraints version = getConstraints(); + + String v = version.getVersionConstraint(); + if (v != null) { + str += " Version=\"" + v + "\""; + } + + String e = version.getEarliestConstraint(); + if (e != null) { + str += " EarliestVersion=\"" + e + "\""; + } + + String l = version.getLatestConstraint(); + if (l != null) { + str += " LatestVersion=\"" + l + "\""; + } + + return str; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicySet.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicySet.java new file mode 100644 index 0000000..6dc41c7 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicySet.java @@ -0,0 +1,696 @@ + +/* + * @(#)PolicySet.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.combine.CombinerElement; +import com.sun.xacml.combine.CombinerParameter; +import com.sun.xacml.combine.PolicyCombinerElement; +import com.sun.xacml.combine.PolicyCombiningAlgorithm; +import com.sun.xacml.ctx.PolicyIssuer; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import com.sun.xacml.finder.PolicyFinder; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents one of the two top-level constructs in XACML, the PolicySetType. + * This can contain other policies and policy sets, and can also contain + * URIs that point to policies and policy sets. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class PolicySet extends AbstractPolicy { + + //private static final Logger logger = Logger.getLogger(PolicySet.class); + + /** + * Creates a new PolicySet with only the required elements. + * + * @param id the policy set identifier + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param target the Target for this set + */ + public PolicySet(URI id, PolicyCombiningAlgorithm combiningAlg, + Target target) { + this(id, null, null, combiningAlg, null, null, target, null, null, + null); + } + + + /** + * Creates a new PolicySet with only the required elements. + * + * @param id the policy set identifier + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this set + */ + public PolicySet(URI id, PolicyCombiningAlgorithm combiningAlg, + PolicyIssuer issuer, Target target) { + this(id, null, null, combiningAlg, null, issuer, target, null, null, + null); + } + + /** + * Creates a new PolicySet with only the required elements, + * plus some policies. + * + * @param id the policy set identifier + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, PolicyCombiningAlgorithm combiningAlg, + Target target, List policies) { + this(id, null, null, combiningAlg, null, null, target, policies, + null, null); + } + + /** + * Creates a new PolicySet with only the required elements, + * plus some policies. + * + * @param id the policy set identifier + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, PolicyCombiningAlgorithm combiningAlg, + PolicyIssuer issuer, Target target, List policies) { + this(id, null, null, combiningAlg, null, issuer, target, policies, + null, null); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies and a String description. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, Target target, List policies) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, policies, null, null); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies and a String description. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, Target target, + List policies) { + this(id, version, xacmlVersion, combiningAlg, description, issuer, + target, policies, null, null); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies, a String description, and policy defaults. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * @param defaultVersion the XPath version to use + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, Target target, List policies, + String defaultVersion) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, policies, defaultVersion, null); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies, a String description, and policy defaults. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * @param defaultVersion the XPath version to use + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, + Target target, List policies, String defaultVersion) { + this(id, version, xacmlVersion, combiningAlg, description, issuer, + target, policies, defaultVersion, null); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies, a String description, policy defaults, and obligations. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * @param defaultVersion the XPath version to use + * @param obligations a set of Obligation objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, Target target, List policies, + String defaultVersion, Set obligations) { + this(id, version, xacmlVersion, combiningAlg, description, null, + target, policies, defaultVersion, obligations, null, -1); + } + + /** + * Creates a new PolicySet with the required elements plus + * some policies, a String description, policy defaults, and obligations. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * policies in this set + * @param description a String describing the policy + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this set + * @param policies a list of AbstractPolicy objects + * @param defaultVersion the XPath version to use + * @param obligations a set of Obligation objects + * + * @throws IllegalArgumentException if the List of policies + * contains an object that is not an + * AbstractPolicy + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, + Target target, List policies, String defaultVersion, + Set obligations) { + super(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, obligations, null, + Constants.MAX_DELEGATION_DEPTH_UNDEFINED); + + List list = null; + + // check that the list contains only AbstractPolicy objects + if (policies != null) { + list = new ArrayList(); + Iterator it = policies.iterator(); + while (it.hasNext()) { + Object o = it.next(); + if (! (o instanceof AbstractPolicy)) { + throw new IllegalArgumentException("non-AbstractPolicy " + + "in policies"); + } + list.add(new PolicyCombinerElement((AbstractPolicy)o)); + } + } + + setChildren(list); + } + + /** + * Creates a new PolicySet with the required and optional + * elements. If you need to provide combining algorithm parameters, you + * need to use this constructor. Note that unlike the other constructors + * in this class, the policies list is actually a list of + * CombinerElements used to match a policy with any + * combiner parameters it may have. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy or + * null if there is no description + * @param target the Target for this policy + * @param policyElements a list of CombinerElement objects or + * null if there are no policies + * @param defaultVersion the XPath version to use or null if there is + * no default version + * @param obligations a set of Obligations objects or null + * if there are no obligations + * @param parameters the List of + * CombinerParameters provided for general + * use by the combining algorithm + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, Target target, + List policyElements, String defaultVersion, + Set obligations, List parameters) { + this(id, version, xacmlVersion, combiningAlg, description, null, target, + policyElements, defaultVersion, obligations, parameters, + Constants.MAX_DELEGATION_DEPTH_UNDEFINED); + } + + /** + * Creates a new PolicySet with the required and optional + * elements. If you need to provide combining algorithm parameters, you + * need to use this constructor. Note that unlike the other constructors + * in this class, the policies list is actually a list of + * CombinerElements used to match a policy with any + * combiner parameters it may have. + * + * @param id the policy set identifier + * @param version the policy version or null for the default (this is + * always null for pre-2.0 policies) + * @param xacmlVersion the xacml version identifier. + * @param combiningAlg the CombiningAlgorithm used on the + * rules in this set + * @param description a String describing the policy or + * null if there is no description + * @param issuer the PolicyIssuer for this set or null if + * it is the trusted issuer + * @param target the Target for this policy + * @param policyElements a list of CombinerElement objects or + * null if there are no policies + * @param defaultVersion the XPath version to use or null if there is + * no default version + * @param obligations a set of Obligations objects or null + * if there are no obligations + * @param parameters the List of + * CombinerParameters provided for general + * use by the combining algorithm + * @param maxDelegationDepth the maximum delegation depth authorised + * by this policy set. + * + * @throws IllegalArgumentException if the List of rules + * contains an object that is not a + * Rule + */ + public PolicySet(URI id, String version, String xacmlVersion, + PolicyCombiningAlgorithm combiningAlg, + String description, PolicyIssuer issuer, + Target target, List policyElements, + String defaultVersion, Set obligations, + List parameters, int maxDelegationDepth) { + super(id, version, xacmlVersion, combiningAlg, description, issuer, + target, defaultVersion, obligations, parameters, + maxDelegationDepth); + + // check that the list contains only CombinerElements + if (policyElements != null) { + Iterator it = policyElements.iterator(); + while (it.hasNext()) { + CombinerElement o = it.next(); + if (! (o instanceof PolicyCombinerElement)) { + throw new IllegalArgumentException("non-AbstractPolicy " + + "in policies"); + } + } + } + + setChildren(policyElements); + } + + /** + * Creates a new PolicySet based on the given root node. This is + * private since every class is supposed to use a getInstance() method + * to construct from a Node, but since we want some common code in the + * parent class, we need this functionality in a constructor. + */ + private PolicySet(Node root, PolicyFinder finder) + throws ParsingException { + super(root, "PolicySet", "PolicyCombiningAlgId"); + + List policies = new ArrayList(); + Map> policyParameters = new HashMap>(); + Map> policySetParameters = new HashMap>(); + PolicyMetaData metaData = getMetaData(); + super.src = RuntimeInfo.getRuntimeInfo(this, root, ELEMENT_TYPE.POLICY_SET); + + // collect the PolicySet-specific elements + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + + if (child.getNodeType() == Node.ELEMENT_NODE) { + String name = child.getLocalName(); + if (name.equals("PolicySet")) { + policies.add(PolicySet.getInstance(child, finder)); + } else if (name.equals("Policy")) { + policies.add(Policy.getInstance(child)); + } else if (name.equals("PolicySetIdReference")) { + policies.add(PolicyReference.getInstance(child, finder, + metaData)); + } else if (name.equals("PolicyIdReference")) { + policies.add(PolicyReference.getInstance(child, finder, + metaData)); + } else if (name.equals("PolicyCombinerParameters")) { + paramaterHelper(policyParameters, child, "Policy"); + } else if (name.equals("PolicySetCombinerParameters")) { + paramaterHelper(policySetParameters, child, "PolicySet"); + } + } + } + + // now make sure that we can match up any parameters we may have + // found to a cooresponding Policy or PolicySet... + List elements = new ArrayList(); + + // right now we have to go though each policy and based on several + // possible cases figure out what paranmeters might apply...but + // there should be a better way to do this + + for ( AbstractPolicy policy : policies ) { + List list = null; + + if (policy instanceof Policy) { + list = policyParameters.remove(policy.getId().toString()); + } else if (policy instanceof PolicySet) { + list = policySetParameters.remove(policy.getId().toString()); + } else { + PolicyReference ref = (PolicyReference)policy; + String id = ref.getReference().toString(); + + if (ref.getReferenceType() == + PolicyReference.POLICY_REFERENCE) { + list = policyParameters.remove(id); + } else { + list = policySetParameters.remove(id); + } + } + elements.add(new PolicyCombinerElement(policy, list)); + } + + // ...and that there aren't extra parameters + if (! policyParameters.isEmpty()) { + throw new ParsingException("Unmatched parameters in Policy"); + } + if (! policySetParameters.isEmpty()) { + throw new ParsingException("Unmatched parameters in PolicySet"); + } + + // finally, set the list of Rules + setChildren(elements); + } + + /** + * The clone method. + * FIXME: caution this is no deep copy in the superclass. + * + * @return a copy of this object. + */ + public Object clone() { + PolicySet clone = (PolicySet)super.clone(); + clone.setChildren(this.getChildElements()); + return clone; + } + + /** + * Private helper method that handles parsing a collection of + * parameters + */ + private void paramaterHelper(Map> parameters, Node root, + String prefix) throws ParsingException { + String ref = null; + if (root.getAttributes().getNamedItem(prefix + "IdRef") != null) { + ref = root.getAttributes().getNamedItem(prefix + "IdRef") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute: " + + prefix + "IdRef not found"); + } + + if (parameters.containsKey(ref)) { + List list = parameters.get(ref); + parseParameters(list, root); + } else { + List list = new ArrayList(); + parseParameters(list, root); + parameters.put(ref, list); + } + } + + /** + * Private helper method that handles parsing a single parameter. + */ + private void parseParameters(List parameters, Node root) + throws ParsingException + { + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("CombinerParameter")) { + parameters.add(CombinerParameter.getInstance(node)); + } + } + } + + /** + * Creates an instance of a PolicySet object based on a + * DOM node. The node must be the root of PolicySetType XML object, + * otherwise an exception is thrown. This PolicySet will + * not support references because it has no PolicyFinder. + * + * @param root the DOM root of a PolicySetType XML type + * + * @return The PolicySet object. + * + * @throws ParsingException if the PolicySetType is invalid + */ + public static PolicySet getInstance(Node root) + throws ParsingException { + return getInstance(root, null); + } + + /** + * Creates an instance of a PolicySet object based on a + * DOM node. The node must be the root of PolicySetType XML object, + * otherwise an exception is thrown. The finder is used to handle + * policy references. + * + * @param root the DOM root of a PolicySetType XML type + * @param finder the PolicyFinder used to handle references + * + * @return The PolicySet object. + * + * @throws ParsingException if the PolicySetType is invalid + */ + public static PolicySet getInstance(Node root, PolicyFinder finder) + throws ParsingException { + // first off, check that it's the right kind of node + if (root.getNodeType() != Node.ELEMENT_NODE + && ! root.getLocalName().equals("PolicySet")) { + throw new ParsingException("Cannot create PolicySet from root of" + + " type " + root.getLocalName()); + } + + return new PolicySet(root, finder); + } + + /** + * Encodes this PolicySet into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this PolicySet into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.print(indent + ""); + + } else { + out.println(">"); + } + + indenter.in(); + String nextIndent = indenter.makeString(); + + String description = getDescription(); + if (description != null) { + out.println(nextIndent + "" + description + + ""); + } + encodePolicyIssuer(output, charsetName, indenter); + + String version = getDefaultVersion(); + if (version != null) { + out.println("" + version + + ""); + } + getTarget().encode(output, charsetName, indenter); + encodeCommonElements(output, charsetName, indenter); + + indenter.out(); + out.println(indent + ""); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyTreeElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyTreeElement.java new file mode 100644 index 0000000..166e7b1 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/PolicyTreeElement.java @@ -0,0 +1,149 @@ + +/* + * @(#)PolicyTreeElement.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.ctx.Result; +import com.sun.xacml.debug.Locatable; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.Collections; +import java.util.List; + + +/** + * This represents a single node in a policy tree. A node is either a policy + * set, a policy, or a rule. This interface is used to interact with these + * node types in a general way. Note that rules are leaf nodes in a policy + * tree as they never contain children. + * + * @since 1.1 + * @author seth proctor + */ +public interface PolicyTreeElement extends Locatable +{ + + public static List EMPTY_LIST = Collections.emptyList(); + + /** + * Returns the List of PolicyTreeElement objects + * that are the children of this node. If this node has no children then + * this list is empty. The children are returned as a List + * instead of some unordered collection because in cases like combining + * or evaluation the order is often important. + * + * @return the non-null List of children of this node + */ + public List getChildren(); + + /** + * Returns the given description of this element or null if + * there is no description + * + * @return the description or null + */ + public String getDescription(); + + /** + * Returns the id of this element + * + * @return the element's identifier + */ + public URI getId(); + + /** + * Returns the target for this element or null if there + * is no target + * + * @return the element's target + */ + public Target getTarget(); + + /** + * Given the input context sees whether or not the request matches this + * element's target. The rules for matching are different depending on + * the type of element being matched. + * + * @param context the representation of the request + * + * @return the result of trying to match this element and the request + */ + public MatchResult match(EvaluationCtx context); + + /** + * Evaluates this element in the policy tree, and therefore all elements + * underneath this element. The rules for evaluation are different + * depending on the type of element being evaluated. + * + * @param context the representation of the request we're evaluating + * + * @return the result of the evaluation + */ + public Result evaluate(EvaluationCtx context); + + /** + * Encodes this element into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException; + + /** + * Encodes this element into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform default character set + * will be used. + * @param indenter an object that creates indentation strings + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ProcessingException.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ProcessingException.java new file mode 100644 index 0000000..46462e5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ProcessingException.java @@ -0,0 +1,107 @@ + +/* + * @(#)ProcessingException.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + + +/** + * Runtime exception that's thrown if any unexpected error occurs. This could + * appear, for example, if you try to match a referernced policy that can't + * be resolved. + * + * @since 1.0 + * @author Seth Proctor + */ +public class ProcessingException extends RuntimeException +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new ProcessingException with no message + * or cause. + */ + public ProcessingException() { + //Processing exception with no message or cause + } + + /** + * Constructs a new ProcessingException with a message, + * but no cause. The message is saved for later retrieval by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} + * method. + * + * @param message the detail message (null if nonexistent + * or unknown) + */ + public ProcessingException(String message) { + super(message); + } + + /** + * Constructs a new ProcessingException with a cause, + * but no message. The cause is saved for later retrieval by the + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * method. + * + * @param cause the cause (null if nonexistent + * or unknown) + */ + public ProcessingException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new ProcessingException with a message + * and a cause. The message and cause are saved for later retrieval + * by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} and + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * methods. + * + * @param message the detail message (null if nonexistent + * or unknown) + * @param cause the cause (null if nonexistent + * or unknown) + */ + public ProcessingException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Rule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Rule.java new file mode 100644 index 0000000..8336b64 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Rule.java @@ -0,0 +1,509 @@ + +/* + * @(#)Rule.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.attr.BooleanAttribute; + +import com.sun.xacml.cond.Apply; +import com.sun.xacml.cond.Condition; +import com.sun.xacml.cond.EvaluationResult; +import com.sun.xacml.cond.VariableManager; + +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Represents the RuleType XACML type. This has a target for matching, and + * encapsulates the condition and all sub-operations that make up the heart + * of most policies. + * + * @since 1.0 + * @author Seth Proctor + */ +public class Rule implements PolicyTreeElement +{ + + // the attributes associated with this Rule + private URI idAttr; + private int effectAttr; + + // the elements in the rule, each of which is optional + private String description = null; + private Target target = null; + private Condition condition = null; + + private RuntimeInfo src = null; + + /** + * Creates a new Rule object for XACML 1.x and 2.0. + * + * @param id the rule's identifier + * @param effect the effect to return if the rule applies (either + * Pemit or Deny) as specified in Result + * @param description a textual description, or null + * @param target the rule's target, or null if the target is to be + * inherited from the encompassing policy + * @param condition the rule's condition, or null if there is none + */ + public Rule(URI id, int effect, String description, Target target, + Condition condition) { + this.idAttr = id; + this.effectAttr = effect; + this.description = description; + this.target = target; + this.condition = condition; + } + + /** + * Creates a new Rule object for XACML 1.x and 2.0. + * + * @param id the rule's identifier + * @param effect the effect to return if the rule applies (either + * Pemit or Deny) as specified in Result + * @param description a textual description, or null + * @param target the rule's target, or null if the target is to be + * inherited from the encompassing policy + * @param condition the rule's condition, or null if there is none + */ + public Rule(URI id, int effect, String description, Target target, + Condition condition, RuntimeInfo src) { + this.idAttr = id; + this.effectAttr = effect; + this.description = description; + this.target = target; + this.condition = condition; + this.src = src; + } + + /** + * Creates a new Rule object for XACML 1.x only. + * + * @deprecated As of 2.0 you should use the Constructor that accepts + * the new Condition class. + * + * @param id the rule's identifier + * @param effect the effect to return if the rule applies (either + * Pemit or Deny) as specified in Result + * @param description a textual description, or null + * @param target the rule's target, or null if the target is to be + * inherited from the encompassing policy + * @param condition the rule's condition, or null if there is none + */ + public Rule(URI id, int effect, String description, Target target, + Apply condition) { + this.idAttr = id; + this.effectAttr = effect; + this.description = description; + this.target = target; + this.condition = new Condition(condition.getFunction(), + condition.getChildren()); + } + + /** + * Returns a new instance of the Rule class based on a + * DOM node. The node must be the root of an XML RuleType. + * + * @deprecated As of 2.0 you should avoid using this method and should + * instead use the version that takes a + * PolicyMetaData instance. This method will + * only work for XACML 1.x policies. + * + * @param root the DOM root of a RuleType XML type + * @param xpathVersion the XPath version to use in any selectors or XPath + * functions, or null if this is unspecified (ie, not + * supplied in the defaults section of the policy) + * + * @return The Rule object. + * + * @throws ParsingException if the RuleType is invalid + */ + public static Rule getInstance(Node root, String xpathVersion) + throws ParsingException { + return getInstance(root, + new PolicyMetaData( + Constants.XACML_1_0_IDENTIFIER, + xpathVersion), + null); + } + + /** + * Returns a new instance of the Rule class based on a + * DOM node. The node must be the root of an XML RuleType. + * + * @param root the DOM root of a RuleType XML type + * @param metaData the meta-data associated with this Rule's policy + * @param manager the VariableManager used to connect + * VariableReferences to their cooresponding + * VariableDefinitions + * + * @return The Rule object. + * + * @throws ParsingException if the RuleType is invalid + */ + public static Rule getInstance(Node root, PolicyMetaData metaData, + VariableManager manager) throws ParsingException { + + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.RULE); + //check if we really got a rule + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a Rule from" + + " a node that is not an element-node" + + (src != null ? src.getLocationMsgForError() : "")); + } + if (!root.getLocalName().equals("Rule")) { + throw new ParsingException("Can't create a Rule from a " + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + + URI id = null; + int effect = 0; + String description = null; + Target target = null; + Condition condition = null; + + // first, get the attributes + NamedNodeMap attrs = root.getAttributes(); + + try { + // get the two required attrs... + id = new URI(attrs.getNamedItem("RuleId").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error parsing required attribute " + + "RuleId in a Rule" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + String str = null; + if (attrs.getNamedItem("Effect") != null) { + str = attrs.getNamedItem("Effect").getNodeValue(); + } else { + throw new ParsingException("Required attribute Effect missing" + + "while parsing a Rule" + + (src != null ? src.getLocationMsgForError() : "")); + } + + if (str.equals(Result.PERMIT)) { + effect = Result.DECISION_PERMIT; + } else if (str.equals(Result.DENY)) { + effect = Result.DECISION_DENY; + } else { + throw new ParsingException("Invalid Effect: " + effect + + (src != null ? src.getLocationMsgForError() : "")); + } + + // next, get the elements + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + String cname = child.getLocalName(); + if (cname.equals("Description")) { + description = child.getFirstChild().getNodeValue(); + } else if (cname.equals("Target")) { + target = Target.getInstance(child, metaData); + } else if (cname.equals("Condition")) { + condition + = Condition.getInstance(child, metaData, manager); + } else { + throw new ParsingException("Found invalid element: " + + cname + " in Rule " + id + + (src != null ? src.getLocationMsgForError() : "")); + } + } + } + Rule rule = new Rule(id, effect, description, target, condition, src); + if ( src != null ) { + src.setXACMLObject(rule); + } + return rule; + } + + /** + * Returns the effect that this Rule will return from + * the evaluate method (Permit or Deny) if the request applies. + * + * @return a decision effect, as defined in Result + */ + public int getEffect() { + return this.effectAttr; + } + + /** + * Returns the id of this Rule + * + * @return the rule id + */ + public URI getId() { + return this.idAttr; + } + + /** + * Returns the given description of this Rule or null if + * there is no description + * + * @return the description or null + */ + public String getDescription() { + return this.description; + } + + /** + * Returns the target for this Rule or null if there + * is no target + * + * @return the rule's target + */ + public Target getTarget() { + return this.target; + } + + /** + * Since a rule is always a leaf in a policy tree because it can have + * no children, this always returns an empty List. + * + * @return a List with no elements + */ + public List getChildren() { + return PolicyTreeElement.EMPTY_LIST; + } + + /** + * Returns the condition for this Rule or null if there + * is no condition + * + * @return the rule's condition + */ + public Condition getCondition() { + return this.condition; + } + + /** + * Given the input context sees whether or not the request matches this + * Rule's Target. Note that unlike the matching + * done by the evaluate method, if the Target + * is missing than this will return Indeterminate. This lets you write + * your own custom matching routines for rules but lets evaluation + * proceed normally. + * + * @param context the representation of the request + * + * @return the result of trying to match this rule and the request + */ + public MatchResult match(EvaluationCtx context) { + if (this.target == null) { + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + Status status = new Status(code, "no target available for " + + "matching a rule"); + return new MatchResult(MatchResult.INDETERMINATE, status); + } + return this.target.match(context); + } + + /** + * Evaluates the rule against the supplied context. This will check that + * the target matches, and then try to evaluate the condition. If the + * target and condition apply, then the rule's effect is returned in + * the result. + *

    + * Note that rules are not required to have targets. If no target is + * specified, then the rule inherits its parent's target. In the event + * that this Rule has no Target then the + * match is assumed to be true, since evaluating a policy tree to this + * level required the parent's target to match. + * + * @param context the representation of the request we're evaluating + * + * @return the result of the evaluation + */ + public Result evaluate(EvaluationCtx context) { + context.newEvent(this); + // If the Target is null then it's supposed to inherit from the + // parent policy, so we skip the matching step assuming we wouldn't + // be here unless the parent matched + if (this.target != null) { + MatchResult match = match(context); + int result = match.getResult(); + + // if the target didn't match, then this Rule doesn't apply + if (result == MatchResult.NO_MATCH) { + Result evalResult = new Result(Result.DECISION_NOT_APPLICABLE, + context); + context.closeCurrentEvent(evalResult); + return evalResult; + } + // if the target was indeterminate, we can't go on + if (result == MatchResult.INDETERMINATE) { + Result evalResult = new Result(Result.DECISION_INDETERMINATE, + match.getStatus(), + context); + context.closeCurrentEvent(evalResult); + return evalResult; + } + } + + // if there's no condition, then we just return the effect... + if (this.condition == null) { + Result evalResult = new Result(this.effectAttr, + context); + context.closeCurrentEvent(evalResult); + return evalResult; + } + + // ...otherwise we evaluate the condition + EvaluationResult result = this.condition.evaluate(context); + + if (result.indeterminate()) { + // if it was INDETERMINATE, then that's what we return + Result evalResult = new Result(Result.DECISION_INDETERMINATE, + result.getStatus(), + context); + context.closeCurrentEvent(evalResult); + return evalResult; + } + // otherwise we return the effect on true, and NA on false + BooleanAttribute bool = + (BooleanAttribute)(result.getAttributeValue()); + + if (bool.getValue()) { + Result evalResult = new Result(this.effectAttr, + context); + context.closeCurrentEvent(evalResult); + return evalResult; + + } + Result evalResult = new Result(Result.DECISION_NOT_APPLICABLE, + context); + context.closeCurrentEvent(evalResult); + return evalResult; + } + + /** + * Encodes this Rule into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Rule into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.print(indent + ""); + + indenter.in(); + String nextIndent = indenter.makeString(); + + if (this.description != null) { + out.println(nextIndent + "" + this.description + + ""); + } + + if (this.target != null) { + this.target.encode(output, charsetName, indenter); + } + + if (this.condition != null) { + this.condition.encode(output, charsetName, indenter); + } + + indenter.out(); + out.println(indent + ""); + } else { + // the Rule is empty, so close the tag and we're done + out.println("/>"); + } + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/Target.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/Target.java new file mode 100644 index 0000000..d5ab427 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/Target.java @@ -0,0 +1,390 @@ + +/* + * @(#)Target.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +//import org.apache.log4j.Logger; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +/** + * Represents the TargetType XML type in XACML. This also stores several + * other XML types: The matching categories (e.g. Subjects, Resources, + * Actions, Environments, Delegates). The target is used to quickly + * identify whether the parent element (a policy set, policy, or rule) is + * applicable to a given request. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class Target implements Cloneable, MatchElement +{ + + /** + * A List containing TargetSections. + * These represent the disjunctive sections of this target. + */ + private List targetElements; + + /** + * The version of XACML of the policy containing this target + */ + private int xacmlVersion = Constants.XACML_DEFAULT_VERSION; + + + private RuntimeInfo src; + +// /** +// * The logger we'll use for all messages +// */ +// private static final Logger logger = +// Logger.getLogger(Target.class.getName()); + + /** + * Constructor that creates a Target from components. + * + * @param targetSections A List of + * TargetSections can be null. + */ + public Target(List targetSections) { + this(targetSections, Constants.XACML_DEFAULT_VERSION); + } + + /** + * Constructor that creates a Target from components. + * + * @param targetSections A List of + * TargetSections can be null. + * @param xacmlVersion The XACML version (for encoding). + */ + public Target(List targetSections, int xacmlVersion) { + if (targetSections != null) { + this.targetElements = new ArrayList(targetSections); + } else { + this.targetElements = TargetSection.EMPTY_LIST; + } + + this.xacmlVersion = xacmlVersion; + } + + /** + * The clone method constructor + * + * FIXME: this does no deep copy on the Lists and Sets. + * + * @return a copy of this object. + */ + public Object clone() { + try { + Target clone = (Target)super.clone(); + clone.targetElements = new ArrayList(this.targetElements); + clone.xacmlVersion = this.xacmlVersion; + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone Target"); + } + } + + + /** + * Creates a Target by parsing a node. + * + * @param root The node to parse for the Target + * @param metaData The policy meta data. + * @return a new Target constructed by parsing + * + * @throws ParsingException if the DOM node is invalid + */ + public static Target getInstance(Node root, PolicyMetaData metaData) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.TARGET); + // first check we really got a Target + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a Target from" + + " a node that is not an element-node" + + (src != null ? src.getLocationMsgForError() : "")); + } + if (!root.getLocalName().equals("Target")) { + throw new ParsingException("Can't create a Target from a " + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + List targetElements = new ArrayList(); + + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + targetElements.add(TargetSection.getInstance(child, metaData)); + } + } + Target target = new Target(targetElements, metaData.getXACMLVersion()); + if (src != null ) { + target.src = src; + src.setXACMLObject(target); + } + return target; + } + + /** + * Returns the Map of TargetSections for + * this target, keyed by category. + * + * @return the Map of TargetSections. + */ + public List getTargetSections() { + return Collections.unmodifiableList(this.targetElements); + } + + /** + * Returns whether or not this Target matches any request. + * + * @return true if this Target matches any request, false otherwise + */ + //TODO changed function + /*public boolean matchesAny() { + return this.targetElements.isEmpty(); + } */ + + public boolean matchesAny() { + if ( this.targetElements.isEmpty() ) { + return true; + } else { + for ( TargetSection element : targetElements ) { + if ( ! element.matchesAny() ) { + return false; + } + } + return true; + } + } + //TODO changed function + + /** + * Determines whether this Target matches + * the input request (whether it is applicable). + * + * @param context the representation of the request + * + * @return the result of trying to match the target and the request + */ + public MatchResult match(EvaluationCtx context) { + context.newEvent(this); + MatchResult result = null; + + // before matching, see if this target matches any request + if (this.matchesAny()) { + result = new MatchResult(MatchResult.MATCH); + context.closeCurrentEvent(result); + return result; + } + Iterator it = this.targetElements.iterator(); + while (it.hasNext()) { + TargetSection section + = (TargetSection)it.next(); + context.newEvent(section); + result = section.match(context); + context.closeCurrentEvent(result); + if (result.getResult() != MatchResult.MATCH) { +// logger.debug("failed to match a disjunctive section " +// + "of the target"); + context.closeCurrentEvent(result); + return result; + } + + } + + // if we got here, then everything matched + result = new MatchResult(MatchResult.MATCH); + context.closeCurrentEvent(result); + return result; + } + + /** + * Encodes this Target into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Target into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + indenter.out(); + String indent1 = indenter.makeString(); + indenter.out(); + String indent2 = indenter.makeString(); + indenter.in(); + indenter.in(); + + + if (this.matchesAny()) { + if (this.xacmlVersion > Constants.XACML_VERSION_1_1) { + //since 2.0, if all the sections match any request, then the Target + //element is empty and should be encoded simply as en empty tag + out.println(indent + ""); + } else { + out.println(indent + ""); + out.println(indent1 + ""); + out.println(indent2 + ""); + out.println(indent1 + ""); + out.println(indent1 + ""); + out.println(indent2 + ""); + out.println(indent1 + ""); + out.println(indent1 + ""); + out.println(indent2 + ""); + out.println(indent1 + ""); + out.println(indent + ""); + } + } else { + out.println(indent + ""); + indenter.in(); + + if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { + TargetSection subject = null; + TargetSection resource = null; + TargetSection action = null; + TargetSection environment = null; + //fetch subject, resource and action + for (int i=0; i"); + out.println(indent2 + ""); + out.println(indent1 + ""); + } + if (resource != null) { + resource.encode(output, charsetName, indenter); + } else if (this.xacmlVersion < Constants.XACML_VERSION_2_0) { + out.println(indent1 + ""); + out.println(indent2 + ""); + out.println(indent1 + ""); + } + if (action != null) { + action.encode(output, charsetName, indenter); + } else if (this.xacmlVersion < Constants.XACML_VERSION_2_0) { + out.println(indent1 + ""); + out.println(indent2 + ""); + out.println(indent1 + ""); + } + if (environment != null + && this.xacmlVersion == Constants.XACML_VERSION_2_0) { + environment.encode(output, charsetName, indenter); + } + } else { + Iterator it = this.targetElements.iterator(); + while (it.hasNext()) { + TargetSection section + = (TargetSection)it.next(); + section.encode(output, charsetName, indenter); + } + } + indenter.out(); + out.println(indent + ""); + } + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatch.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatch.java new file mode 100644 index 0000000..8d4921e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatch.java @@ -0,0 +1,537 @@ + +/* + * @(#)TargetMatch.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeSelector; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.BooleanAttribute; + +import com.sun.xacml.cond.Evaluatable; +import com.sun.xacml.cond.EvaluationResult; +import com.sun.xacml.cond.Expression; +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.FunctionFactory; +import com.sun.xacml.cond.FunctionTypeException; + +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the Match XML type in XACML. This is the part of the Target that + * actually evaluates whether the specified attribute values in the Target match + * the corresponding attribute values in the request context. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class TargetMatch implements MatchElement +{ + + /** + * The function used for matching. + */ + private Function function; + + /** + * The AttributeDesignator or + * AttributeSelector to be used to select + * attributes from the request context + */ + private Evaluatable eval; + + /** + * The value to compare against. + */ + private AttributeValue attrValue; + + /** + * The xacml version for encoding. + */ + private int xacmlVersion; + + /** + * The match category. Used only for backwards compatibility. + */ + private URI category; + + private RuntimeInfo src; + + /** + * Constructor that creates a default versionTargetMatch + * from components. + * + * @param function the Function that represents the MatchId + * @param eval the AttributeDesignator or + * AttributeSelector to be used to select + * attributes from the request context + * @param attrValue the AttributeValue to compare against + * + * @throws IllegalArgumentException if the input type isn't a valid value + */ + public TargetMatch(Function function, Evaluatable eval, + AttributeValue attrValue) + throws IllegalArgumentException { + this(function, eval, attrValue, Constants.XACML_DEFAULT_VERSION, + null); + } + + + + /** + * Constructor that creates a TargetMatch from components. + * + * @param function the Function that represents the MatchId + * @param eval the AttributeDesignator or + * AttributeSelector to be used to select + * attributes from the request context + * @param attrValue the AttributeValue to compare against + * @param xacmlVersion The XACML version number. + * @param category The category of this match (e.g. "Subject") for + * XACML versions 2.0 and earlier. Is null for + * later versions. + * + * @throws IllegalArgumentException if the input type isn't a valid value + */ + public TargetMatch(Function function, Evaluatable eval, + AttributeValue attrValue, int xacmlVersion, + URI category) + throws IllegalArgumentException { + + this.function = function; + this.eval = eval; + this.attrValue = attrValue; + this.xacmlVersion = xacmlVersion; + this.category = category; + } + + /** + * Creates a TargetMatch by parsing a node, using the + * input prefix to determine which category of match this is. + * + * @param root The node to parse for the TargetMatch + * @param metaData The policy's meta-data + * @param masterCategory The category of the TargetMatchGroup, for + * checking consistency. + * + * @return a new TargetMatch constructed by parsing + * + * @throws ParsingException if there was an error during parsing + */ + public static TargetMatch getInstance(Node root, + PolicyMetaData metaData, URI masterCategory) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.TARGET_MATCH); + // first make sure the node passed is indeed a TargetMatch + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a TargetMatch from" + + " a node that is not an element-node" + + (src != null ? src.getLocationMsgForError() : "")); + } + if (!root.getLocalName().endsWith("Match")) { + throw new ParsingException("Can't create a TargetMatch from a " + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + Function function; + Evaluatable eval = null; + AttributeValue attrValue = null; + + AttributeFactory attrFactory = AttributeFactory.getInstance(); + + // get the function type, making sure that it's really a correct + // Target function + String funcName = null; + if (root.getAttributes().getNamedItem("MatchId") != null) { + funcName = root.getAttributes().getNamedItem("MatchId") + .getNodeValue(); + } else { + throw new ParsingException("Required XML attribute " + + "MatchId not found while parsing a TargetMatch" + + (src != null ? src.getLocationMsgForError() : "")); + } + + FunctionFactory factory = FunctionFactory.getTargetInstance(); + try { + URI funcId = new URI(funcName); + function = factory.createFunction(funcId); + } catch (URISyntaxException use) { + throw new ParsingException("Error parsing TargetMatch" + + (src != null ? src.getLocationMsgForError() : ""), use); + } catch (UnknownIdentifierException uie) { + throw new ParsingException("Unknown MatchId" + + (src != null ? src.getLocationMsgForError() : ""), uie); + } catch (FunctionTypeException fte) { + // try to create an abstract function + try { + URI funcId = new URI(funcName); + function = factory.createAbstractFunction(funcId, root); + } catch (Exception e) { + // any exception here is an error + throw new ParsingException("invalid abstract function" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + } + + // next, get the designator or selector being used, and the attribute + // value paired with it + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + String name = node.getLocalName(); + // endsWith() is compatibility code for XACML 2.0 + if (name.endsWith("AttributeDesignator")) { + if (name.equals("AttributeDesignator")) { + if (metaData.getXACMLVersion() + < Constants.XACML_VERSION_3_0) { + throw new ParsingException( + "Can't create a < XACML 3.0 " + + "AttributeDesignator out of a " + + name + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + } else { // XACML 2.0 compatibility + if (metaData.getXACMLVersion() + > Constants.XACML_VERSION_2_0) { + throw new ParsingException( + "Can't create a > XACML 2.0 " + + "AttributeDesignator out of a " + + name + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + String categoryStr + = name.replaceAll("AttributeDesignator", ""); + URI category = null; + if (categoryStr.equals("Subject")) { + category = Constants.SUBJECT_CAT; + } else if (categoryStr.equals("Resource")) { + category = Constants.RESOURCE_CAT; + } else if (categoryStr.equals("Action")) { + category = Constants.ACTION_CAT; + } else if (categoryStr.equals("Environment")){ + category = Constants.ENVIRONMENT_CAT; + } else { + throw new ParsingException("Can't create a " + + "< XACML 3.0 AttributeDesignator out of" + + " a " + categoryStr + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + + if (!category.equals(masterCategory)) { + throw new ParsingException(categoryStr + "Match" + + " can't be located in enclosing " + + masterCategory.toString() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + } + eval = AttributeDesignator.getInstance(node, metaData); + } else if (name.equals("AttributeSelector")) { + eval = AttributeSelector.getInstance(node, metaData); + } else if (name.equals("AttributeValue")) { + try { + attrValue = attrFactory.createValue(node); + } catch (UnknownIdentifierException uie) { + throw new ParsingException( + "Unknown Attribute Type" + + (src != null ? src.getLocationMsgForError() : ""), uie); + } + } else { + throw new ParsingException("Encountered: '" + + name + "' node while parsing a TargetMatch" + + (src != null ? src.getLocationMsgForError() : "")); + } + } + } + + // finally, check that the inputs are valid for this function + List inputs = new ArrayList(); + inputs.add(attrValue); + inputs.add(eval); + function.checkInputsNoBag(inputs, src); + + TargetMatch targetMatch = new TargetMatch(function, eval, attrValue, + metaData.getXACMLVersion(), masterCategory); + if ( src != null ) { + targetMatch.src = src; + src.setXACMLObject(targetMatch); + } + return targetMatch; + } + + /** + * Returns the Function used to do the matching. + * + * @return the match function + */ + public Function getMatchFunction() { + return this.function; + } + + /** + * Returns the AttributeValue used by the matching function. + * + * @return the AttributeValue for the match + */ + public AttributeValue getMatchValue() { + return this.attrValue; + } + + /** + * Returns the AttributeDesignator or + * AttributeSelector used by the matching function. + * + * @return the designator or selector for the match + */ + public Evaluatable getMatchEvaluatable() { + return this.eval; + } + + /** + * Returns the category of this match. + * + * @return the category of this match. + */ + public URI getCategory() { + return this.category; + } + + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + /** + * Determines whether this TargetMatch matches + * the input request (whether it is applicable) + * + * @param context the representation of the request + * + * @return the result of trying to match the TargetMatch and the request + */ + public MatchResult match(EvaluationCtx context) { + // start by evaluating the AD/AS + EvaluationResult result = this.eval.evaluate(context); + + if (result.indeterminate()) { + // in this case, we don't ask the function for anything, and we + // simply return INDETERMINATE + return new MatchResult(MatchResult.INDETERMINATE, + result.getStatus()); + } + + // an AD/AS will always return a bag + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + + if (! bag.isEmpty()) { + // we got back a set of attributes, so we need to iterate through + // them, seeing if at least one matches + Iterator it = bag.iterator(); + boolean atLeastOneError = false; + Status firstIndeterminateStatus = null; + + while (it.hasNext()) { + ArrayList inputs = new ArrayList(); + + inputs.add(this.attrValue); + inputs.add(it.next()); + + // do the evaluation + MatchResult match = evaluateMatch(inputs, context); + + // we only need one match for this whole thing to match + if (match.getResult() == MatchResult.MATCH) { + return match; + } + + // if it was INDETERMINATE, we want to remember for later + if (match.getResult() == MatchResult.INDETERMINATE) { + atLeastOneError = true; + + // there are no rules about exactly what status data + // should be returned here, so like in the combining + // algs, we'll just track the first error + if (firstIndeterminateStatus == null) { + firstIndeterminateStatus = match.getStatus(); + } + } + } + + // if we got here, then nothing matched, so we'll either return + // INDETERMINATE or NO_MATCH + if (atLeastOneError) { + return new MatchResult(MatchResult.INDETERMINATE, + firstIndeterminateStatus); + } + return new MatchResult(MatchResult.NO_MATCH); + + } + // this is just an optimization, since the loop above will + // actually handle this case, but this is just a little + // quicker way to handle an empty bag + return new MatchResult(MatchResult.NO_MATCH); + } + + /** + * Private helper that evaluates an individual match. + */ + private MatchResult evaluateMatch(List inputs, EvaluationCtx context) { + + RuntimeInfo funcSrc = null; + //set (context dependent) source locator for function + if ( src != null ) { + //funcSrc = RuntimeInfo.getIndirectSourceLocator(src, ELEMENT_TYPE.FUNCTION); + funcSrc = src.getIndirectRuntimeInfo(function, ELEMENT_TYPE.FUNCTION); + this.function.setRuntimeInfo(funcSrc); + } + + // first off, evaluate the function + EvaluationResult result = this.function.evaluate(inputs, context); + + //unset source locator + if ( funcSrc != null ) { + this.function.unsetRuntimeInfo(funcSrc) ; + } + + // if it was indeterminate, then that's what we return immediately + if (result.indeterminate()) { + return new MatchResult(MatchResult.INDETERMINATE, + result.getStatus()); + } + + // otherwise, we figure out if it was a match + BooleanAttribute bool = (BooleanAttribute)(result.getAttributeValue()); + + if (bool.getValue()) { + return new MatchResult(MatchResult.MATCH); + } + return new MatchResult(MatchResult.NO_MATCH); + } + + /** + * Encodes this TargetMatch into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this TargetMatch into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + String closingTag = null; + + if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { + if (this.category.equals(Constants.SUBJECT_CAT)) { + out.print(indent + ""); + indenter.in(); + + this.attrValue.encode(output, charsetName, indenter); + this.eval.encode(output, charsetName, indenter); + + indenter.out(); + out.println(indent + closingTag); + } +} \ No newline at end of file diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatchGroup.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatchGroup.java new file mode 100644 index 0000000..5857e88 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetMatchGroup.java @@ -0,0 +1,330 @@ + +/* + * @(#)TargetMatchGroup.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + + +/** + * This class contains a group of TargetMatch instances and + * represents the different elements in an XACML Target (e.g. Subject) + * + * @since 2.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class TargetMatchGroup implements MatchElement +{ + + /** + * The list of TargetMatches. + */ + private List matches; + + /** + * The XACML version number. Only used for encoding. + */ + private int xacmlVersion; + + /** + * The category. Only used for encoding XACML versions < 3.0 + */ + private URI category; + + public static final List EMPTY_LIST = Collections.emptyList(); + + private RuntimeInfo src; + + /** + * Constructor that creates a new TargetMatchGroup based + * on the given elements with the default XACML version. + * + * @param matchElements A List of TargetMatch. + * They should all have the same category. + */ + public TargetMatchGroup(List matchElements) { + this(matchElements, Constants.XACML_DEFAULT_VERSION, null); + } + /** + * Constructor that creates a new TargetMatchGroup based + * on the given elements. + * + * @param matchElements A List of TargetMatch. + * They should all have the same category. + * @param xacmlVersion The XACML version number. + * @param category The category if this match group. + * This is null for XACML version > 2.0. + */ + public TargetMatchGroup(List matchElements, int xacmlVersion, + URI category) { + if (matchElements == null) { + this.matches = Collections.unmodifiableList(new ArrayList()); + } else { + this.matches = + Collections.unmodifiableList(new ArrayList(matchElements)); + } + + this.xacmlVersion = xacmlVersion; + this.category = category; + if (this.category == null + && this.xacmlVersion < Constants.XACML_VERSION_3_0) { + throw new IllegalArgumentException("Can't create TargetSections" + + " in XACML version < 3.0 without category"); + } + } + + /** + * Creates a Target based on its DOM node. + * + * @param root The node to parse for the target group. + * @param metaData Meta-data associated with the policy. + * @param masterCategory The category of the TargetSection, for + * checking consistency. + * + * @return a new TargetMatchGroup constructed by parsing + * + * @throws ParsingException if the DOM node is invalid + */ + public static TargetMatchGroup getInstance(Node root, + PolicyMetaData metaData, + URI masterCategory) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.TARGET_MATCH_GROUP ); + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a TargetMatchGroup from" + + " a node that is not an element-node" + + (src != null ? src.getLocationMsgForError() : "")); + } + List matches = new ArrayList(); + NodeList children = root.getChildNodes(); + String categoryStr = root.getLocalName(); + + if (!categoryStr.equals("AllOf")) { //XACML v2.0 or lower + if (metaData.getXACMLVersion() + > Constants.XACML_VERSION_2_0) { + throw new ParsingException("Can't create a > XACML 2.0" + + " TargetMatchGroup form a " + categoryStr + + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + + URI category = null; + if (categoryStr.equals("Subject")) { + category = Constants.SUBJECT_CAT; + } else if (categoryStr.equals("Resource")) { + category = Constants.RESOURCE_CAT; + } else if (categoryStr.equals("Action")) { + category = Constants.ACTION_CAT; + } else if (categoryStr.equals("Environment")){ + category= Constants.ENVIRONMENT_CAT; + } else { + throw new ParsingException("Can't create a < XACML 3.0" + + " TargetMatchGroup from a " + categoryStr + + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + + if (!category.equals(masterCategory)) { + throw new ParsingException(categoryStr + " element must" + + " can't be in enclosing " + + masterCategory.toString() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + } else if (categoryStr.equals("AllOf") + && (metaData.getXACMLVersion() + < Constants.XACML_VERSION_3_0)) { + throw new ParsingException("Can't create a < XACML 3.0" + + " TargetMatchGroup from a " + categoryStr + + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + matches.add(TargetMatch.getInstance(child, metaData, + masterCategory)); + } + } + + TargetMatchGroup targetMatchGroup = new TargetMatchGroup(matches, + metaData.getXACMLVersion(), masterCategory); + if ( src != null ) { + targetMatchGroup.src = src; + src.setXACMLObject(targetMatchGroup); + } + return targetMatchGroup; + } + + /** + * Determines whether this TargetMatchGroup matches + * the input request (whether it is applicable). + * + * @param context the representation of the request + * + * @return the result of trying to match the group with the context + */ + public MatchResult match(EvaluationCtx context) { + //TODO changed function + if ( this.matches.size() == 0 ) { + return new MatchResult(MatchResult.MATCH); + } + //TODO changed function + Iterator it = this.matches.iterator(); + MatchResult result = null; + + while (it.hasNext()) { + TargetMatch tm = (TargetMatch)(it.next()); + context.newEvent(tm); + result = tm.match(context); + context.closeCurrentEvent(result); + if (result.getResult() != MatchResult.MATCH) { + break; + } + } + + return result; + } + + /** + * Returns the category of this group. + * + * @return the category of this group. + */ + public URI getCategory() { + return this.category; + } + + /** + * Encodes this TargetMatchGroup into its XML representation + * and writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this TargetMatchGroup into its XML representation + * and writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + Iterator it = this.matches.iterator(); + String closingTag = null; + + if (this.xacmlVersion > Constants.XACML_VERSION_2_0) { + out.println(indent + ""); + closingTag = ""; + } else { // XACML 2.0 and below compatibility code + if (this.category.equals(Constants.SUBJECT_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.RESOURCE_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.ACTION_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.ENVIRONMENT_CAT)) { + out.println(indent + ""); + closingTag = ""; + } + } + + indenter.in(); + + while (it.hasNext()) { + TargetMatch tm = (TargetMatch)(it.next()); + tm.encode(output, charsetName, indenter); + } + out.println(indent + closingTag); + indenter.out(); + } + + /** + * Returns the matches of this match group. + * @return The list of TargetMatches. + */ + public List getMatches() { + return Collections.unmodifiableList(this.matches); + } + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetSection.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetSection.java new file mode 100644 index 0000000..f683f5f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/TargetSection.java @@ -0,0 +1,382 @@ + +/* + * @(#)TargetSection.java + * + * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * This is a container class for instances of TargetMatchGroup + * and represents the matching categories sections of an XACML Target + * (e.g. Subjects, Resources, Actions, Environments, Delegates). + * This section may apply to any request. + * + * @since 2.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class TargetSection implements MatchElement +{ + + /** + * The list of match groups + */ + private List matchGroups; + + /** + * The XACML version of this target section + * for encoding older XACML versions + */ + private int xacmlVersion; + + /** + * The category of this target section + */ + private URI category; + + public static final List EMPTY_LIST = Collections.emptyList(); + + private RuntimeInfo src; + + /** + * Constructor that takes a group and a version. If the group is + * null or empty, then this represents a section that matches any request. + * + * @param matchGroups A possibly null List of + * TargetMatchGroups. + */ + public TargetSection(List matchGroups) { + this(matchGroups, null, Constants.XACML_DEFAULT_VERSION); + } + + /** + * Constructor that takes a group and a version. If the group is + * null or empty, then this represents a section that matches any request. + * + * @param matchGroups A possibly null List of + * TargetMatchGroups. + * @param category The category of this target section. + * @param xacmlVersion The XACML version of this TargetSection + * (for encoding). + */ + public TargetSection(List matchGroups, URI category, int xacmlVersion) { + if (matchGroups == null) { + this.matchGroups = TargetMatchGroup.EMPTY_LIST; + } else { + this.matchGroups = Collections. + unmodifiableList(new ArrayList(matchGroups)); + } + this.category = category; + this.xacmlVersion = xacmlVersion; + if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { + if (this.category == null) { + throw new IllegalArgumentException("Can't create TargetSections" + + " in XACML version < 3.0 without category"); + } + if (!this.category.toString().startsWith( + "urn:oasis:names:tc:xacml:1.0:subject-category:") + && !this.category.equals(Constants.RESOURCE_CAT) + && !this.category.equals(Constants.ACTION_CAT)) { + if (this.xacmlVersion == Constants.XACML_VERSION_2_0) { + if (!this.category.equals(Constants.ENVIRONMENT_CAT)) { + throw new IllegalArgumentException("Illegal" + + " Category: " + + this.category.toString() + + " for pre XACML 3.0 policy"); + } + } else { + throw new IllegalArgumentException("Illegal" + + " Category: " + + this.category.toString() + + " for pre XACML 3.0 policy"); + } + } + } + } + + /** + * Creates a Target by parsing a node. + * + * @param root The node to parse for the Target. + * @param metaData The meta-data from the enclosing policy. + * + * @return a new Target constructed by parsing + * + * @throws ParsingException if the DOM node is invalid + */ + public static TargetSection getInstance(Node root, PolicyMetaData metaData) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.TARGET_SECTION); + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a TargetSection from" + + " a node that is not an element-node" + + (src != null ? src.getLocationMsgForError() : "")); + } + List groups = new ArrayList(); + NodeList children = root.getChildNodes(); + String categoryStr = null; + URI category = null; + if (metaData.getXACMLVersion() > Constants.XACML_VERSION_2_0) { + if (!root.getLocalName().equals("AnyOf")) { + throw new ParsingException("Found: " + root.getLocalName() + + " tag where expecting AnyOf tag" + + (src != null ? src.getLocationMsgForError() : "")); + } + } else { + //Get node name minus the tailing 's' + categoryStr = root.getLocalName(); + categoryStr = categoryStr.substring(0, categoryStr.length()-1); + + if (categoryStr.equals("Subject")) { + category = Constants.SUBJECT_CAT; + } else if (categoryStr.equals("Resource")) { + category = Constants.RESOURCE_CAT; + } else if (categoryStr.equals("Action")) { + category = Constants.ACTION_CAT; + } else if (metaData.getXACMLVersion() + == Constants.XACML_VERSION_2_0 + && categoryStr.equals("Environment")) { + category = Constants.ENVIRONMENT_CAT; + } else { + throw new ParsingException("Invalid element: " + + root.getLocalName() + + "for XACML version:" + metaData.getXACMLVersion() + + (src != null ? src.getLocationMsgForError() : "")); + } + } + + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + //check for Any* elements as children + if (metaData.getXACMLVersion() < Constants.XACML_VERSION_2_0) { + if (child.getLocalName().startsWith("Any")) { + TargetSection targetSection = new TargetSection(groups, + category, metaData.getXACMLVersion()); + targetSection.src = src; + return targetSection; + } + } + groups.add(TargetMatchGroup.getInstance(child, metaData, + category)); + } + } + + // at this point the list is non-empty (it has specific groups to + // match) or is empty + TargetSection targetSection = new TargetSection(groups, + category, metaData.getXACMLVersion()); + if ( src != null ) { + targetSection.src = src; + src.setXACMLObject(targetSection); + } + return targetSection; + } + + /** + * Returns the TargetMatchGroups contained in this group. + * + * @return a List of TargetMatchGroups + */ + public List getMatchGroups() { + return this.matchGroups; + } + + /** + * Returns whether this section matches any request. + * + * @return true if this section matches any request, false otherwise + */ + public boolean matchesAny() { + return this.matchGroups.isEmpty(); + } + + /** + * Returns the category of this section. + * + * @return the category of this section. + */ + public URI getCategory() { + return this.category; + } + + /** + * Determines whether this TargetSection matches + * the input request (whether it is applicable). + * + * @param context the representation of the request + * + * @return the result of trying to match the target and the request + */ + public MatchResult match(EvaluationCtx context) { + // if we apply to anything, then we always match + if (this.matchGroups.isEmpty()) { + return new MatchResult(MatchResult.MATCH); + } + + // there are specific matching elements, so prepare to iterate + // through the list + Iterator it = this.matchGroups.iterator(); + Status firstIndeterminateStatus = null; + + // in order for this section to match, one of the groups must match + while (it.hasNext()) { + // get the next group and try matching it + TargetMatchGroup group = (TargetMatchGroup)(it.next()); + context.newEvent(group); + MatchResult result = group.match(context); + context.closeCurrentEvent(result); + + // we only need one match, so if this matched, then we're done + if (result.getResult() == MatchResult.MATCH) { + return result; + } + + // if we didn't match then it was either a NO_MATCH or + // INDETERMINATE...in the second case, we need to remember + // it happened, 'cause if we don't get a MATCH, then we'll + // be returning INDETERMINATE + if (result.getResult() == MatchResult.INDETERMINATE) { + if (firstIndeterminateStatus == null) { + firstIndeterminateStatus = result.getStatus(); + } + } + } + + // if we got here, then none of the sub-matches passed, so + // we have to see if we got any INDETERMINATE cases + if (firstIndeterminateStatus == null) { + return new MatchResult(MatchResult.NO_MATCH); + } + return new MatchResult(MatchResult.INDETERMINATE, + firstIndeterminateStatus); + } + + /** + * Encodes this TargetSection into its XML representation + * and writes this encoding to the given OutputStream with + * no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this TargetSection into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + String closingTag = null; + // figure out if this section applies to any request + if (!this.matchGroups.isEmpty()) { + if (this.xacmlVersion > Constants.XACML_VERSION_2_0) { + // this has specific rules, so we can now encode them + out.println(indent + ""); + closingTag = ""; + + } else { // XACML 2.0 and below compatibility code + if (this.category.equals(Constants.SUBJECT_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.RESOURCE_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.ACTION_CAT)) { + out.println(indent + ""); + closingTag = ""; + } else if (this.category.equals(Constants.ENVIRONMENT_CAT)) { + out.println(indent + ""); + closingTag = ""; + } + } + Iterator it = this.matchGroups.iterator(); + indenter.in(); + while (it.hasNext()) { + TargetMatchGroup group = (TargetMatchGroup)(it.next()); + group.encode(output, charsetName, indenter); + } + indenter.out(); + out.println(indent + closingTag); + } + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/UnknownIdentifierException.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/UnknownIdentifierException.java new file mode 100644 index 0000000..a8466d0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/UnknownIdentifierException.java @@ -0,0 +1,71 @@ + +/* + * @(#)UnknownIdentifierException.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + + +/** + * Exception that gets thrown if an unknown identifier was used, such as the + * identifier used in any of the standard factories. + * + * @since 1.0 + * @author Seth Proctor + */ +public class UnknownIdentifierException extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Creates an UnknownIdentifierException with no data + */ + public UnknownIdentifierException() { + //contains no data + } + + /** + * Creates an UnknownIdentifierException with a message + * + * @param message the message + */ + public UnknownIdentifierException(String message) { + super(message); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/VersionConstraints.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/VersionConstraints.java new file mode 100644 index 0000000..371ae56 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/VersionConstraints.java @@ -0,0 +1,241 @@ + +/* + * @(#)VersionConstraints.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml; + +import java.util.StringTokenizer; + + +/** + * Supports the three version constraints that can be included with a + * policy reference. This class also provides a simple set of comparison + * methods for matching against the constraints. Note that this feature + * was introduced in XACML 2.0, which means that constraints are never + * used in pre-2.0 policy references. + * + * @since 2.0 + * @author Seth Proctor + */ +public class VersionConstraints +{ + + // internal identifiers used to specify the kind of match + private static final int COMPARE_EQUAL = 0; + private static final int COMPARE_LESS = 1; + private static final int COMPARE_GREATER = 2; + + // the three constraint strings + private String version; + private String earliest; + private String latest; + + /** + * Creates a VersionConstraints with the three optional + * constraint strings. Each of the three strings must conform to the + * VersionMatchType type defined in the XACML schema. Any of the + * strings may be null to specify that the given constraint is not + * used. + * + * @param version a matching constraint on the version or null + * @param earliest a lower-bound constraint on the version or null + * @param latest an upper-bound constraint on the version or null + */ + public VersionConstraints(String version, String earliest, String latest) { + this.version = version; + this.earliest = earliest; + this.latest = latest; + } + + /** + * Returns the matching constraint string, which will be null if there + * is no constraint on matching the version. + * + * @return the version constraint + */ + public String getVersionConstraint() { + return this.version; + } + + /** + * Returns the lower-bound constraint string, which will be null if there + * is no lower-bound constraint on the version. + * + * @return the lower-bound constraint + */ + public String getEarliestConstraint() { + return this.earliest; + } + + /** + * Returns the upper-bound constraint string, which will be null if there + * is no upper-bound constraint on the version. + * + * @return the upper-bound constraint + */ + public String getLatestConstraint() { + return this.latest; + } + + /** + * Checks if the given version string meets all three constraints. + * + * @param version the version to compare, which is formatted as a + * VersionType XACML type + * + * @return true if the given version meets all the constraints + */ + public boolean meetsConstraint(String version) { + return (matches(version, this.version) + && isEarlier(version, this.latest) + && isLater(version, this.earliest)); + } + + /** + * Checks if the given version string matches the constraint string. + * + * @param version the version string to check + * @param constraint a constraint string to use in matching + * + * @return true if the version string matches the constraint + */ + public static boolean matches(String version, String constraint) { + return compareHelper(version, constraint, COMPARE_EQUAL); + } + + /** + * Checks if the given version string is less-than or equal-to the + * constraint string. + * + * @param version the version string to check + * @param constraint a constraint string to use in matching + * + * @return true if the version string is earlier than the constraint + */ + public static boolean isEarlier(String version, String constraint) { + return compareHelper(version, constraint, COMPARE_LESS); + } + + /** + * Checks if the given version string is greater-than or equal-to the + * constraint string. + * + * @param version the version string to check + * @param constraint a constraint string to use in matching + * + * @return true if the version string is later than the constraint + */ + public static boolean isLater(String version, String constraint) { + return compareHelper(version, constraint, COMPARE_GREATER); + } + + /** + * Private helper that handles all three comparisons. + */ + private static boolean compareHelper(String version, String constraint, + int type) { + // check that a constraint was provided... + if (constraint == null) { + return true; + } + + // ...and a version too + // FIXME: this originally returned false, but I think it should + // return true, since we always match if the contstraint is + // unbound (null) ... is that right? + if (version == null) { + return true; + } + + // setup tokenizers + StringTokenizer vtok = new StringTokenizer(version, "."); + StringTokenizer ctok = new StringTokenizer(constraint, "."); + + while (vtok.hasMoreTokens()) { + // if there's nothing left in the constraint, then this means + // we didn't match, unless this is the greater-than function + if (! ctok.hasMoreTokens()) { + if (type == COMPARE_GREATER) { + return true; + } + return false; + } + + // get the next constraint token... + String c = ctok.nextToken(); + + // ...and if it's a + then it's done and we match + if (c.equals("+")) { + return true; + } + String v = vtok.nextToken(); + + // if it's a * then we always match, otherwise... + if (! c.equals("*")) { + // if it's a match then we just keep going, otherwise... + if (! v.equals(c)) { + // if we're matching on equality, then we failed + if (type == COMPARE_EQUAL) { + return false; + } + + // convert both tokens to integers... + int cint = Integer.valueOf(c).intValue(); + int vint = Integer.valueOf(v).intValue(); + + // ...and do the right kind of comparison + if (type == COMPARE_LESS) { + return vint <= cint; + } + return vint >= cint; + } + } + } + + // if we got here, then we've finished the processing the version, + // so see if there's anything more in the constrant, which would + // mean we didn't match unless we're doing less-than + if (ctok.hasMoreTokens()) { + if (type == COMPARE_LESS) { + return true; + } + return false; + } + + // we got through everything, so the constraint is met + return true; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AnyURIAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AnyURIAttribute.java new file mode 100644 index 0000000..bfb329d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AnyURIAttribute.java @@ -0,0 +1,201 @@ + +/* + * @(#)AnyURIAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an xs:anyURI value. This class supports parsing + * xs:anyURI values. + * + * @since 1.0 + * @author Seth Proctor + */ +public class AnyURIAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.ANYURI; + + + //URI version of name for this type + private static URI identifierURI; + + // RuntimeException that wraps an Exception thrown during the + // creation of identifierURI, null if none + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + // the URI value that this class represents + private URI value; + + /** + * Creates a new AnyURIAttribute that represents + * the URI value supplied. + * + * @param value the URI value to be represented + */ + public AnyURIAttribute(URI value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + this.value = value; + } + + /** + * Returns a new AnyURIAttribute that represents + * the xs:anyURI at a particular DOM node. + * + * @param root the Node that contains the desired value + * + * @return a new AnyURIAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws URISyntaxException + * @throws ParsingException + */ + public static AnyURIAttribute getInstance(Node root) + throws URISyntaxException, ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a AnyURIAttribute"); + } + + /** + * Returns a new AnyURIAttribute that represents + * the xs:anyURI value indicated by the String provided. + * + * @param value a string representing the desired value + * + * @return a new AnyURIAttribute representing the + * appropriate value + * + * @throws URISyntaxException + * @throws ParsingException + */ + public static AnyURIAttribute getInstance(String value) + throws URISyntaxException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "AnyURIAttribute from null input"); + } + return new AnyURIAttribute(new URI(value)); + } + + /** + * Returns the URI value represented by this object. + * + * @return the URI value + */ + public URI getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof AnyURIAttribute)) { + return false; + } + AnyURIAttribute other = (AnyURIAttribute)o; + + return this.value.equals(other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return this.value.hashCode(); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + return "AnyURIAttribute: \"" + this.value.toString() + "\""; + } + + /** + * @return The AttributeValue encoded as a String. + * + */ + public String encode() { + return this.value.toString(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeDesignator.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeDesignator.java new file mode 100644 index 0000000..1c6e5e2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeDesignator.java @@ -0,0 +1,552 @@ + +/* + * @(#)AttributeDesignator.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +import com.sun.xacml.cond.Evaluatable; +import com.sun.xacml.cond.EvaluationResult; +import com.sun.xacml.cond.Expression; + +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.ctx.Status; +import com.sun.xacml.ctx.StatusDetail; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; +import com.sun.xacml.finder.RequiredAttributesModule; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * Represents Attribute Designators in XACML. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class AttributeDesignator implements Evaluatable +{ + + /** + * The category of the Designator. + */ + private URI category; + + /** + * The datatype resolved by this designator + */ + private URI type; + + /** + * The attribute id resolved by this designator + */ + private URI id; + + /** + * The optional issuer attribute + */ + private URI issuer; + + /** + * Throw an error if the resolution doesn't find something + */ + private boolean mustBePresent; + + /** + * The XACML version + */ + private int xacmlVersion; + + /** + * Backwards compatibility switch that indicates if the + * SubjectCategory was explicit or default. + */ + private boolean withSubjectCategory = false; + + /** + * Information where the Attribute Designator has been defined in src (files) + */ + private RuntimeInfo src = null; + + /** + * the logger we'll use for all messages + */ + private static final Logger logger = + Logger.getLogger(AttributeDesignator.class.getName()); + + private static ArrayList requiredAttrModules; + + public static void setRequiredAttrModules(ArrayList requiredAttrModules) { + AttributeDesignator.requiredAttrModules = requiredAttrModules; + } + + /** + * Creates a new AttributeDesignator. + * + * @param category the category of this designator + * @param type the data type resolved by this designator + * @param id the attribute id looked for by this designator + * @param mustBePresent whether resolution must find a value + * @param issuer the issuer of the values to search for or null if no + * issuer is specified + * + */ + public AttributeDesignator(URI category, URI type, URI id, + boolean mustBePresent, URI issuer) { + this(category, type, id, mustBePresent, issuer, + Constants.XACML_DEFAULT_VERSION, false); + } + + /** + * Creates a new AttributeDesignator. + * + * @param category the category of this designator + * @param type the data type resolved by this designator + * @param id the attribute id looked for by this designator + * @param mustBePresent whether resolution must find a value + * @param issuer the issuer of the values to search for or null if no + * issuer is specified + * @param xacmlVersion the XACML version that is used. + * @param withSubjectCategory Backwards compatibility switch that + * indicates if the SubjectCategory is + * explicit or default. + * + */ + public AttributeDesignator(URI category, URI type, URI id, + boolean mustBePresent, URI issuer, int xacmlVersion, + boolean withSubjectCategory) { + + this.category = category; + this.type = type; + this.id = id; + this.mustBePresent = mustBePresent; + this.issuer = issuer; + this.xacmlVersion = xacmlVersion; + this.withSubjectCategory = withSubjectCategory; + } + + + + /** + * Creates a new AttributeDesignator based on the DOM + * root of the XML data. + * + * @param root the DOM root of the AttributeDesignatorType XML type + * @param metaData the meta-data associated with the containing policy + * + * @return the designator + * + * @throws ParsingException if the AttributeDesignatorType was invalid + */ + public static AttributeDesignator getInstance(Node root, + PolicyMetaData metaData) throws ParsingException { + URI category = null; + URI type = null; + URI id = null; + URI issuer = null; + boolean mustBePresent = false; + int xacmlVersion = metaData.getXACMLVersion(); + boolean withSubjectCategory = false; + + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.ATTRIBUTE_DESIGNATOR); + + NamedNodeMap attrs = root.getAttributes(); + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Cannot build a AttributeDesignator" + + " with this node type: " + root.getClass().getName() + + (src != null ? src.getLocationMsgForError() : "")); + } + + if (root.getLocalName().equals("SubjectAttributeDesignator")) { + if (xacmlVersion > Constants.XACML_VERSION_2_0) { + throw new ParsingException("Can't create a > XACML 2.0" + + "AttributeDesignator from " + root.getLocalName() + + (src != null ? src.getLocationMsgForError() : "")); + } + //compatibility code for XACML 2.0 + category = Constants.SUBJECT_CAT; + if (attrs != null) { + Node catNode = attrs.getNamedItem("SubjectCategory"); + if (catNode != null) { + try { + category = new URI(catNode.getNodeValue()); + } catch (URISyntaxException e) { + throw new ParsingException("Error while parsing" + + "category: " + catNode.getNodeValue() + + (src != null ? src.getLocationMsgForError() : "")); + } + withSubjectCategory = true; + } + } + } else if (root.getLocalName().equals("ResourceAttributeDesignator")) { + if (xacmlVersion > Constants.XACML_VERSION_2_0) { + throw new ParsingException("Can't create an > XACML 2.0 " + + "AttributeDesignator from " + root.getLocalName() + + src.getLocationMsgForError()); + } + category = Constants.RESOURCE_CAT; + } else if (root.getLocalName().equals("ActionAttributeDesignator")) { + if (xacmlVersion > Constants.XACML_VERSION_2_0) { + throw new ParsingException("Can't create an > XACML 2.0 " + + "AttributeDesignator from " + root.getLocalName() + + (src != null ? src.getLocationMsgForError() : "")); + } + category = Constants.ACTION_CAT; + } else if (root.getLocalName().equals( + "EnvironmentAttributeDesignator")) { + if (xacmlVersion != Constants.XACML_VERSION_2_0) { + throw new ParsingException("Can't create an XACML 2.0 " + + "AttributeDesignator from " + root.getLocalName() + + src.getLocationMsgForError()); + } + category = Constants.ENVIRONMENT_CAT; + } else { + if (xacmlVersion < Constants.XACML_VERSION_3_0) { + throw new ParsingException("Can't create an XACML " + + xacmlVersion + " AttributeDesignator from " + + root.getLocalName() + + (src != null ? src.getLocationMsgForError() : "")); + } + // there's always a category + try { + category = new URI( + attrs.getNamedItem("Category").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Required Category missing or" + + " invalid in AttributeDesignator" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + } + try { + // there's always an Id + id = new URI(attrs.getNamedItem("AttributeId").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Required AttributeId missing or" + + " invalid in AttributeDesignator" + + src.getLocationMsgForError(), e); + } + + try { + // there's always a data type + type = new URI(attrs.getNamedItem("DataType").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Required DataType missing or" + + " invalid in AttributeDesignator" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + try { + // there might be an issuer + Node node = attrs.getNamedItem("Issuer"); + if (node != null) { + issuer = new URI(node.getNodeValue()); + } + // there might be a mustBePresent flag + node = attrs.getNamedItem("MustBePresent"); + if (node != null) { + if (node.getNodeValue().equals("true")) { + mustBePresent = true; + } + } + } catch (Exception e) { + // this shouldn't ever happen, but in theory something could go + // wrong in the code in this try block + throw new ParsingException("Error parsing AttributeDesignator " + + "optional attributes" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + AttributeDesignator attrDesgn = new AttributeDesignator(category, type, + id, mustBePresent, issuer, xacmlVersion, withSubjectCategory); + if ( src != null ) { + attrDesgn.src = src; + src.setXACMLObject(attrDesgn); + } + return attrDesgn; + } + + /** + * Returns the type of attribute that is resolved by this designator. + * While an AD will always return a bag, this method will always return + * the type that is stored in the bag. + * + * @return the attribute type + */ + public URI getType() { + return this.type; + } + + /** + * Returns the AttributeId of the values resolved by this designator. + * + * @return identifier for the values to resolve + */ + public URI getId() { + return this.id; + } + + /** + * Returns the category for this designator. + * + * @return the category + */ + public URI getCategory() { + return this.category; + } + + /** + * Returns the issuer of the values resolved by this designator if + * specified. + * + * @return the attribute issuer or null if unspecified + */ + public URI getIssuer() { + return this.issuer; + } + + /** + * Returns whether or not a value is required to be resolved by this + * designator. + * + * @return true if a value is required, false otherwise + */ + public boolean mustBePresent() { + return this.mustBePresent; + } + + /** + * Always returns true, since a designator always returns a bag of + * attribute values. + * + * @return true + */ + public boolean returnsBag() { + return true; + } + + /** + * Always returns an empty list since designators never have children. + * + * @return an empty List + */ + public List getChildren() { + return Expression.EMPTY_LIST; //Collections.emptyList(); + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + /** + * Evaluates the pre-assigned meta-data against the given context, + * trying to find some matching values. + * + * @param context the representation of the request + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult evaluate(EvaluationCtx context) { + context.newEvent(this); + EvaluationResult result = null; + + // look in the right section for some attribute values + result = context.getAttribute(this.category, this.type, this.id, + this.issuer); + + // if the lookup was indeterminate, then we return immediately + if (result.indeterminate()) { + context.closeCurrentEvent(result); + return result; + } + + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + + if (bag.isEmpty()) { + // if it's empty, this may be an error + if (this.mustBePresent) { + if (logger.isInfoEnabled()) { + logger.info("AttributeDesignator failed to resolve a " + + "value for a required attribute: " + + this.id.toString() + " (MustBePresent: " + + mustBePresent + ")"); + } + + ArrayList code = new ArrayList(); + code.add(Status.STATUS_MISSING_ATTRIBUTE); + + String message = "Couldn't find " + + "AttributeDesignator attribute"; + + // Note that there is a bug in the XACML spec. You can't + // specify an identifier without specifying acceptable + // values. Until this is fixed, this code will only + // return the status code, and not any hints about what + // was missing + Set attr = null; + for ( RequiredAttributesModule requAttrMod : requiredAttrModules ) { + attr = requAttrMod.resolveRequiredAttributes(context, this); + + if ( attr != null && attr.size() > 0 ) { + break; + } + } + + Status status; + if ( attr == null ) { + status = new Status(code, message); + } else { + status = new Status(code, message, new StatusDetail(attr)); + } + + EvaluationResult evalResult = new EvaluationResult(status); + context.closeCurrentEvent(evalResult); + return evalResult; + } + } + + // if we got here the bag wasn't empty, or mustBePresent was false, + // so we just return the result + context.closeCurrentEvent(result); + return result; + } + + /** + * Encodes this designator into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this designator into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + String tag = ""; + + if (this.xacmlVersion > Constants.XACML_VERSION_2_0) { + tag = " registeredFactories; + + /** + * static intialiazer that sets up the default factory proxy and + * registers the standard namespaces + */ + static { + AttributeFactoryProxy proxy = new AttributeFactoryProxy() { + public AttributeFactory getFactory() { + return StandardAttributeFactory.getFactory(); + } + }; + + registeredFactories = new HashMap(); + registeredFactories.put(Constants.XACML_1_0_IDENTIFIER, proxy); + registeredFactories.put(Constants.XACML_2_0_IDENTIFIER, proxy); + + defaultFactoryProxy = proxy; + } + + /** + * Default constructor. Used only by subclasses. + */ + protected AttributeFactory() { + // used only by subclasses + } + + /** + * Returns the default factory. Depending on the default factory's + * implementation, this may return a singleton instance or new instances + * with each invokation. + * + * @return the default AttributeFactory + */ + public static final AttributeFactory getInstance() { + return defaultFactoryProxy.getFactory(); + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0 and 2.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return an AttributeFactory + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final AttributeFactory getInstance(String identifier) + throws UnknownIdentifierException + { + AttributeFactoryProxy proxy = registeredFactories.get(identifier); + + if (proxy == null) { + throw new UnknownIdentifierException("Uknown AttributeFactory " + + "identifier: " + identifier); + } + return proxy.getFactory(); + } + + /** + * Sets the default factory. This does not register the factory proxy as + * an identifiable factory. + * + * @param proxy the AttributeFactoryProxy to set as the new + * default factory proxy + */ + public static final void setDefaultFactory(AttributeFactoryProxy proxy) { + defaultFactoryProxy = proxy; + } + + /** + * Registers the given factory proxy with the given identifier. If the + * identifier is already used, then this throws an exception. If the + * identifier is not already used, then it will always be bound to the + * given proxy. + * + * @param identifier the identifier for the proxy + * @param proxy the AttributeFactoryProxy to register with + * the given identifier + * + * @throws IllegalArgumentException if the identifier is already used + */ + public static final void registerFactory(String identifier, + AttributeFactoryProxy proxy) + throws IllegalArgumentException + { + synchronized (registeredFactories) { + if (registeredFactories.containsKey(identifier)) { + throw new IllegalArgumentException("Identifier is already " + + "registered as " + + "AttributeFactory: " + + identifier); + } + registeredFactories.put(identifier, proxy); + } + } + + /** + * Adds a proxy to the factory, which in turn will allow new attribute + * types to be created using the factory. Typically the proxy is + * provided as an anonymous class that simply calls the getInstance + * methods (or something similar) of some AttributeValue + * class. + * + * @param id the name of the attribute type + * @param proxy the proxy used to create new attributes of the given type + * + * @throws IllegalArgumentException if the given id is already in use + */ + public abstract void addDatatype(String id, AttributeProxy proxy); + + /** + * Adds a proxy to the default factory, which in turn will allow new + * attribute types to be created using the factory. Typically the proxy + * is provided as an anonymous class that simply calls the getInstance + * methods (or something similar) of some AttributeValue + * class. + * + * @deprecated As of version 1.2, replaced by + * {@link #addDatatype(String,AttributeProxy)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. Note that this operates only on the + * default factory. + * + * @param id the name of the attribute type + * @param proxy the proxy used to create new attributes of the given type + * + * @throws IllegalArgumentException if the given id is already in use + */ + public static void addAttributeProxy(String id, AttributeProxy proxy) { + getInstance().addDatatype(id, proxy); + } + + /** + * Returns the datatype identifiers supported by this factory. + * + * @return a Set of Strings + */ + public abstract Set getSupportedDatatypes(); + + /** + * Creates a value based on the given DOM root node. The type of the + * attribute is assumed to be present in the node as an XAML attribute + * named DataType, as is the case with the + * AttributeValueType in the policy schema. The value is assumed to be + * the first child of this node. + * + * @param root the DOM root of an attribute value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type in the node isn't + * known to the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public abstract AttributeValue createValue(Node root) + throws UnknownIdentifierException, ParsingException; + + /** + * Creates a value based on the given DOM root node. The type of the + * attribute is assumed to be present in the node as an XAML attribute + * named DataType, as is the case with the + * AttributeValueType in the policy schema. The value is assumed to be + * the first child of this node. This uses the default factory. + * + * @deprecated As of version 1.2, replaced by + * {@link #createValue(Node)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param root the DOM root of an attribute value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type in the node isn't + * known to the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public static AttributeValue createAttribute(Node root) + throws UnknownIdentifierException, ParsingException + { + return getInstance().createValue(root); + } + + /** + * Creates a value based on the given DOM root node and data type. + * + * @param root the DOM root of an attribute value + * @param dataType the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public abstract AttributeValue createValue(Node root, URI dataType) + throws UnknownIdentifierException, ParsingException; + + /** + * Creates a value based on the given DOM root node and data type. This + * uses the default factory. + * + * @deprecated As of version 1.2, replaced by + * {@link #createValue(Node,URI)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param root the DOM root of an attribute value + * @param dataType the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public static AttributeValue createAttribute(Node root, URI dataType) + throws UnknownIdentifierException, ParsingException + { + return getInstance().createValue(root, dataType); + } + + /** + * Creates a value based on the given DOM root node and data type. + * + * @param root the DOM root of an attribute value + * @param type the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public abstract AttributeValue createValue(Node root, String type) + throws UnknownIdentifierException, ParsingException; + + /** + * Creates a value based on the given DOM root node and data type. This + * uses the default factory. + * + * @deprecated As of version 1.2, replaced by + * {@link #createValue(Node,String)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param root the DOM root of an attribute value + * @param type the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public static AttributeValue createAttribute(Node root, String type) + throws UnknownIdentifierException, ParsingException + { + return getInstance().createValue(root, type); + } + + /** + * Creates a value based on the given data type and text-encoded value. + * Used primarily by code that does an XPath query to get an + * attribute value, and then needs to turn the resulting value into + * an Attribute class. + * + * @param dataType the type of the attribute + * @param value the text-encoded representation of an attribute's value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the text is invalid or can't be parsed + * by the appropriate proxy + */ + public abstract AttributeValue createValue(URI dataType, String value) + throws UnknownIdentifierException, ParsingException; + + /** + * Creates a value based on the given data type and text-encoded value. + * Used primarily by code that does an XPath query to get an + * attribute value, and then needs to turn the resulting value into + * an Attribute class. This uses the default factory. + * + * @deprecated As of version 1.2, replaced by + * {@link #createValue(URI,String)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param dataType the type of the attribute + * @param value the text-encoded representation of an attribute's value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the text is invalid or can't be parsed + * by the appropriate proxy + */ + public static AttributeValue createAttribute(URI dataType, String value) + throws UnknownIdentifierException, ParsingException + { + return getInstance().createValue(dataType, value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeFactoryProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeFactoryProxy.java new file mode 100644 index 0000000..9c355ef --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeFactoryProxy.java @@ -0,0 +1,58 @@ + +/* + * @(#)AttributeFactoryProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + + +/** + * A simple proxy interface used to install new + * AttributeFactorys. + * + * @since 1.2 + * @author Seth Proctor + */ +public interface AttributeFactoryProxy +{ + + /** + * Returns an instance of the AttributeFactory for which + * this is a proxy. + * + * @return an AttributeFactory instance + */ + public AttributeFactory getFactory(); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeProxy.java new file mode 100644 index 0000000..4e231f6 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeProxy.java @@ -0,0 +1,80 @@ + +/* + * @(#)AttributeProxy.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import org.w3c.dom.Node; + + +/** + * Used by the AttributeFactory to create new attributes. + * Typically a new proxy class is created which in turn knows how to create + * a specific kind of attribute, and then this proxy class is installed in + * the AttributeFactory. + * + * @since 1.0 + * @author Seth Proctor + */ +public interface AttributeProxy +{ + + /** + * Tries to create a new AttributeValue based on the given + * DOM root node. + * + * @param root the DOM root of some attribute data + * + * @return an AttributeValue representing the given data + * + * @throws Exception if the data couldn't be used (the exception is + * typically wrapping some other exception) + */ + public AttributeValue getInstance(Node root) throws Exception; + + /** + * Tries to create a new AttributeValue based on the given + * String data. + * + * @param value the text form of some attribute data + * + * @return an AttributeValue representing the given data + * + * @throws Exception if the data couldn't be used (the exception is + * typically wrapping some other exception) + */ + public AttributeValue getInstance(String value) throws Exception; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeSelector.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeSelector.java new file mode 100644 index 0000000..fde8e12 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/AttributeSelector.java @@ -0,0 +1,421 @@ + +/* + * @(#)AttributeSelector.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +import com.sun.xacml.cond.Evaluatable; +import com.sun.xacml.cond.EvaluationResult; +import com.sun.xacml.cond.Expression; + +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * Supports the standard selector functionality in XACML, which uses XPath + * expressions to resolve values from the Request or elsewhere. All selector + * queries are done by AttributeFinderModules so that it's easy + * to plugin different XPath implementations. + * + * @since 1.0 + * @author Seth Proctor + */ +public class AttributeSelector implements Evaluatable +{ + + // the data type returned by this selector + private URI type; + + // the XPath to search + private String contextPath; + + // must resolution find something + private boolean mustBePresent; + + // the xpath version we've been told to use + private String xpathVersion; + + // the policy root, where we get namespace mapping details + private Node policyRoot; + + private RuntimeInfo src; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(AttributeSelector.class.getName()); + + /** + * Creates a new AttributeSelector with no policy root. + * + * @param type the data type of the attribute values this selector + * looks for + * @param contextPath the XPath to query + * @param mustBePresent must resolution find a match + * @param xpathVersion the XPath version to use, which must be a valid + * XPath version string (the identifier for XPath 1.0 + * is provided in PolicyMetaData) + */ + public AttributeSelector(URI type, String contextPath, + boolean mustBePresent, String xpathVersion) { + this(type, contextPath, null, mustBePresent, xpathVersion); + } + + /** + * Creates a new AttributeSelector. + * + * @param type the data type of the attribute values this selector + * looks for + * @param contextPath the XPath to query + * @param policyRoot the root DOM Element for the policy containing this + * selector, which defines namespace mappings + * @param mustBePresent must resolution find a match + * @param xpathVersion the XPath version to use, which must be a valid + * XPath version string (the identifier for XPath 1.0 + * is provided in PolicyMetaData) + */ + public AttributeSelector(URI type, String contextPath, Node policyRoot, + boolean mustBePresent, String xpathVersion) { + this.type = type; + this.contextPath = contextPath; + this.mustBePresent = mustBePresent; + this.xpathVersion = xpathVersion; + this.policyRoot = policyRoot; + } + + /** + * Creates a new AttributeSelector based on the DOM root + * of the XML type. Note that as of XACML 1.1 the XPathVersion element + * is required in any policy that uses a selector, so if the + * xpathVersion string is null, then this will throw + * an exception. + * + * @param root the root of the DOM tree for the XML AttributeSelectorType + * XML type + * @param metaData the meta-data associated with the containing policy + * + * @return an AttributeSelector + * + * @throws ParsingException if the AttributeSelectorType was invalid + */ + public static AttributeSelector getInstance(Node root, + PolicyMetaData metaData) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.ATTRIBUTE_SELECTOR); + if (root.getNodeType() != Node.ELEMENT_NODE || + !root.getLocalName().equals("AttributeSelector")) { + throw new ParsingException("Can't create an AttributeSelector" + + " from a " + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + URI type = null; + String contextPath = null; + boolean mustBePresent = false; + String xpathVersion = metaData.getXPathIdentifier(); + + // make sure we were given an xpath version + if (xpathVersion == null) { + throw new ParsingException("An XPathVersion is required for "+ + "any policies that use selectors" + + (src != null ? src.getLocationMsgForError() : "")); + } + NamedNodeMap attrs = root.getAttributes(); + + try { + // there's always a DataType attribute + type = new URI(attrs.getNamedItem("DataType").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error parsing required DataType " + + "attribute in AttributeSelector" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + try { + // there's always a RequestPath + contextPath = + attrs.getNamedItem("RequestContextPath").getNodeValue(); + } catch (Exception e) { + throw new ParsingException("Error parsing required " + + "RequestContextPath attribute in AttributeSelector" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + try { + // there may optionally be a MustBePresent + Node node = attrs.getNamedItem("MustBePresent"); + if (node != null) + if (node.getNodeValue().equals("true")) { + mustBePresent = true; + } + } catch (Exception e) { + // this shouldn't happen, since we check the cases, but still... + throw new ParsingException("Error parsing optional attributes " + + "in AttributeSelector" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + + // as of 1.2 we need the root element of the policy so we can get + // the namespace mapping, but in order to leave the APIs unchanged, + // we'll walk up the tree to find the root rather than pass this + // element around through all the code + Node policyRoot = null; + Node node = root.getParentNode(); + + while ((node != null) && (node.getNodeType() == Node.ELEMENT_NODE)) { + policyRoot = node; + node = node.getParentNode(); + } + + // create the new selector + AttributeSelector attrSelector = new AttributeSelector(type, + contextPath, policyRoot, mustBePresent, xpathVersion); + if ( src != null ) { + attrSelector.src = src; + src.setXACMLObject(attrSelector); + } + return attrSelector; + } + + /** + * Returns the data type of the attribute values that this selector + * will resolve + * + * @return the data type of the values found by this selector + */ + public URI getType() { + return this.type; + } + + /** + * Returns the XPath query used to resolve attribute values. + * + * @return the XPath query + */ + public String getContextPath() { + return this.contextPath; + } + + /** + * Returns whether or not a value is required to be resolved by this + * selector. + * + * @return true if a value is required, false otherwise + */ + public boolean mustBePresent() { + return this.mustBePresent; + } + + /** + * Always returns true, since a selector always returns a bag of + * attribute values. + * + * @return true + */ + public boolean returnsBag() { + return true; + } + + /** + * Always returns an empty list since selectors never have children. + * + * @return an empty List + */ + public List getChildren() { + return Expression.EMPTY_LIST; + } + + /** + * Returns the XPath version this selector is supposed to use. This is + * typically provided by the defaults section of the policy containing + * this selector. + * + * @return the XPath version + */ + public String getXPathVersion() { + return this.xpathVersion; + } + + /** + * Returns the policy root node, from where we get namespace + * mapping details. + * + * @return a Node object + */ + public Node getPolicyRoot() { + return this.policyRoot; + } + + public RuntimeInfo getRuntimeInfo() { + return src; + } + + + /** + * Invokes the AttributeFinder used by the given + * EvaluationCtx to try to resolve an attribute value. If + * the selector is defined with MustBePresent as true, then failure + * to find a matching value will result in Indeterminate, otherwise it + * will result in an empty bag. To support the basic selector + * functionality defined in the XACML specification, use a finder that + * has only the SelectorModule as a module that supports + * selector finding. + * + * @param context representation of the request to search + * + * @return a result containing a bag either empty because no values were + * found or containing at least one value, or status associated with an + * Indeterminate result + */ + public EvaluationResult evaluate(EvaluationCtx context) { + context.newEvent(this); + // query the context + EvaluationResult result = context.getAttribute(this.contextPath, + this.policyRoot, + this.type, + this.xpathVersion); + + // see if we got anything + if (! result.indeterminate()) { + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + + // see if it's an empty bag + if (bag.isEmpty()) { + // see if this is an error or not + if (this.mustBePresent) { + // this is an error +// if (logger.isLoggable(Level.INFO)) { + logger.info("AttributeSelector failed to resolve a " + + "value for a required attribute: " + + this.contextPath); +// } + ArrayList code = new ArrayList(); + code.add(Status.STATUS_MISSING_ATTRIBUTE); + String message = "couldn't resolve XPath expression " + + this.contextPath + " for type " + this.type.toString(); + EvaluationResult evaluationResult + = new EvaluationResult(new Status(code, message)); + context.closeCurrentEvent(evaluationResult); + return evaluationResult; + } + // return the empty bag + context.closeCurrentEvent(); + return result; + } + // return the values + context.closeCurrentEvent(result); + return result; + } + // return the error + context.closeCurrentEvent(result); + return result; + } + + /** + * Encodes this selector into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this selector into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + String tag = "AttributeValues. If you want to + * provide a new type, extend this class and implement the + * equals(Object) and hashCode methods from + * Object, which are used for equality checking. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class AttributeValue implements Evaluatable +{ + + // the type of this attribute + private URI type; + + private RuntimeInfo src; + + /** + * Constructor that takes the specific attribute type. + * + * @param type the attribute's type + */ + protected AttributeValue(URI type) { + this.type = type; + } + + /** + * Returns the type of this attribute value. By default this always + * returns the type passed to the constructor. + * + * @return the attribute's type + */ + public URI getType() { + return this.type; + } + + /** + * Returns whether or not this value is actually a bag of values. This + * is a required interface from Expression, but the + * more meaningful isBag method is used by + * AttributeValues, so this method is declared as final + * and calls the isBag method for this value. + * + * @return true if this is a bag of values, false otherwise + */ + public final boolean returnsBag() { + return isBag(); + } + + /** + * Returns whether or not this value is actually a bag of values. This + * is a required interface from Evaluatable, but the + * more meaningful isBag method is used by + * AttributeValues, so this method is declared as final + * and calls the isBag method for this value. + * + * + * @deprecated As of 2.0, you should use the returnsBag + * method from the super-interface Expression. + * + * @return true if this is a bag of values, false otherwise + */ + public final boolean evaluatesToBag() { + return isBag(); + } + + /** + * Always returns an empty list since values never have children. + * + * @return an empty List + */ + public List getChildren() { + return Expression.EMPTY_LIST; + } + + /** + * Returns whether or not this value is actually a bag of values. By + * default this returns false. Typically, only the + * BagAttribute should ever override this to return + * true. + * + * @return true if this is a bag of values, false otherwise + */ + public boolean isBag() { + return false; + } + + /** + * Implements the required interface from Evaluatable. + * Since there is nothing to evaluate in an attribute value, the default + * result is just this instance. Override this method if you want + * special behavior, like a dynamic value. + * + * @param context the representation of the request + * + * @return a successful evaluation containing this value + */ + public EvaluationResult evaluate(EvaluationCtx context) { + return new EvaluationResult(this); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This must return a value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public abstract String encode(); + + /** + * Encodes this AttributeValue into its XML representation + * and writes this encoding to the given OutputStream with + * no indentation. This will always produce the version used in a + * policy rather than that used in a request, so this is equivalent + * to calling encodeWithTags(true) and then stuffing that + * into a stream. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this AttributeValue into its XML representation + * and writes this encoding to the given OutputStream with + * indentation. This will always produce the version used in a + * policy rather than that used in a request, so this is equivalent + * to calling encodeWithTags(true) and then stuffing that + * into a stream. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + out.println(indenter.makeString() + encodeWithTags(true)); + } + + /** + * Encodes the value and includes the AttributeValue XML tags so that + * the resulting string can be included in a valid XACML policy or + * Request/Response. The boolean parameter lets you include + * the DataType attribute, which is required in a policy but not allowed + * in a Request or Response. + * + * @param includeType include the DataType XML attribute if + * true, exclude if false + * + * @return a String encoding including the XML tags + */ + public String encodeWithTags(boolean includeType) { + if (includeType) { + return "" + + encode() + ""; + } + return "" + encode() + ""; + } + + /** + * defines if this attribute is dynamic, i.e., if it has to be evaluated at runtime + * @return + */ + public boolean isDynamic() { + return false; + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + public void setSrcLocFromFactory(RuntimeInfo src) { + this.src = src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BagAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BagAttribute.java new file mode 100644 index 0000000..d840bfa --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BagAttribute.java @@ -0,0 +1,265 @@ + +/* + * @(#)BagAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + + +/** + * Represents a bag used in the XACML spec as return values from functions + * and designators/selectors that provide more than one value. All values in + * the bag are of the same type, and the bag may be empty. The bag is + * immutable, although its contents may not be. + *

    + * NOTE: This is the one standard attribute type that can't be created from + * the factory, since you can't have this in an XML block (it is used only + * in return values & dynamic inputs). I think this is right, but we may need + * to add some functionality to let this go into the factory. + * + * @since 1.0 + * @author Seth Proctor + * @author Steve Hanna + */ +public class BagAttribute extends AttributeValue +{ + + // The Collection of AttributeValues that this object encapsulates + private Collection bag; + + /** + * Creates a new BagAttribute that represents + * the Collection of AttributeValues supplied. + * If the set is null or empty, then the new bag is empty. + * + * @param type the data type of all the attributes in the set + * @param bag a Collection of AttributeValues + */ + public BagAttribute(URI type, Collection bag) { + super(type); + + if (type == null) { + throw new IllegalArgumentException("Bags require a non-null " + + "type be provided"); + } + + // see if the bag is empty/null + if ((bag == null) || (bag.size() == 0)) { + // empty bag + this.bag = new ArrayList(); + } else { + // go through the collection to make sure it's a valid bag + Iterator it = bag.iterator(); + + while (it.hasNext()) { + AttributeValue attr = it.next(); + + // a bag cannot contain other bags, so make sure that each + // value isn't actually another bag + if (attr.isBag()) { + throw new IllegalArgumentException("bags cannot contain " + + "other bags"); + } + + // make sure that they're all the same type + if (! type.equals(attr.getType())) { + throw new + IllegalArgumentException("Bag items must all be of " + + "the same type"); + } + } + + // if we get here, then they're all the same type + this.bag = bag; + } + } + + /** + * Overrides the default method to always return true. + * + * @return a value of true + */ + public boolean isBag() { + return true; + } + + /** + * Convenience function that returns a bag with no elements + * + * @param type the types contained in the bag + * + * @return a new empty bag + */ + public static BagAttribute createEmptyBag(URI type) { + return new BagAttribute(type, null); + } + + /** + * A convenience function that returns whether or not the bag is empty + * (ie, whether or not the size of the bag is zero) + * + * @return whether or not the bag is empty + */ + public boolean isEmpty() { + return (this.bag.size() == 0); + } + + /** + * Returns the number of elements in this bag + * + * @return the number of elements in this bag + */ + public int size() { + return this.bag.size(); + } + + /** + * Returns true if this set contains the specified value. More formally, + * returns true if and only if this bag contains a value v such that + * (value==null ? v==null : value.equals(v)). Note that this will only + * work correctly if the AttributeValue has overridden the + * equals method. + * + * @param value the value to look for + * + * @return true if the value is in the bag + */ + public boolean contains(AttributeValue value) { + return this.bag.contains(value); + } + + /** + * Returns true if this bag contains all of the values of the specified bag. + * Note that this will only work correctly if the + * AttributeValue type contained in the bag has overridden + * the equals method. + * + * @param bag the bag to compare + * + * @return true if the input is a subset of this bag + */ + public boolean containsAll(BagAttribute bag) { + return this.bag.containsAll(bag.bag); + } + + + /** + * Returns an iterator over the bag. + * + * @return The iterator. + */ + public Iterator iterator() { + return new ImmutableIterator(this.bag.iterator()); + } + + + /** + * Returns an iterator over the bag. + * + * @return The iterator. + */ + public Iterable iterable() { + return this.bag; + } + + + + /** + * This is a version of Iterator that overrides the remove + * method so that items can't be taken out of the bag. + */ + private static class ImmutableIterator implements Iterator { + + // the iterator we're wrapping + private Iterator iterator; + + /** + * Create a new ImmutableIterator + * + * @param iterator The iterator that shall be made immutable. + */ + public ImmutableIterator(Iterator iterator) { + this.iterator = iterator; + } + + /** + * Standard hasNext method + * + * @return true of this iterator has a next element, false otherwise. + */ + public boolean hasNext() { + return this.iterator.hasNext(); + } + + /** + * Standard next method + * + * @return The next Object pointed to by the iterator. + * + * @throws NoSuchElementException + */ + public AttributeValue next() throws NoSuchElementException { + return this.iterator.next(); + } + + /** + * Makes sure that no one can remove any elements from the bag + * + * @throws UnsupportedOperationException + */ + public void remove() throws UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + } + + /** + * Because a bag cannot be included in a request/response or a + * policy, this will always throw an + * UnsupportedOperationException. + * + * @return The String that would encode this bag. + */ + public String encode() { + throw new UnsupportedOperationException("Bags cannot be encoded"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64.java new file mode 100644 index 0000000..51eb3be --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64.java @@ -0,0 +1,379 @@ + +/* + * @(#)Base64.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.io.IOException; +import java.io.ByteArrayOutputStream; + + + +/** + * Class that knows how to encode and decode Base64 values. Base64 + * Content-Transfer-Encoding rules are defined in Section 6.8 of IETF RFC 2045 + * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet + * Message Bodies, available at + * ftp://ftp.isi.edu/in-notes/rfc2045.txt. + *

    + * All methods of this class are static and thread-safe. + * + * @since 1.0 + * @author Anne Anderson + */ +class Base64 +{ + /* + * ASCII white-space characters. These are the ones recognized by the + * C and Java language [pre-processors]. + */ + private static final char SPACE = 0x20; /* space, or blank, character */ + private static final char ETX = 0x04; /* end-of-text character */ + private static final char VTAB = 0x0b; /* vertical tab character */ + private static final char FF = 0x0c; /* form-feed character */ + private static final char HTAB = 0x09; /* horizontal tab character */ + private static final char LF = 0x0a; /* line feed character */ + private static final char ALTLF = 0x13; /* line feed on some systems */ + private static final char CR = 0x0d; /* carriage-return character */ + + + /* + * String used for BASE64 encoding and decoding. + * + * For index values 0-63, the character at each index is the Base-64 + * encoded value of the index value. Index values beyond 63 are never + * referenced during encoding, but are used in this implementation to + * help in decoding. The character at index 64 is the Base64 pad + * character '='. + * + * Charaters in index positions 0-64 MUST NOT be moved or altered, as + * this will break the implementation. + * + * The characters after index 64 are white space characters that should be + * ignored in Base64-encoded input strings while doing decoding. Note that + * the white-space character set should include values used on various + * platforms, since a Base64-encoded value may have been generated on a + * non-Java platform. The values included here are those used in Java and + * in C. + * + * The white-space character set may be modified without affecting the + * implementation of the encoding algorithm. + */ + private static final String BASE64EncodingString = + "ABCDEFGHIJ" + + "KLMNOPQRST" + + "UVWXYZabcd" + + "efghijklmn" + + "opqrstuvwx" + + "yz01234567" + + "89+/" + + "=" + + SPACE + ETX + VTAB + FF + HTAB + LF + ALTLF + CR; + + // Index of pad character in Base64EncodingString + private static final int PAD_INDEX = 64; + + /* + * The character in Base64EncodingString with the maximum + * character value in Unicode. + */ + private static final int MAX_BASE64_CHAR = 'z'; + + /* + * Array for mapping encoded characters to decoded values. + * This array is initialized when needed by calling + * initDecodeArray(). Only includes entries up to + * MAX_BASE64_CHAR. + */ + private static int [] Base64DecodeArray = null; + + /* + * State values used for decoding a quantum of four encoded input + * characters as follows. + * + * Initial state: NO_CHARS_DECODED + * NO_CHARS_DECODED: no characters have been decoded + * on encoded char: decode char into output quantum; + * new state: ONE_CHAR_DECODED + * otherwise: Exception + * ONE_CHAR_DECODED: one character has been decoded + * on encoded char: decode char into output quantum; + * new state: TWO_CHARS_DECODED + * otherwise: Exception + * TWO_CHARS_DECODED: two characters have been decoded + * on encoded char: decode char into output quantum; + * new state: THREE_CHARS_DECODED + * on pad: write quantum byte 0 to output; + * new state: PAD_THREE_READ + * THREE_CHARS_DECODED: three characters have been decoded + * on encoded char: decode char into output quantum; + * write quantum bytes 0-2 to output; + * new state: NO_CHARS_DECODED + * on pad: write quantum bytes 0-1 to output; + * new state: PAD_FOUR_READ + * PAD_THREE_READ: pad character has been read as 3rd of 4 chars + * on pad: new state: PAD_FOUR_READ + * otherwise: Exception + * PAD_FOUR_READ: pad character has been read as 4th of 4 char + * on any char: Exception + * + * The valid terminal states are NO_CHARS_DECODED and PAD_FOUR_READ. + */ + private static final int NO_CHARS_DECODED = 0; + private static final int ONE_CHAR_DECODED = 1; + private static final int TWO_CHARS_DECODED = 2; + private static final int THREE_CHARS_DECODED = 3; + private static final int PAD_THREE_READ = 5; + private static final int PAD_FOUR_READ = 6; + + /** + * The maximum number of groups that should be encoded + * onto a single line (so we don't exceed 76 characters + * per line). + */ + private static final int MAX_GROUPS_PER_LINE = 76/4; + + /** + * Encodes the input byte array into a Base64-encoded + * String. The output String + * has a CR LF (0x0d 0x0a) after every 76 bytes, but + * not at the end. + *

    + * WARNING: If the input byte array is modified + * while encoding is in progress, the output is undefined. + * + * @param binaryValue the byte array to be encoded + * + * @return the Base64-encoded String + */ + public static String encode(byte[] binaryValue) { + + int binaryValueLen = binaryValue.length; + // Estimated output length (about 1.4x input, due to CRLF) + int maxChars = (binaryValueLen * 7) / 5; + // Buffer for encoded output + StringBuffer sb = new StringBuffer(maxChars); + + int groupsToEOL = MAX_GROUPS_PER_LINE; + // Convert groups of 3 input bytes, with pad if < 3 in final + for (int binaryValueNdx = 0; binaryValueNdx < binaryValueLen; + binaryValueNdx += 3) { + + // Encode 1st 6-bit group + int group1 = (binaryValue[binaryValueNdx] >> 2) & 0x3F; + sb.append(BASE64EncodingString.charAt(group1)); + + // Encode 2nd 6-bit group + int group2 = (binaryValue[binaryValueNdx] << 4) & 0x030; + if ((binaryValueNdx+1) < binaryValueLen) { + group2 = group2 + | ((binaryValue[binaryValueNdx+1] >> 4) & 0xF); + } + sb.append(BASE64EncodingString.charAt(group2)); + + // Encode 3rd 6-bit group + int group3; + if ((binaryValueNdx+1) < binaryValueLen) { + group3 = (binaryValue[binaryValueNdx+1] << 2) & 0x03C; + if ((binaryValueNdx+2) < binaryValueLen) { + group3 = group3 + | ((binaryValue[binaryValueNdx+2] >> 6) & 0x3); + } + } else { + group3 = PAD_INDEX; + } + sb.append(BASE64EncodingString.charAt(group3)); + + // Encode 4th 6-bit group + int group4; + if ((binaryValueNdx+2) < binaryValueLen) { + group4 = binaryValue[binaryValueNdx+2] & 0x3F; + } else { + group4 = PAD_INDEX; + } + sb.append(BASE64EncodingString.charAt(group4)); + + // After every MAX_GROUPS_PER_LINE groups, insert CR LF. + // Unless this is the final line, in which case we skip that. + groupsToEOL = groupsToEOL - 1; + if (groupsToEOL == 0) { + groupsToEOL = MAX_GROUPS_PER_LINE; + if ((binaryValueNdx+3) <= binaryValueLen) { + sb.append(CR); + sb.append(LF); + } + } + } + return sb.toString(); + } + + /** + * Initializes Base64DecodeArray, if this hasn't already been + * done. + */ + private static synchronized void initDecodeArray() { + if (Base64DecodeArray != null) { + return; + } + + int [] ourArray = new int [MAX_BASE64_CHAR+1]; + for (int i = 0; i <= MAX_BASE64_CHAR; i++) { + ourArray[i] = BASE64EncodingString.indexOf(i); + } + Base64DecodeArray = ourArray; + } + + /** + * Decodes a Base64-encoded String. The result + * is returned in a byte array that should match the original + * binary value (before encoding). Whitespace characters + * in the input String are ignored. + *

    + * If the ignoreBadChars parameter is + * true, characters that are not allowed + * in a BASE64-encoded string are ignored. Otherwise, + * they cause an IOException to be raised. + * + * @param encoded a String containing a + * Base64-encoded value + * @param ignoreBadChars If true, bad characters + * are ignored. Otherwise, they cause + * an IOException to be + * raised. + * + * @return a byte array containing the decoded value + * + * @throws IOException if the input String is not + * a valid Base64-encoded value + */ + public static byte[] decode(String encoded, boolean ignoreBadChars) + throws IOException + { + int encodedLen = encoded.length(); + int maxBytes = (encodedLen/4)*3; /* Maximum possible output bytes */ + ByteArrayOutputStream ba = /* Buffer for decoded output */ + new ByteArrayOutputStream(maxBytes); + byte[] quantum = new byte[3]; /* one output quantum */ + + // ensure Base64DecodeArray is initialized + initDecodeArray(); + + /* + * Every 4 encoded characters in input are converted to 3 bytes of + * output. This is called one "quantum". Each encoded character is + * mapped to one 6-bit unit of the output. Whitespace characters in + * the input are passed over; they are not included in the output. + */ + + int state = NO_CHARS_DECODED; + for (int encodedNdx = 0; encodedNdx < encodedLen; encodedNdx++) { + // Turn encoded char into decoded value + int encodedChar = encoded.charAt(encodedNdx); + int decodedChar; + if (encodedChar > MAX_BASE64_CHAR) { + decodedChar = -1; + } else { + decodedChar = Base64DecodeArray[encodedChar]; + } + + // Handle white space and invalid characters + if (decodedChar == -1) { + if (ignoreBadChars) { + continue; + } + throw new IOException("Invalid character"); + } + if (decodedChar > PAD_INDEX) { /* whitespace */ + continue; + } + + // Handle valid characters + switch (state) { + case NO_CHARS_DECODED: + if (decodedChar == PAD_INDEX) { + throw new IOException("Pad character in invalid position"); + } + quantum[0] = (byte) ((decodedChar << 2) & 0xFC); + state = ONE_CHAR_DECODED; + break; + case ONE_CHAR_DECODED: + if (decodedChar == PAD_INDEX) { + throw new IOException("Pad character in invalid position"); + } + quantum[0] = (byte) (quantum[0] | ((decodedChar >> 4) & 0x3)); + quantum[1] = (byte) ((decodedChar << 4) & 0xF0); + state = TWO_CHARS_DECODED; + break; + case TWO_CHARS_DECODED: + if (decodedChar == PAD_INDEX) { + ba.write(quantum, 0, 1); + state = PAD_THREE_READ; + } else { + quantum[1] = + (byte) (quantum[1] | ((decodedChar >> 2) & 0x0F)); + quantum[2] = (byte) ((decodedChar << 6) & 0xC0); + state = THREE_CHARS_DECODED; + } + break; + case THREE_CHARS_DECODED: + if (decodedChar == PAD_INDEX) { + ba.write(quantum, 0, 2); + state = PAD_FOUR_READ; + } else { + quantum[2] = (byte) (quantum[2] | decodedChar); + ba.write(quantum, 0, 3); + state = NO_CHARS_DECODED; + } + break; + case PAD_THREE_READ: + if (decodedChar != PAD_INDEX) { + throw new IOException("Missing pad character"); + } + state = PAD_FOUR_READ; + break; + case PAD_FOUR_READ: + throw new IOException("Invalid input follows pad character"); + } + } + + // Test valid terminal states + if (state != NO_CHARS_DECODED && state != PAD_FOUR_READ) { + throw new IOException("Invalid sequence of input characters"); + } + + return ba.toByteArray(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64BinaryAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64BinaryAttribute.java new file mode 100644 index 0000000..07cbc4f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/Base64BinaryAttribute.java @@ -0,0 +1,251 @@ + +/* + * @(#)Base64BinaryAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.io.IOException; + +import java.net.URI; + +import java.util.Arrays; + +import org.w3c.dom.Node; + + +/** + * Representation of an xsi:base64Binary value. This class supports parsing + * xsi:base64Binary values. All objects of this class are immutable and + * all methods of the class are thread-safe. + * + * @since 1.0 + * @author Steve Hanna + */ +public class Base64BinaryAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.BASE64BINARY; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual binary value that this object represents. + */ + private byte [] value; + + /** + * The value returned by toString(). Cached, but only + * generated if needed. + */ + private String strValue; + + /** + * Creates a new Base64BinaryAttribute that represents + * the byte [] value supplied. + * + * @param value the byte [] value to be represented + */ + public Base64BinaryAttribute(byte [] value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + // This will throw a NullPointerException if value == null. + // That's what we want in that case. + this.value = (byte[])value.clone(); + } + + /** + * Returns a new Base64BinaryAttribute that represents + * the xsi:base64Binary at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new Base64BinaryAttribute representing the + * appropriate value + * @exception ParsingException if a parsing error occurs + */ + public static Base64BinaryAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a Base64BinaryAttribute"); + } + + /** + * Returns a new Base64BinaryAttribute that represents + * the xsi:base64Binary value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new Base64BinaryAttribute representing the + * desired value + * @exception ParsingException if a parsing error occurs + */ + public static Base64BinaryAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "Base64BinaryAttribute from null input"); + } + byte [] bytes = null; + + try { + bytes = Base64.decode(value, false); + } catch (IOException e) { + throw new ParsingException("Couldn't parse purported " + + "Base64 string: " + value, e); + } + + return new Base64BinaryAttribute(bytes); + } + + /** + * Returns the byte [] value represented by this object. + * Note that this value is cloned before returning to prevent + * unauthorized modifications. + * + * @return the byte [] value + */ + public byte [] getValue() { + return (byte[])this.value.clone(); + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof Base64BinaryAttribute)) { + return false; + } + Base64BinaryAttribute other = (Base64BinaryAttribute)o; + + return Arrays.equals(this.value, other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + int code = this.value[0]; + + for (int i = 1; i < this.value.length; i++) { + code *= 31; + code += this.value[i]; + } + + return code; + } + + /** + * Make the String representation of this object. + * + * @return the String representation + */ + private String makeStringRep() { + return Base64.encode(this.value); + } + + /** + * Returns a String representation. + * + * @return the String representation + */ + public String toString() { + if (this.strValue == null) { + this.strValue = makeStringRep(); + } + return "Base64BinaryAttribute: [" + Constants.nl + + this.strValue + "]" + Constants.nl; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + if (this.strValue == null) { + this.strValue = makeStringRep(); + } + + return this.strValue; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BaseAttributeFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BaseAttributeFactory.java new file mode 100644 index 0000000..d90d439 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BaseAttributeFactory.java @@ -0,0 +1,267 @@ + +/* + * @(#)BaseAttributeFactory.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.net.URI; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * This is a basic implementation of AttributeFactory. It + * implements the insertion and retrieval methods, but doesn't actually + * setup the factory with any datatypes. + *

    + * Note that while this class is thread-safe on all creation methods, it + * is not safe to add support for a new datatype while creating an instance + * of a value. This follows from the assumption that most people will + * initialize these factories up-front, and then start processing without + * ever modifying the factories. If you need these mutual operations to + * be thread-safe, then you should write a wrapper class that implements + * the right synchronization. + * + * @since 1.2 + * @author Seth Proctor + */ +public class BaseAttributeFactory extends AttributeFactory +{ + + // the map of proxies + private HashMap attributeMap; + + /** + * Default constructor. + */ + public BaseAttributeFactory() { + this.attributeMap = new HashMap(); + } + + /** + * Constructor that configures this factory with an initial set of + * supported datatypes. + * + * @param attributes a Map of Strings to + * AttributeProxys + * + * @throws IllegalArgumentException if any elements of the Map are not + * AttributeProxys + */ + public BaseAttributeFactory(Map attributes) { + this.attributeMap = new HashMap(); + + Iterator it = attributes.keySet().iterator(); + while (it.hasNext()) { + try { + String id = it.next(); + AttributeProxy proxy = attributes.get(id); + this.attributeMap.put(id, proxy); + } catch (ClassCastException cce) { + throw new IllegalArgumentException("an element of the map " + + "was not an instance of " + + "AttributeProxy"); + } + } + } + + /** + * Adds a proxy to the factory, which in turn will allow new attribute + * types to be created using the factory. Typically the proxy is + * provided as an anonymous class that simply calls the getInstance + * methods (or something similar) of some AttributeValue + * class. + * + * @param id the name of the attribute type + * @param proxy the proxy used to create new attributes of the given type + */ + public void addDatatype(String id, AttributeProxy proxy) { + // make sure this doesn't already exist + if (this.attributeMap.containsKey(id)) { + throw new IllegalArgumentException("datatype already exists"); + } + + this.attributeMap.put(id, proxy); + } + + /** + * Returns the datatype identifiers supported by this factory. + * + * @return a Set of Strings + */ + public Set getSupportedDatatypes() { + return Collections.unmodifiableSet(this.attributeMap.keySet()); + } + + /** + * Creates a value based on the given DOM root node. The type of the + * attribute is assumed to be present in the node as an XACML attribute + * named DataType, as is the case with the + * AttributeValueType in the policy schema. The value is assumed to be + * the first child of this node. + * + * @param root the DOM root of an attribute value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type in the node isn't + * known to the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public AttributeValue createValue(Node root) + throws UnknownIdentifierException, ParsingException { + if (root.getNodeType() != Node.ELEMENT_NODE || + root.getAttributes().getNamedItem("DataType") == null) { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.ATTRIBUTE_VALUE); + String message = ""; + if ( root.getNodeType() != Node.ELEMENT_NODE ) { + message = ": received element is not a node (" + root.toString() + ")"; + } else if ( root.getAttributes().getNamedItem("DataType") == null) { + message = ": missing attribute \"DataType\""; + } + + throw new ParsingException("Error while parsing AttributeValue" + message + + ( src == null ? "" : src.getLocationMsgForError())); + } + Node node = root.getAttributes().getNamedItem("DataType"); + + return createValue(root, node.getNodeValue()); + } + + /** + * Creates a value based on the given DOM root node and data type. + * + * @param root the DOM root of an attribute value + * @param dataType the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public AttributeValue createValue(Node root, URI dataType) + throws UnknownIdentifierException, ParsingException + { + return createValue(root, dataType.toString()); + } + + /** + * Creates a value based on the given DOM root node and data type. + * + * @param root the DOM root of an attribute value + * @param type the type of the attribute + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the type isn't known to + * the factory + * @throws ParsingException if the node is invalid or can't be parsed + * by the appropriate proxy + */ + public AttributeValue createValue(Node root, String type) + throws UnknownIdentifierException, ParsingException + { + AttributeProxy proxy = (AttributeProxy)(this.attributeMap.get(type)); + + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.ATTRIBUTE_VALUE); + + if (proxy != null) { + try { + AttributeValue val = proxy.getInstance(root); + if ( src != null ) { + val.setSrcLocFromFactory(src); + src.setXACMLObject(val); + } + return val; + } catch (Exception e) { + throw new ParsingException("couldn't create " + type + + " attribute based on DOM node" + + (src != null ? src.getLocationMsgForError() : ""), e); + } + } + throw new UnknownIdentifierException("Attributes of type " + type + + " aren't supported." + + (src != null ? src.getLocationMsgForError() : "")); + } + + /** + * Creates a value based on the given data type and text-encoded value. + * Used primarily by code that does an XPath query to get an + * attribute value, and then needs to turn the resulting value into + * an Attribute class. + * + * @param dataType the type of the attribute + * @param value the text-encoded representation of an attribute's value + * + * @return a new AttributeValue + * + * @throws UnknownIdentifierException if the data type isn't known to + * the factory + * @throws ParsingException if the text is invalid or can't be parsed + * by the appropriate proxy + */ + public AttributeValue createValue(URI dataType, String value) + throws UnknownIdentifierException, ParsingException + { + String type = dataType.toString(); + AttributeProxy proxy = (AttributeProxy)(this.attributeMap.get(type)); + + if (proxy != null) { + try { + return proxy.getInstance(value); + } catch (Exception e) { + throw new ParsingException("couldn't create " + type + + " attribute from input: " + value, e); + } + } + throw new UnknownIdentifierException("Attributes of type " + type + + " aren't supported."); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BooleanAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BooleanAttribute.java new file mode 100644 index 0000000..6b17a4b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/BooleanAttribute.java @@ -0,0 +1,308 @@ + +/* + * @(#)BooleanAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.ParsingException; + +import java.net.URI; + +import org.w3c.dom.Node; + + +/** + * Representation of an xs:boolean value. This class supports parsing + * xs:boolean values. All objects of this class are immutable and + * all methods of the class are thread-safe. + * + * @since 1.0 + * @author Marco Barreno + * @author Steve Hanna + */ +public class BooleanAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = TypeIdentifierConstants.BOOLEAN; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Single instance of BooleanAttribute that represents true. + * Initialized by the static initializer below. + */ + private static BooleanAttribute trueInstance; + + /** + * Single instance of BooleanAttribute that represents false. + * Initialized by the static initializer below. + */ + private static BooleanAttribute falseInstance; + + /** + * TODO hack? required for null value for defining missing + * attributes in the statusDetail + */ + private static BooleanAttribute invalidInstance; + + /** + * Static initializer that initializes many static fields. + *

    + * It is possible identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + trueInstance = new BooleanAttribute(true); + falseInstance = new BooleanAttribute(false); + invalidInstance = new BooleanAttribute(); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual boolean value that this object represents. + */ + private boolean value; + + private boolean valid = true; + + /** + * Creates a new BooleanAttribute that represents + * the boolean value supplied. + *

    + * This constructor is private because it should not be used by + * anyone other than the static initializer in this class. + * Instead, please use one of the getInstance methods, which + * will ensure that only two BooleanAttribute objects are created, + * thus avoiding excess object creation. + */ + protected BooleanAttribute(boolean value) { + super(identifierURI); + + this.value = value; + } + + private BooleanAttribute() { + super(identifierURI); + + this.valid = false; + this.value = false; + } + + /** + * Returns a BooleanAttribute that represents + * the xs:boolean at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a BooleanAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParsingException + */ + public static BooleanAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a BooleanAttribute"); + } + + /** + * Returns a BooleanAttribute that represents + * the xs:boolean value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a BooleanAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParsingException + */ + public static BooleanAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + return invalidInstance; +// throw new ParsingException("Can't create a " +// + "BooleanAttribute from null input"); + } + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + if (value.equals("true")) { + return trueInstance; + } + if (value.equals("false")) { + return falseInstance; + } + if (value.equals("")) { + return invalidInstance; + } + + throw new ParsingException("Boolean string must be true or false"); + } + + /** + * Returns a BooleanAttribute that represents + * the boolean value provided. + * + * @param value a boolean representing the desired value + * @return a BooleanAttribute representing the + * appropriate value + */ + public static BooleanAttribute getInstance(boolean value) { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + if (value) { + return trueInstance; + } + return falseInstance; + } + + /** + * Returns a BooleanAttribute that represents + * a true value. + * + * @return a BooleanAttribute representing a + * true value + */ + public static BooleanAttribute getTrueInstance() { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + return trueInstance; + } + + /** + * Returns a BooleanAttribute that represents + * a false value. + * + * @return a BooleanAttribute representing a + * false value + */ + public static BooleanAttribute getFalseInstance() { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + return falseInstance; + } + + /** + * Returns the boolean value represented by this object. + * + * @return the boolean value + */ + public boolean getValue() { + if (!valid) { + throw new RuntimeException("Accessing invalid attribute"); + } + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof BooleanAttribute)) { + return false; + } + + BooleanAttribute other = (BooleanAttribute)o; + + return (this.value == other.value && this.valid == other.valid); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + // these numbers come from the javadoc for java.lang.Boolean...no, + // really, they do. I can't imagine what they were thinking... + return (this.value ? 1231 : 1237); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + if (valid ) { + return (this.value ? "true" : "false"); + } else { + return ""; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DNSNameAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DNSNameAttribute.java new file mode 100644 index 0000000..2601673 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DNSNameAttribute.java @@ -0,0 +1,292 @@ + +/* + * @(#)DNSNameAttribute.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Represents the DNSName datatype introduced in XACML 2.0. All objects of + * this class are immutable and all methods of the class are thread-safe. + * + * @since 2.0 + * @author Seth Proctor + */ +public class DNSNameAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.DNSNAME; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = new URI(identifier); + } catch (Exception e) { + earlyException = new IllegalArgumentException(); + earlyException.initCause(e); + } + } + + // the required hostname + private String hostname; + + // the optional port range + private PortRange range; + + // true if the hostname starts with a '*' + private boolean isSubdomain = false; + + /** + * Creates the new DNSNameAttribute with only the required + * hostname component. + * + * @param hostname the host name component of the address + */ + public DNSNameAttribute(String hostname) { + this(hostname, new PortRange()); + } + + /** + * Creates the new DNSNameAttribute with the optional + * port range component. + * + * @param hostname the host name component of the address + * @param range the port range + */ + public DNSNameAttribute(String hostname, PortRange range) { + super(identifierURI); + + // shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + // verify that the hostname is valid before we store it + if (! isValidHostName(hostname)) { + System.err.println("FIXME: throw error about bad hostname"); + } + // see if it started with a '*' character + if (hostname.charAt(0) == '*') { + this.isSubdomain = true; + } + this.hostname = hostname; + this.range = range; + } + + /** + * Private helper that tests whether the given string is valid. + */ + private boolean isValidHostName(String hostname) { + /* + hostname = *( domainlabel "." ) toplabel [ "." ] + domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + toplabel = alpha | alpha *( alphanum | "-" ) alphanum + */ + + String domainlabel = "\\w[[\\w|\\-]*\\w]?"; + String toplabel = "[a-zA-Z][[\\w|\\-]*\\w]?"; + String pattern = "[\\*\\.]?[" + domainlabel + "\\.]*" + toplabel + + "\\.?"; + + return hostname.matches(pattern); + } + + /** + * Returns a new DNSNameAttribute that represents + * the name at a particular DOM node. + * + * @param root the Node that contains the desired value + * + * @return a new DNSNameAttribute representing the + * appropriate value (null if there is a parsing error) + * @throws ParsingException + * @throws DOMException + */ + public static DNSNameAttribute getInstance(Node root) + throws DOMException, ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a DNSNameAttribute"); + } + + /** + * Returns a new DNSNameAttribute that represents + * the name indicated by the String provided. + * + * @param value a string representing the name + * + * @return a new DNSNameAttribute + * @throws ParsingException + */ + public static DNSNameAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "DNSNameAttribute from null input"); + } + int portSep = value.indexOf(':'); + + if (portSep == -1) { + // there is no port range, so just use the name + return new DNSNameAttribute(value); + } + // split the name and the port range + String hostname = value.substring(0, portSep); + PortRange range = + PortRange.getInstance(value.substring(portSep + 1, + value.length())); + return new DNSNameAttribute(hostname, range); + } + + /** + * Returns the host name represented by this object. + * + * @return the host name + */ + public String getHostName() { + return this.hostname; + } + + /** + * Returns the port range represented by this object which will be + * unbound if no range was specified. + * + * @return the port range + */ + public PortRange getPortRange() { + return this.range; + } + + /** + * Returns true if the leading character in the hostname is a '*', and + * therefore represents a matching subdomain, or false otherwise. + * + * @return true if the name represents a subdomain, false otherwise + */ + public boolean isSubdomain() { + return this.isSubdomain; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof DNSNameAttribute)) { + return false; + } + DNSNameAttribute other = (DNSNameAttribute)o; + + if (! this.hostname.toUpperCase().equals( + other.hostname.toUpperCase())) { + return false; + } + + if (! this.range.equals(other.range)) { + return false; + } + + return true; + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. + * + * @return the object's hashcode value + */ + public int hashCode() { + return encode().hashCode(); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + return "DNSNameAttribute: \"" + encode() + "\""; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + if (this.range.isUnbound()) { + return this.hostname; + } + + return this.hostname + ":" + this.range.encode(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateAttribute.java new file mode 100644 index 0000000..8c22abd --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateAttribute.java @@ -0,0 +1,714 @@ + +/* + * @(#)DateAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.w3c.dom.Node; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + + +/** + * Representation of an xs:date value. This class supports parsing + * xs:date values. All objects of this class are immutable and + * thread-safe. The Date objects returned are not, but + * these objects are cloned before being returned. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + * @author Steve Hanna + */ +public class DateAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = TypeIdentifierConstants.DATE; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + *

    + * This object is used for synchronization whenever we need + * protection across this whole class. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Parser for dates with no time zones + *

    + * This field is only initialized if needed (by initParsers()). + *

    + * NOTE: This object should only be accessed from code that + * has synchronized on it, since SimpleDateFormat objects are not + * thread-safe. + */ + private DateFormat simpleParser; + + /** + * Parser for dates with RFC 822 time zones (like +0300) + *

    + * This field is only initialized if needed (by initParsers()). + *

    + * NOTE: This object should only be accessed from code that + * has a lock on it, since SimpleDateFormat objects are not + * thread-safe. + */ + private DateFormat zoneParser; + + /** + * Calendar for GMT + *

    + * NOTE: This object should only be accessed from code that + * has a lock on it, since Calendar objects are not generally + * thread-safe. + */ + private Calendar gmtCalendar; + + /** + * Number of nanoseconds per millisecond + * (shared by other classes in this package) + */ + static final int NANOS_PER_MILLI = 1000000; + + /** + * Number of milliseconds per second + * (shared by other classes in this package) + */ + static final int MILLIS_PER_SECOND = 1000; + + /** + * Number of seconds in a minute + * (shared by other classes in this package) + */ + static final int SECONDS_PER_MINUTE = 60; + + /** + * Number of minutes in an hour + * (shared by other classes in this package) + */ + static final int MINUTES_PER_HOUR = 60; + + /** + * Number of hours in a day + * (shared by other classes in this package) + */ + static final int HOURS_PER_DAY = 24; + + /** + * Number of nanoseconds per second + * (shared by other classes in this package) + */ + static final int NANOS_PER_SECOND = NANOS_PER_MILLI * MILLIS_PER_SECOND; + + /** + * Number of milliseconds in a minute + * (shared by other classes in this package) + */ + static final int MILLIS_PER_MINUTE = + MILLIS_PER_SECOND * SECONDS_PER_MINUTE; + + /** + * Number of milliseconds in an hour + * (shared by other classes in this package) + */ + static final int MILLIS_PER_HOUR = + MILLIS_PER_MINUTE * MINUTES_PER_HOUR; + + /** + * Number of milliseconds in a day + * (shared by other classes in this package) + */ + static final long MILLIS_PER_DAY = MILLIS_PER_HOUR * HOURS_PER_DAY; + + /** + * Time zone value that indicates that the time zone was not + * specified. + */ + public static final int TZ_UNSPECIFIED = -1000000; + + /** + * The instant (in GMT) at which the specified date began (midnight) + * in the specified time zone. If no time zone was specified, + * the local time zone is used. + */ + private Date value; + + /** + * The time zone specified for this object (or TZ_UNSPECIFIED if + * unspecified). The offset to GMT, in minutes. + */ + private int timeZone; + + /** + * The time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * The offset to GMT, in minutes. + */ + private int defaultedTimeZone; + + /** + * Cached encoded value (null if not cached yet). + */ + private String encodedValue = null; + + /** + * Creates a new TimeAttribute that represents + * the current date in the default time zone. + */ + public DateAttribute() { + this(new Date()); + } + + /** + * Creates a new TimeAttribute that represents + * the given date with default timezone values. + * + * @param date a Date object representing the + * instant at which the specified date began (midnight) + * in the specified time zone (the actual time value + * will be forced to midnight) + */ + public DateAttribute(Date date) { + super(identifierURI); + + // Get the current time and GMT offset + int currOffset = DateTimeAttribute.getDefaultTZOffset(date); + long millis = date.getTime(); + + // Now find out the last time it was midnight local time + // (actually the last time it was midnight with the current + // GMT offset, but that's good enough). + + // Skip back by time zone offset. + // Multiplication with 1L to avoid overflows in the + // integer multiplication, since it's converted to long anyway + millis += 1L * currOffset * MILLIS_PER_MINUTE; + // Reset to last GMT midnight + millis -= millis % MILLIS_PER_DAY; + // Skip forward by time zone offset. + // Multiplication with 1L to avoid overflows in the + // integer multiplication, since it's converted to long anyway + millis -= 1L * currOffset * MILLIS_PER_MINUTE; + date.setTime(millis); + init(date, currOffset, currOffset); + } + + /** + * Creates a new DateAttribute that represents + * the date supplied. + * + * @param date a Date object representing the + * instant at which the specified date began (midnight) + * in the specified time zone + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object (if it was originally unspecified, + * the default time zone used). + * The offset to GMT, in minutes. + */ + public DateAttribute(Date date, int timeZone, int defaultedTimeZone) { + super(identifierURI); + + init(date, timeZone, defaultedTimeZone); + } + + /** + * Initialization code shared by constructors. + * + * @param date a Date object representing the + * instant at which the specified date began (midnight) + * in the specified time zone. + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object (if it was originally unspecified, + * the default time zone used). + * The offset to GMT, in minutes. + */ + private void init(Date date, int timeZone, int defaultedTimeZone) { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + this.value = (Date) date.clone(); + this.timeZone = timeZone; + this.defaultedTimeZone = defaultedTimeZone; + } + + /** + * Returns a new DateAttribute that represents + * the xs:date at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new DateAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParseException + * @throws ParsingException + */ + public static DateAttribute getInstance(Node root) + throws ParseException, ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a DateAttribute"); + } + + /** + * Returns a new DateAttribute that represents + * the xs:date value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new DateAttribute representing the + * desired value (null if there is a parsing error) + * + * @throws ParseException + * @throws ParsingException + */ + public static DateAttribute getInstance(String value) + throws ParseException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "DateAttribute from null input"); + } + Date dateValue = null; + int timeZone; + int defaultedTimeZone; + + // This simple parser has no time zone + DateFormat simpleParser = new SimpleDateFormat("yyyy-MM-dd"); + simpleParser.setLenient(false); + + // This parser has a four digit offset to GMT with sign + DateFormat zoneParser = new SimpleDateFormat("yyyy-MM-ddZ"); + // FIXME: temporarily we need to set this to true + // this is a problem with Java 1.5, if you now + // of good documentation about the differnces between + // SimpleDateFormat in 1.4 and 1.5 let me (ludwig) know. + zoneParser.setLenient(true); + + // If string ends with Z, it's in GMT. Chop off the Z and + // add +0000 to make the time zone explicit, then parse it + // with the timezone parser. + if (value.endsWith("Z")) { + value = value.substring(0, value.length()-1) + "+0000"; + dateValue = strictParse(zoneParser, value); + timeZone = 0; + defaultedTimeZone = 0; + } else { + // If string ends with :XX, it must have a time zone + // or be invalid. Strip off the possible time zone and + // make sure what's left is a valid simple date. If so, + // reformat the time zone by stripping out the colon + // and parse the whole thing with the timezone parser. + int len = value.length(); + + if ((len > 6) && (value.charAt(len-3) == ':')) { + Date gmtValue = strictParse(zoneParser, + value.substring(0,len-6) + + "+0000"); + value = value.substring(0, len-3) + + value.substring(len-2, len); + dateValue = strictParse(zoneParser, value); + timeZone = + (int) (gmtValue.getTime() - dateValue.getTime()); + timeZone = timeZone / 60000; + defaultedTimeZone = timeZone; + } else { + // No funny business. This must be a simple date. + dateValue = strictParse(simpleParser, value); + timeZone = TZ_UNSPECIFIED; + Date gmtValue = strictParse(zoneParser, value + "+0000"); + defaultedTimeZone = + (int) (gmtValue.getTime() - dateValue.getTime()); + defaultedTimeZone = defaultedTimeZone / 60000; + } + } + + // If parsing went OK, create a new DateAttribute object and + // return it. + DateAttribute attr = new DateAttribute(dateValue, timeZone, + defaultedTimeZone); + return attr; + } + + /** + * Parse a String using a DateFormat parser, requiring that + * the entire String be consumed by the parser. On success, + * return a Date. On failure, throw a ParseException. + *

    + * Synchronize on the parser object when using it, since we + * assume they're the shared static objects in this class. + */ + private static Date strictParse(DateFormat parser, String str) + throws ParseException { + ParsePosition pos = new ParsePosition(0); + Date ret; + synchronized (parser) { + ret = parser.parse(str, pos); + } + if (pos.getIndex() != str.length()) { + throw new ParseException("", 0); + } + return ret; + } + + /** + * Initialize the parser objects. + */ + private void initParsers() { + // If simpleParser is already set, we're done. + if (this.simpleParser != null) { + return; + } + + // Make sure that identifierURI is not null + if (earlyException != null) { + throw earlyException; + } + + // Synchronize on identifierURI while initializing parsers + // so we don't end up using a half-way initialized parser + synchronized (identifierURI) { + // This simple parser has no time zone + this.simpleParser = new SimpleDateFormat("yyyy-MM-dd"); + this.simpleParser.setLenient(false); + + // This parser has a four digit offset to GMT with sign + this.zoneParser = new SimpleDateFormat("yyyy-MM-ddZ"); + // FIXME: temporarily we need to set this to true + // this is a problem with Java 1.5, if you now + // of good documentation about the differnces between + // SimpleDateFormat in 1.4 and 1.5 let me (ludwig) know. + this.zoneParser.setLenient(true); + } + } + + /** + * Gets the date represented by this object. The return value is + * a Date object representing the + * instant at which the specified date began (midnight) + * in the time zone. + *

    + * NOTE: The Date object is cloned before it + * is returned to avoid unauthorized changes. + * + * @return a Date object representing the instant + * at which the date began + */ + public Date getValue() { + return (Date) this.value.clone(); + } + + /** + * Gets the specified time zone of this object (or + * TZ_UNSPECIFIED if unspecified). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getTimeZone() { + return this.timeZone; + } + + /** + * Gets the time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getDefaultedTimeZone() { + return this.defaultedTimeZone; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + *

    + * Two DateAttributes are equal if and only if the + * instant on which the date began is equal. This means that they + * must have the same time zone. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof DateAttribute)) { + return false; + } + + DateAttribute other = (DateAttribute)o; + + return this.value.equals(other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. + * + * @return the object's hashcode value + */ + public int hashCode() { + // Only the value field is considered by the equals method, so only + // that field should be considered by this method. + return this.value.hashCode(); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("DateAttribute: [" + Constants.nl); + sb.append(" Date: " + this.value + " local time"); + sb.append(" TimeZone: " + this.timeZone); + sb.append(" Defaulted TimeZone: " + this.defaultedTimeZone); + sb.append("]"); + + return sb.toString(); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This must return a value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public String encode() { + if (this.encodedValue != null) { + return this.encodedValue; + } + + if (this.timeZone == TZ_UNSPECIFIED) { + // If no time zone was specified, format Date value in + // local time with no time zone string. + initParsers(); + synchronized (this.simpleParser) { + this.encodedValue = this.simpleParser.format(this.value); + } + } else { + // If a time zone was specified, don't use SimpleParser + // because it can only format dates in the local (default) + // time zone. And the offset between that time zone and the + // time zone we need to display can vary in complicated ways. + + // Instead, do it ourselves using our formatDateWithTZ method. + this.encodedValue = formatDateWithTZ(); + } + return this.encodedValue; + } + + /** + * Encodes the value of this object as an xsi:date. + * Only for use when the time zone is specified. + * + * @return a String form of the value + */ + private String formatDateWithTZ() { + if (this.gmtCalendar == null) { + TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT"); + + // Locale doesn't make much difference here. We don't use + // any of the strings in the Locale and we don't do anything + // that depends on week count conventions. We use the US + // locale because it's always around and it ensures that we + // will always get a Gregorian calendar, which is necessary + // for compliance with ISO 8501. + this.gmtCalendar = Calendar.getInstance(gmtTimeZone, Locale.US); + } + + // "YYYY-MM-DD+hh:mm".length() = 16 + // Length may be longer if years < -999 or > 9999 + StringBuffer buf = new StringBuffer(16); + + // Start with the GMT instant when the date started in the + // specified time zone (would be 7:00 PM the preceding day + // if the specified time zone was +0500). + this.gmtCalendar.setTime(this.value); + // Bump by the timeZone (so we get the right date/time that + // that we want to format) + this.gmtCalendar.add(Calendar.MINUTE, this.timeZone); + + // Now, assemble the string + int year = this.gmtCalendar.get(Calendar.YEAR); + buf.append(zeroPadInt(year, 4)); + buf.append('-'); + // JANUARY is 0 + int month = this.gmtCalendar.get(Calendar.MONTH) + 1; + buf.append(zeroPadInt(month, 2)); + buf.append('-'); + int dom = this.gmtCalendar.get(Calendar.DAY_OF_MONTH); + buf.append(zeroPadInt(dom, 2)); + + int tzNoSign = this.timeZone; + if (this.timeZone < 0) { + tzNoSign = -tzNoSign; + buf.append('-'); + } else { + buf.append('+'); + } + int tzHours = tzNoSign / 60; + buf.append(zeroPadInt(tzHours, 2)); + buf.append(':'); + int tzMinutes = tzNoSign % 60; + buf.append(zeroPadInt(tzMinutes, 2)); + + return buf.toString(); + } + + /** + * Takes a String representation of an integer (an optional + * sign followed by digits) and pads it with zeros on the left + * until it has at least the specified number of digits. + * Note that this function will work for an integer of + * any size: int, long, etc. + * + * @param unpadded the unpadded String + * (must have length of at least one) + * @param minDigits the minimum number of digits desired + * @return the padded String + */ + static String zeroPadIntString(String unpadded, int minDigits) { + int len = unpadded.length(); + + // Get the sign character (or 0 if none) + char sign = unpadded.charAt(0); + if ((sign != '-') && (sign != '+')) { + sign = 0; + } + + // The number of characters required is the number of digits, + // plus one for the sign if present. + int minChars = minDigits; + if (sign != 0) { + minChars++; + } + + // If we already have that many characters, we're done. + if (len >= minChars) { + return unpadded; + } + + // Otherwise, create the buffer + StringBuffer buf = new StringBuffer(); + + // Copy in the sign first, if present + if (sign != 0) { + buf.append(sign); + } + + // Add the zeros + int zerosNeeded = minChars - len; + while (zerosNeeded-- != 0) { + buf.append('0'); + } + // Copy the rest of the unpadded string + if (sign != 0) { + // Skip sign + buf.append(unpadded.substring(1, len)); + } else { + buf.append(unpadded); + } + + return buf.toString(); + } + + /** + * Converts an integer to a base 10 string and pads it with + * zeros on the left until it has at least the specified + * number of digits. Note that the length of the resulting + * string will be greater than minDigits if the number is + * negative since the string will start with a minus sign. + * + * @param intValue the integer to convert + * @param minDigits the minimum number of digits desired + * @return the padded String + */ + static String zeroPadInt(int intValue, int minDigits) { + return zeroPadIntString(Integer.toString(intValue), minDigits); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateTimeAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateTimeAttribute.java new file mode 100644 index 0000000..1fdb231 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DateTimeAttribute.java @@ -0,0 +1,754 @@ + +/* + * @(#)DateTimeAttribute.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.net.URI; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.w3c.dom.Node; + + +/** + * Representation of an xs:dateTime value. This class supports parsing + * xs:dateTime values. All objects of this class are immutable and + * thread-safe. The Date objects returned are not, but + * these objects are cloned before being returned. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + * @author Steve Hanna + * @author Ludwig Seitz + */ +public class DateTimeAttribute extends AttributeValue implements Cloneable +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.DATETIME; + + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + *

    + * This object is used for synchronization whenever we need + * protection across this whole class. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Parser for dates with no time zones + *

    + * This field is only initialized if needed (by initParsers()). + *

    + * NOTE: This object should only be accessed from code that + * has synchronized on it, since SimpleDateFormat objects are not + * thread-safe. + */ + private DateFormat simpleParser; + + /** + * Parser for dates with RFC 822 time zones (like +0300) + *

    + * This field is only initialized if needed (by initParsers()). + *

    + * NOTE: This object should only be accessed from code that + * has synchronized on it, since SimpleDateFormat objects are not + * thread-safe. + */ + private DateFormat zoneParser; + + /** + * Calendar for GMT + *

    + * NOTE: This object should only be accessed from code that + * has a lock on it, since Calendar objects are not generally + * thread-safe. + */ + private Calendar gmtCalendar; + + /** + * Time zone value that indicates that the time zone was not + * specified. + */ + public static final int TZ_UNSPECIFIED = -1000000; + + /** + * The actual date and time that this object represents (in GMT, + * as with all Date objects). If no time zone was specified, the + * local time zone is used to convert to GMT. + *

    + * This Date does not include fractions of a second. Those are + * handled by the separate nanoseconds field, since Date only + * provides millisecond accuracy and the XML Query spec requires + * at least 100 nanosecond accuracy. + */ + private Date value; + + /** + * The number of nanoseconds beyond the Date given by the value + * field. The XML Query document says that fractional seconds + * must be supported down to at least 100 nanosecond resolution. + * The Date class only supports milliseconds, so we include here + * support for nanosecond resolution. + */ + private int nanoseconds; + + /** + * The time zone specified for this object (or TZ_UNSPECIFIED if + * unspecified). The offset to GMT, in minutes. + */ + private int timeZone; + + /** + * The time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * The offset to GMT, in minutes. + */ + private int defaultedTimeZone; + + /** + * Cached encoded value (null if not cached yet). + */ + private String encodedValue = null; + + /** + * Creates a new DateTimeAttribute that represents + * the current date in the default time zone. + */ + public DateTimeAttribute() { + this(new Date()); + } + + /** + * Creates a new DateTimeAttribute that represents + * the supplied date but uses default timezone and offset values. + * + * @param dateTime a Date object representing the + * specified date and time down to second + * resolution. If this object has non-zero + * milliseconds, they are combined + * with the nanoseconds parameter. + */ + public DateTimeAttribute(Date dateTime) { + super(identifierURI); + + int currOffset = getDefaultTZOffset(dateTime); + init(dateTime, 0, currOffset, currOffset); + } + + /** + * Creates a new DateTimeAttribute that represents + * the date supplied. + * + * @param dateTime a Date object representing the + * specified date and time down to second + * resolution. If this object has non-zero + * milliseconds, they are combined + * with the nanoseconds parameter. + * @param nanoseconds the number of nanoseconds beyond the + * Date specified in the date parameter + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object (if it was originally unspecified, + * the default time zone used). + * The offset to GMT, in minutes. + */ + public DateTimeAttribute(Date dateTime, int nanoseconds, int timeZone, + int defaultedTimeZone) { + super(identifierURI); + + init(dateTime, nanoseconds, timeZone, defaultedTimeZone); + } + + /** + * The clone method. + * + * @return a copy of this object. + */ + public Object clone() { + try { + DateTimeAttribute clone = (DateTimeAttribute)super.clone(); + clone.value = (Date)this.value.clone(); + clone.nanoseconds = this.nanoseconds; + clone.timeZone = this.timeZone; + clone.defaultedTimeZone = this.defaultedTimeZone; + clone.encodedValue = this.encodedValue; + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone DateTimeAttribute"); + } + } + + /** + * Initialization code shared by constructors. + * + * @param date a Date object representing the + * specified date and time down to second + * resolution. If this object has non-zero + * milliseconds, they are combined + * with the nanoseconds parameter. + * @param nanoseconds the number of nanoseconds beyond the + * Date specified in the date parameter + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object (if it was originally unspecified, + * the default time zone used). + * The offset to GMT, in minutes. + */ + private void init(Date date, int nanoseconds, int timeZone, + int defaultedTimeZone) { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + // Make a new Date object + this.value = (Date) date.clone(); + // Combine the nanoseconds so they are between 0 and 999,999,999 + this.nanoseconds = combineNanos(this.value, nanoseconds); + this.timeZone = timeZone; + this.defaultedTimeZone = defaultedTimeZone; + } + + /** + * Returns a new DateTimeAttribute that represents + * the xs:dateTime at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new DateTimeAttribute representing the + * appropriate value + * + * @throws ParsingException if any problems occurred while parsing + * @throws NumberFormatException + * @throws ParseException + */ + public static DateTimeAttribute getInstance(Node root) + throws ParsingException, NumberFormatException, ParseException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a DayTimeAttribute"); + } + + /** + * Returns a new DateTimeAttribute that represents + * the xs:dateTime value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new DateTimeAttribute representing the + * desired value + * @throws ParsingException if the text is formatted incorrectly + * @throws NumberFormatException if the nanosecond format is incorrect + * @throws ParseException + */ + public static DateTimeAttribute getInstance(String value) + throws ParsingException, NumberFormatException, ParseException { + if (value == null) { + throw new ParsingException("Can't create a " + + "DayTimeAttribute from null input"); + } + Date dateValue = null; + int nanoseconds = 0; + int timeZone; + int defaultedTimeZone; + + // This simple parser has no time zone + DateFormat simpleParser + = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + simpleParser.setLenient(false); + + // This parser has a four digit offset to GMT with sign + DateFormat zoneParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + //FIXME: temporarily we need to set this to true + // this is a problem with Java 1.5, if you now + // of good documentation about the differnces between SimpleDateFormat + // in 1.4 and 1.5 let me (ludwig) know. + zoneParser.setLenient(true); + + // If string ends with Z, it's in GMT. Chop off the Z and + // add +00:00 to make the time zone explicit. + if (value.endsWith("Z")) { + value = value.substring(0, value.length()-1) + "+00:00"; + } + + // Figure out if the string has a time zone. + // If string ends with +XX:XX or -XX:XX, it must have + // a time zone or be invalid. + int len = value.length(); // This variable is often not up-to-date + boolean hasTimeZone = ((value.charAt(len-3) == ':') && + ((value.charAt(len-6) == '-') || + (value.charAt(len-6) == '+'))); + + // If string contains a period, it must have fractional + // seconds (or be invalid). Strip them out and put the + // value in nanoseconds. + int dotIndex = value.indexOf('.'); + if (dotIndex != -1) { + // Decide where fractional seconds end. + int secondsEnd = value.length(); + if (hasTimeZone) { + secondsEnd -= 6; + } + // Copy the fractional seconds out of the string. + String nanoString = value.substring(dotIndex+1, secondsEnd); + // Check that all those characters are ASCII digits. + for (int i = nanoString.length()-1; i >= 0; i--) { + char c = nanoString.charAt(i); + if ((c < '0') || (c > '9')) { + throw new ParsingException("non-ascii digit found"); + } + } + // If there are less than 9 digits in the fractional seconds, + // pad with zeros on the right so it's nanoseconds. + while (nanoString.length() < 9) { + nanoString += "0"; + } + // If there are more than 9 digits in the fractional seconds, + // drop the least significant digits. + if (nanoString.length() > 9) { + nanoString = nanoString.substring(0, 9); + } + // Parse the fractional seconds. + nanoseconds = Integer.parseInt(nanoString); + + // Remove the fractional seconds from the string. + value = value.substring(0, dotIndex) + + value.substring(secondsEnd, value.length()); + } + + // this is the code that may trow a ParseException + if (hasTimeZone) { + // Strip off the purported time zone and make sure what's + // left is a valid unzoned date and time (by parsing in GMT). + // If so, reformat the time zone by stripping out the colon + // and parse the revised string with the timezone parser. + + len = value.length(); + + Date gmtValue = strictParse(zoneParser, + value.substring(0,len-6) + "+0000"); + value = value.substring(0, len-3) + + value.substring(len-2, len); + dateValue = strictParse(zoneParser, value); + timeZone = + (int) (gmtValue.getTime() - dateValue.getTime()); + timeZone = timeZone / 60000; + defaultedTimeZone = timeZone; + } else { + // No funny business. This must be a simple date and time. + dateValue = strictParse(simpleParser, value); + timeZone = TZ_UNSPECIFIED; + // Figure out what time zone was used. + Date gmtValue = strictParse(zoneParser, value + "+0000"); + defaultedTimeZone = + (int) (gmtValue.getTime() - dateValue.getTime()); + defaultedTimeZone = defaultedTimeZone / 60000; + } + + // If parsing went OK, create a new DateTimeAttribute object and + // return it. + + DateTimeAttribute attr = new DateTimeAttribute(dateValue, nanoseconds, + timeZone, + defaultedTimeZone); + return attr; + } + + /** + * Parse a String using a DateFormat parser, requiring that + * the entire String be consumed by the parser. On success, + * return a Date. On failure, throw a ParseException. + *

    + * Synchronize on the parser object when using it, since we + * assume they're the shared static objects in this class. + */ + private static Date strictParse(DateFormat parser, String str) + throws ParseException { + ParsePosition pos = new ParsePosition(0); + Date ret; + synchronized (parser) { + ret = parser.parse(str, pos); + } + if (pos.getIndex() != str.length()) { + throw new ParseException("", 0); + } + return ret; + } + + /** + * Initialize the parser objects. + */ + private void initParsers() { + // If simpleParser is already set, we're done. + if (this.simpleParser != null) { + return; + } + + // Make sure that identifierURI is not null + if (earlyException != null) { + throw earlyException; + } + + // Synchronize on identifierURI while initializing parsers + // so we don't end up using a half-way initialized parser + synchronized (identifierURI) { + // This simple parser has no time zone + this.simpleParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + this.simpleParser.setLenient(false); + + // This parser has a four digit offset to GMT with sign + this.zoneParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + //FIXME: temporarily we need to set this to true + // this is a problem with Java 1.5, if you now + // of good documentation about the differnces between SimpleDateFormat + // in 1.4 and 1.5 let me (ludwig) know. + this.zoneParser.setLenient(true); + } + } + + /** + * Gets the date and time represented by this object. The return + * value is a Date object representing the + * specified date and time down to second resolution. + * Subsecond values are handled by the + * {@link #getNanoseconds getNanoseconds} method. + *

    + * NOTE: The Date object is cloned before it + * is returned to avoid unauthorized changes. + * + * @return a Date object representing the date and + * time represented by this object + */ + public Date getValue() { + return (Date) this.value.clone(); + } + + /** + * Gets the nanoseconds of this object. + * + * @return the number of nanoseconds + */ + public int getNanoseconds() { + return this.nanoseconds; + } + + /** + * Gets the time zone of this object (or TZ_UNSPECIFIED if + * unspecified). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getTimeZone() { + return this.timeZone; + } + + /** + * Gets the time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getDefaultedTimeZone() { + return this.defaultedTimeZone; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + *

    + * Two DateTimeAttributes are equal if and only if the + * dates and times represented are identical (down to the nanosecond). + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof DateTimeAttribute)) { + return false; + } + + DateTimeAttribute other = (DateTimeAttribute)o; + + // Since the value field is normalized into GMT, this is a + // good way to compare. + return (this.value.equals(other.value) && + (this.nanoseconds == other.nanoseconds)); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. + * + * @return the object's hashcode value + */ + public int hashCode() { + // Both the value field and the nanoseconds field are considered + // by the equals method, so it's best if the hashCode is derived + // from both of those fields. + int hashCode = this.value.hashCode(); + hashCode = 31*hashCode + this.nanoseconds; + return hashCode; + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("DateTimeAttribute: [" + Constants.nl); + sb.append(" Date: " + this.value + " local time"); + sb.append(" Nanoseconds: " + this.nanoseconds); + sb.append(" TimeZone: " + this.timeZone); + sb.append(" Defaulted TimeZone: " + this.defaultedTimeZone); + sb.append("]"); + + return sb.toString(); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This must return a value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public String encode() { + if (this.encodedValue != null) { + return this.encodedValue; + } + + if (this.timeZone == TZ_UNSPECIFIED) { + // If no time zone was specified, format Date value in + // local time with no time zone string. + initParsers(); + synchronized (this.simpleParser) { + this.encodedValue = this.simpleParser.format(this.value); + } + if (this.nanoseconds != 0) { + this.encodedValue = this.encodedValue + "." + + DateAttribute.zeroPadInt(this.nanoseconds, 9); + } + } else { + // If a time zone was specified, don't use SimpleParser + // because it can only format dates in the local (default) + // time zone. And the offset between that time zone and the + // time zone we need to display can vary in complicated ways. + + // Instead, do it ourselves using our formatDateWithTZ method. + this.encodedValue = formatDateTimeWithTZ(); + } + return this.encodedValue; + } + + /** + * Encodes the value of this object as an xsi:dateTime. + * Only for use when the time zone is specified. + * + * @return a String form of the value + */ + private String formatDateTimeWithTZ() { + if (this.gmtCalendar == null) { + TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT"); + + // Locale doesn't make much difference here. We don't use + // any of the strings in the Locale and we don't do anything + // that depends on week count conventions. We use the US + // locale because it's always around and it ensures that we + // will always get a Gregorian calendar, which is necessary + // for compliance with ISO 8501. + this.gmtCalendar = Calendar.getInstance(gmtTimeZone, Locale.US); + } + + // "YYYY-MM-DDThh:mm:ss.sssssssss+hh:mm".length() = 35 + // Length may be longer if years < -999 or > 9999 + StringBuffer buf = new StringBuffer(35); + + // Start with the proper time in GMT. + this.gmtCalendar.setTime(this.value); + // Bump by the timeZone, since we're going to be extracting + // the value in GMT + this.gmtCalendar.add(Calendar.MINUTE, this.timeZone); + + // Now, assemble the string + int year = this.gmtCalendar.get(Calendar.YEAR); + buf.append(DateAttribute.zeroPadInt(year, 4)); + buf.append('-'); + // JANUARY is 0 + int month = this.gmtCalendar.get(Calendar.MONTH) + 1; + buf.append(DateAttribute.zeroPadInt(month, 2)); + buf.append('-'); + int dom = this.gmtCalendar.get(Calendar.DAY_OF_MONTH); + buf.append(DateAttribute.zeroPadInt(dom, 2)); + buf.append('T'); + int hour = this.gmtCalendar.get(Calendar.HOUR_OF_DAY); + buf.append(DateAttribute.zeroPadInt(hour, 2)); + buf.append(':'); + int minute = this.gmtCalendar.get(Calendar.MINUTE); + buf.append(DateAttribute.zeroPadInt(minute, 2)); + buf.append(':'); + int second = this.gmtCalendar.get(Calendar.SECOND); + buf.append(DateAttribute.zeroPadInt(second, 2)); + + if (this.nanoseconds != 0) { + buf.append('.'); + buf.append(DateAttribute.zeroPadInt(this.nanoseconds, 9)); + } + + int tzNoSign = this.timeZone; + if (this.timeZone < 0) { + tzNoSign = -tzNoSign; + buf.append('-'); + } else { + buf.append('+'); + } + int tzHours = tzNoSign / 60; + buf.append(DateAttribute.zeroPadInt(tzHours, 2)); + buf.append(':'); + int tzMinutes = tzNoSign % 60; + buf.append(DateAttribute.zeroPadInt(tzMinutes, 2)); + + return buf.toString(); + } + + /** + * Gets the offset in minutes between the default time zone and + * UTC for the specified date. + * + * @param date the Date whose offset is desired + * + * @return the offset in minutes + */ + static int getDefaultTZOffset(Date date) { + int offset = TimeZone.getDefault().getOffset(date.getTime()); + offset = offset / DateAttribute.MILLIS_PER_MINUTE; + return offset; + } + + /** + * Combines a number of nanoseconds with a Date + * so that the Date has no fractional seconds and the number + * of nanoseconds is non-negative and less than a second. + *

    + * WARNING: This function changes the value stored in + * the date parameter! + * + * @param date the Date to be combined + * (value may be modified!) + * @param nanoseconds the nanoseconds to be combined + * + * @return the resulting number of nanoseconds + */ + static int combineNanos(Date date, int nanoseconds) { + long millis = date.getTime(); + int milliCarry = (int) (millis % DateAttribute.MILLIS_PER_SECOND); + + // If nothing needs fixing, get out quick + if ((milliCarry == 0) && (nanoseconds > 0) + && (nanoseconds < DateAttribute.NANOS_PER_SECOND)) { + return nanoseconds; + } + + // Remove any non-zero milliseconds from the date. + millis -= milliCarry; + // Add them into the nanoseconds. + long nanoTemp = nanoseconds; + // Multiplication with 1L to avoid overflows in the + // integer multiplication, since it's converted to long anyway + nanoTemp += 1L * milliCarry * DateAttribute.NANOS_PER_MILLI; + // Get the nanoseconds that represent fractional seconds. + // This we'll return. + int nanoResult = (int) (nanoTemp % DateAttribute.NANOS_PER_SECOND); + // Get nanoseconds that represent whole seconds. + nanoTemp -= nanoResult; + // Convert that to milliseconds and add it back to the date. + millis += nanoTemp / DateAttribute.NANOS_PER_MILLI; + date.setTime(millis); + + return nanoResult; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DayTimeDurationAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DayTimeDurationAttribute.java new file mode 100644 index 0000000..ea952d9 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DayTimeDurationAttribute.java @@ -0,0 +1,585 @@ + +/* + * @(#)DayTimeDurationAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.math.BigInteger; + +import java.net.URI; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import java.util.regex.Matcher; + +import org.w3c.dom.Node; + + +/** + * Representation of an xf:dayTimeDuration value. This class supports parsing + * xd:dayTimeDuration values. All objects of this class are immutable and + * thread-safe. The Date objects returned are not, but + * these objects are cloned before being returned. + * + * @since 1.0 + * @author Steve Hanna + */ +public class DayTimeDurationAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.DAYTIMEDURATION; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Regular expression for dayTimeDuration (a la java.util.regex) + */ + private static final String patternString = + "(\\-)?P((\\d+)?D)?(T((\\d+)?H)?((\\d+)?M)?((\\d+)?(.(\\d+)?)?S)?)?"; + + /** + * The index of the capturing group for the negative sign. + */ + private static final int GROUP_SIGN = 1; + + /** + * The index of the capturing group for the number of days. + */ + private static final int GROUP_DAYS = 3; + + /** + * The index of the capturing group for the number of hours. + */ + private static final int GROUP_HOURS = 6; + + /** + * The index of the capturing group for the number of minutes. + */ + private static final int GROUP_MINUTES = 8; + + /** + * The index of the capturing group for the number of seconds. + */ + private static final int GROUP_SECONDS = 10; + + /** + * The index of the capturing group for the number of nanoseconds. + */ + private static final int GROUP_NANOSECONDS = 12; + + /** + * Static BigInteger values. We only use these if one of + * the components is bigger than Integer.MAX_LONG and we + * want to detect overflow. + */ + private static BigInteger big24 = BigInteger.valueOf(24); + private static BigInteger big60 = BigInteger.valueOf(60); + private static BigInteger big1000 = BigInteger.valueOf(1000); + private static BigInteger bigMaxLong = BigInteger.valueOf(Long.MAX_VALUE); + + /** + * A shared Pattern object, only initialized if needed + */ + private static Pattern pattern; + + /** + * Negative flag. true if duration is negative, false otherwise + */ + private boolean negative; + + /** + * Number of days + */ + private long days; + + /** + * Number of hours + */ + private long hours; + + /** + * Number of minutes + */ + private long minutes; + + /** + * Number of seconds + */ + private long seconds; + + /** + * Number of nanoseconds + */ + private int nanoseconds; + + /** + * Total number of round seconds (in milliseconds) + */ + private long totalMillis; + + /** + * Cached encoded value (null if not cached yet). + */ + private String encodedValue = null; + + /** + * Creates a new DayTimeDurationAttribute that represents + * the duration supplied. + * + * @param negative true if the duration is negative, false otherwise + * @param days the number of days in the duration + * @param hours the number of hours in the duration + * @param minutes the number of minutes in the duration + * @param seconds the number of seconds in the duration + * @param nanoseconds the number of nanoseconds in the duration + * @throws IllegalArgumentException if the total number of milliseconds + * exceeds Long.MAX_LONG + */ + public DayTimeDurationAttribute(boolean negative, long days, long hours, + long minutes, long seconds, + int nanoseconds) + throws IllegalArgumentException { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + this.negative = negative; + this.days = days; + this.hours = hours; + this.minutes = minutes; + this.seconds = seconds; + this.nanoseconds = nanoseconds; + + // Convert all the components except nanoseconds to milliseconds + + // If any of the components is big (too big to be an int), + // use the BigInteger class to do the math so we can detect + // overflow. + if ((days > Integer.MAX_VALUE) || (hours > Integer.MAX_VALUE) || + (minutes > Integer.MAX_VALUE) || (seconds > Integer.MAX_VALUE)) { + + BigInteger bigDays = BigInteger.valueOf(days); + BigInteger bigHours = BigInteger.valueOf(hours); + BigInteger bigMinutes = BigInteger.valueOf(minutes); + BigInteger bigSeconds = BigInteger.valueOf(seconds); + + BigInteger bigTotal = bigDays.multiply(big24).add(bigHours) + .multiply(big60).add(bigMinutes).multiply(big60) + .add(bigSeconds).multiply(big1000); + + // If the result is bigger than Long.MAX_VALUE, we have an + // overflow. Indicate an error (should be a processing error, + // since it can be argued that we should handle gigantic + // values for this). + if (bigTotal.compareTo(bigMaxLong) == 1) { + throw new IllegalArgumentException("total number of " + + "milliseconds " + + "exceeds Long.MAX_VALUE"); + } + // If no overflow, convert to a long. + this.totalMillis = bigTotal.longValue(); + } else { + // The numbers are small, so do it the fast way. + this.totalMillis = ((((((days * 24) + hours) * 60) + minutes) * 60) + + seconds) * 1000; + } + } + + /** + * Returns a new DayTimeDurationAttribute that represents + * the xf:dayTimeDuration at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new DayTimeDurationAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParsingException + * @throws NumberFormatException + */ + public static DayTimeDurationAttribute getInstance(Node root) + throws ParsingException, NumberFormatException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a DayTimeDurationAttribute"); + } + + /** + * Returns the long value for the capturing group groupNumber. + * This method takes a Matcher that has been used to match a + * Pattern against a String, fetches the value for the specified + * capturing group, converts that value to an long, and returns + * the value. If that group did not match, 0 is returned. + * If the matched value is not a valid long, NumberFormatException + * is thrown. + * + * @param matcher the Matcher from which to fetch the group + * @param groupNumber the group number to fetch + * @return the long value for that groupNumber + * @throws NumberFormatException if the string value for that + * groupNumber is not a valid long + */ + private static long parseGroup(Matcher matcher, int groupNumber) + throws NumberFormatException { + long groupLong = 0; + + if (matcher.start(groupNumber) != -1) { + String groupString = matcher.group(groupNumber); + groupLong = Long.parseLong(groupString); + } + return groupLong; + } + + /** + * Returns a new DayTimeDurationAttribute that represents + * the xf:dayTimeDuration value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new DayTimeDurationAttribute representing the + * desired value (null if there is a parsing error) + * + * @throws ParsingException + * @throws NumberFormatException + */ + public static DayTimeDurationAttribute getInstance(String value) + throws ParsingException, NumberFormatException { + if (value == null) { + throw new ParsingException("Can't create a " + + "DayTimeDurationAttribute from null input"); + } + boolean negative = false; + long days = 0; + long hours = 0; + long minutes = 0; + long seconds = 0; + int nanoseconds = 0; + + // Compile the pattern, if not already done. + // No thread-safety problem here. The worst that can + // happen is that we initialize pattern several times. + if (pattern == null) { + try { + pattern = Pattern.compile(patternString); + } catch (PatternSyntaxException e) { + // This should never happen + throw new ParsingException("unexpected pattern match error"); + } + } + + // See if the value matches the pattern. + Matcher matcher = pattern.matcher(value); + boolean matches = matcher.matches(); + + // If not, syntax error! + if (!matches) { + throw new ParsingException("Syntax error in dayTimeDuration"); + } + + // If the negative group matched, the value is negative. + if (matcher.start(GROUP_SIGN) != -1) { + negative = true; + } + + try { + // If the days group matched, parse that value. + days = parseGroup(matcher, GROUP_DAYS); + + // If the hours group matched, parse that value. + hours = parseGroup(matcher, GROUP_HOURS); + + // If the minutes group matched, parse that value. + minutes = parseGroup(matcher, GROUP_MINUTES); + + // If the seconds group matched, parse that value. + seconds = parseGroup(matcher, GROUP_SECONDS); + + // Special handling for fractional seconds, since + // they can have any resolution. + if (matcher.start(GROUP_NANOSECONDS) != -1) { + String nanosecondString = matcher.group(GROUP_NANOSECONDS); + + // If there are less than 9 digits in the fractional seconds, + // pad with zeros on the right so it's nanoseconds. + while (nanosecondString.length() < 9) { + nanosecondString += "0"; + } + + // If there are more than 9 digits in the fractional seconds, + // drop the least significant digits. + if (nanosecondString.length() > 9) { + nanosecondString = nanosecondString.substring(0, 9); + } + + nanoseconds = Integer.parseInt(nanosecondString); + } + } catch (NumberFormatException e) { + // If we run into a number that's too big to be a long + // that's an error. Really, it's a processing error, + // since one can argue that we should handle that. + throw e; + } + + // Here's a requirement that's not checked for in the pattern. + // The designator 'T' must be absent if all the time + // items are absent. So the string can't end in 'T'. + // Note that we don't have to worry about a zero length + // string, since the pattern won't allow that. + if (value.charAt(value.length()-1) == 'T') { + throw new ParsingException("'T' must be absent if all" + + "time items are absent"); + } + // If parsing went OK, create a new DayTimeDurationAttribute object and + // return it. + return new DayTimeDurationAttribute(negative, days, hours, minutes, + seconds, nanoseconds); + } + + /** + * Returns true if the duration is negative. + * + * @return true if the duration is negative, false otherwise + */ + public boolean isNegative() { + return this.negative; + } + + /** + * Gets the number of days. + * + * @return the number of days + */ + public long getDays() { + return this.days; + } + + /** + * Gets the number of hours. + * + * @return the number of hours + */ + public long getHours() { + return this.hours; + } + + /** + * Gets the number of minutes. + * + * @return the number of minutes + */ + public long getMinutes() { + return this.minutes; + } + + /** + * Gets the number of seconds. + * + * @return the number of seconds + */ + public long getSeconds() { + return this.seconds; + } + + /** + * Gets the number of nanoseconds. + * + * @return the number of nanoseconds + */ + public int getNanoseconds() { + return this.nanoseconds; + } + + /** + * Gets the total number of round seconds (in milliseconds). + * + * @return the total number of seconds (in milliseconds) + */ + public long getTotalSeconds() { + return this.totalMillis; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof DayTimeDurationAttribute)) { + return false; + } + + DayTimeDurationAttribute other = (DayTimeDurationAttribute)o; + + return ((this.totalMillis == other.totalMillis) && + (this.nanoseconds == other.nanoseconds) && + (this.negative == other.negative)); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + // The totalMillis, nanoseconds, and negative fields are all considered + // by the equals method, so it's best if the hashCode is derived + // from all of those fields. + int hashCode = (int) this.totalMillis ^ (int) (this.totalMillis >> 32); + hashCode = 31*hashCode + this.nanoseconds; + if (this.negative) { + hashCode = -hashCode; + } + return hashCode; + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("DayTimeDurationAttribute: [" + Constants.nl); + sb.append(" Negative: " + this.negative); + sb.append(" Days: " + this.days); + sb.append(" Hours: " + this.hours); + sb.append(" Minutes: " + this.minutes); + sb.append(" Seconds: " + this.seconds); + sb.append(" Nanoseconds: " + this.nanoseconds); + sb.append(" TotalSeconds: " + this.totalMillis); + sb.append("]"); + + return sb.toString(); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This must return a value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public String encode() { + if (this.encodedValue != null) { + return this.encodedValue; + } + + // Length is quite variable + StringBuffer buf = new StringBuffer(10); + + if (this.negative) { + buf.append('-'); + } + buf.append('P'); + if (this.days != 0) { + buf.append(Long.toString(this.days)); + buf.append('D'); + } + if ((this.hours != 0) || (this.minutes != 0) + || (this.seconds != 0) || (this.nanoseconds != 0)) { + // Only include the T if there are some time fields + buf.append('T'); + } else { + // Make sure that there's always at least one field specified + if (this.days == 0) { + buf.append("0D"); + } + } + if (this.hours != 0) { + buf.append(Long.toString(this.hours)); + buf.append('H'); + } + if (this.minutes != 0) { + buf.append(Long.toString(this.minutes)); + buf.append('M'); + } + if ((this.seconds != 0) || (this.nanoseconds != 0)) { + buf.append(Long.toString(this.seconds)); + if (this.nanoseconds != 0) { + buf.append('.'); + buf.append(DateAttribute.zeroPadInt(this.nanoseconds, 9)); + } + buf.append('S'); + } + + this.encodedValue = buf.toString(); + + return this.encodedValue; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DecisionAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DecisionAttribute.java new file mode 100644 index 0000000..ba404c7 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DecisionAttribute.java @@ -0,0 +1,99 @@ + +/* + * @(#)DecisionAttribute.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.ctx.Result; + +/** + * Convenience class that represents the Decision attribute. + * + * @author Ludwig Seitz + * + */ +public class DecisionAttribute extends Attribute { + + + /** + * The static id URI of the Decision attribute + */ + private static URI idURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of idURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + idURI = URI.create(TypeIdentifierConstants.DECISION); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Constructor that creates a Decision Attribute. + * + * @param decision The decision code from the Result class. + */ + public DecisionAttribute(int decision) { + super(DecisionAttribute.idURI, null, + new StringAttribute((String)Result.DECISIONS.get(decision))); + if (earlyException != null) { + throw earlyException; + } + if (decision != Result.DECISION_DENY + && decision != Result.DECISION_PERMIT) { + throw new IllegalArgumentException("Decision attribute value must" + + " be 'PERMIT' or 'DENY'"); + + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DoubleAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DoubleAttribute.java new file mode 100644 index 0000000..ca9e595 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/DoubleAttribute.java @@ -0,0 +1,218 @@ + +/* + * @(#)DoubleAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an xsi:double value. This class supports parsing + * xsi:double values. All objects of this class are immutable and + * all methods of the class are thread-safe. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + * @author Steve Hanna + */ +public class DoubleAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.DOUBLE; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual double value that this object represents. + */ + private double value; + + /** + * Creates a new DoubleAttribute that represents + * the double value supplied. + * + * @param value the double value to be represented + */ + public DoubleAttribute(double value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + this.value = value; + } + + /** + * Returns a new DoubleAttribute that represents + * the xsi:double at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new DoubleAttribute representing the + * appropriate value (null if there is a parsing error) + * @throws NumberFormatException if the string form is not a double + * @throws ParsingException + */ + public static DoubleAttribute getInstance(Node root) + throws NumberFormatException, ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a DoubleAttribute"); + } + + /** + * Returns a new DoubleAttribute that represents + * the xsi:double value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new DoubleAttribute representing the + * desired value (null if there is a parsing error) + * @throws ParsingException + * @throws NumberFormatException if the value is not a double + */ + public static DoubleAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "DoubleAttribute from null input"); + } + // Convert "INF" to "Infinity" + if (value.endsWith("INF")) { + int infIndex = value.lastIndexOf("INF"); + value = value.substring(0, infIndex) + "Infinity"; + } + + return new DoubleAttribute(Double.parseDouble(value)); + } + + /** + * Returns the double value represented by this object. + * + * @return the double value + */ + public double getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof DoubleAttribute)) { + return false; + } + + DoubleAttribute other = (DoubleAttribute)o; + + // Handle the NaN case, where Java says NaNs are never + // equal and XML Query says they always are + if (Double.isNaN(this.value)) { + // this is a NaN, so see if the other is as well + if (Double.isNaN(other.value)) { + // they're both NaNs, so they're equal + return true; + } + // they're not both NaNs, so they're not equal + return false; + } + // not NaNs, so we can do a normal comparison + return (this.value == other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + long v = Double.doubleToLongBits(this.value); + return (int)(v ^ (v >>> 32)); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + return String.valueOf(this.value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/HexBinaryAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/HexBinaryAttribute.java new file mode 100644 index 0000000..9e6bd79 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/HexBinaryAttribute.java @@ -0,0 +1,326 @@ + +/* + * @(#)HexBinaryAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.net.URI; + +import java.util.Arrays; + +import org.w3c.dom.Node; + + +/** + * Representation of an xsi:hexBinary value. This class supports parsing + * xsi:hexBinary values. All objects of this class are immutable and + * all methods of the class are thread-safe. + * + * @since 1.0 + * @author Steve Hanna + */ +public class HexBinaryAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.HEXBINARY; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual binary value that this object represents. + */ + private byte [] value; + + /** + * The value returned by toString(). Cached, but only + * generated if needed. + */ + private String strValue; + + /** + * Creates a new HexBinaryAttribute that represents + * the byte [] value supplied. + * + * @param value the byte [] value to be represented + */ + public HexBinaryAttribute(byte [] value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + // This will throw a NullPointerException if value == null. + // That's what we want in that case. + this.value = (byte[])value.clone(); + } + + /** + * Returns a new HexBinaryAttribute that represents + * the xsi:hexBinary at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new HexBinaryAttribute representing the + * appropriate value + * @exception ParsingException if a parsing error occurs + */ + public static HexBinaryAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a HexBinaryAttribute"); + } + + /** + * Returns a new HexBinaryAttribute that represents + * the xsi:hexBinary value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new HexBinaryAttribute representing the + * desired value + * @exception ParsingException if a parsing error occurs + */ + public static HexBinaryAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "HexBinaryAttribute from null input"); + } + byte [] bytes = hexToBin(value); + + if (bytes == null) { + throw new ParsingException("Couldn't parse purported " + + "hex string: " + value); + } + return new HexBinaryAttribute(bytes); + } + + /** + * Returns the byte [] value represented by this object. + * Note that this value is cloned before returning to prevent + * unauthorized modifications. + * + * @return the byte [] value + */ + public byte [] getValue() { + return (byte[])this.value.clone(); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + int code = this.value[0]; + + for (int i = 1; i < this.value.length; i++) { + code *= 31; + code += this.value[i]; + } + + return code; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof HexBinaryAttribute)) { + return false; + } + HexBinaryAttribute other = (HexBinaryAttribute)o; + + return Arrays.equals(this.value, other.value); + } + + /** + * Return the int value of a hex character. Return -1 if the + * character is not a valid hex character. + */ + private static int hexToBinNibble(char c) { + int result = -1; + + if ((c >= '0') && (c <= '9')) { + result = (c - '0'); + } else { + if ((c >= 'a') && (c <= 'f')) { + result = (c - 'a') + 10; + } else { + if ((c >= 'A') && (c <= 'F')) { + result = (c - 'A') + 10; + } + // else pick up the -1 value set above + } + } + return result; + } + + /** + * Parse a hex string, returning a new byte array containing the + * value. Return null in case of a parsing error. + * + * @param hex the hex string + * @return a new byte array containing the value (or null) + */ + private static byte [] hexToBin(String hex) { + int len = hex.length(); + // Must have an even number of hex digits + if (len % 2 != 0) { + return null; + } + int byteCount = len / 2; + byte [] bytes = new byte [byteCount]; + + int charIndex = 0; + for (int byteIndex = 0; byteIndex < byteCount; byteIndex++) { + int hiNibble = hexToBinNibble(hex.charAt(charIndex++)); + int loNibble = hexToBinNibble(hex.charAt(charIndex++)); + if ((hiNibble < 0) || (loNibble < 0)) { + return null; + } + bytes[byteIndex] = (byte) (hiNibble * 16 + loNibble); + } + return bytes; + } + + /** + * Return the hex character for a particular nibble (half a byte). + * + * @param nibble a value 0-15 + * @return hex character for that nibble (using A-F for 10-15) + */ + private static char binToHexNibble(int nibble) { + char result = (char) 0; + + if (nibble < 10) { + result = (char) (nibble + '0'); + } else { + result = (char) ((nibble - 10) + 'A'); + } + return result; + } + + /** + * Return a straight hexadecimal conversion of a byte array. + * This is a String containing only hex digits. + * + * @param bytes the byte array + * @return the hex version + */ + private static String binToHex(byte [] bytes) { + int byteLength = bytes.length; + char [] chars = new char [byteLength * 2]; + int charIndex = 0; + + for (int byteIndex = 0; byteIndex < byteLength; byteIndex++) { + byte b = bytes[byteIndex]; + chars[charIndex++] = binToHexNibble((b >> 4) & 0xf); + chars[charIndex++] = binToHexNibble(b & 0xf); + } + + return new String(chars); + } + + /** + * Returns a String representation. + * + * @return the String representation + */ + public String toString() { + if (this.strValue == null) { + this.strValue = binToHex(this.value); + } + + return "HexBinaryAttribute: [" + Constants.nl + + this.strValue + "]" + Constants.nl; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + if (this.strValue == null) { + this.strValue = binToHex(this.value); + } + + return this.strValue; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPAddressAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPAddressAttribute.java new file mode 100644 index 0000000..cb44cf2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPAddressAttribute.java @@ -0,0 +1,269 @@ + +/* + * @(#)IPAddressAttribute.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.ParsingException; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.net.URI; + +import org.w3c.dom.Node; + + +/** + * Represents the IPAddress datatype introduced in XACML 2.0. All objects of + * this class are immutable and all methods of the class are thread-safe. + *

    + * To create an instance of an ipAddress from an encoded String or a DOM + * Node you should use the getInstance methods provided by + * this class. To construct an ipAddress instance directly, you must use + * the constructors provided by IPv4AddressAttribute and + * IPv6AddressAttribute. These will both create an attribute + * of XACML type ipAddress, but will handle the differences in these + * two representations correctly. + * + * @since 2.0 + * @author Seth Proctor + */ +public abstract class IPAddressAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.IPADDRESS; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = new URI(identifier); + } catch (Exception e) { + earlyException = new IllegalArgumentException(); + earlyException.initCause(e); + } + } + + // the required address + private InetAddress address; + + // the optional mask + private InetAddress mask; + + // this is the optional port-range + private PortRange range; + + /** + * Creates the new IPAddressAttribute with all the optional + * components. + * + * @param address a non-null InetAddress + * @param mask an InetAddress or null if there is no mask + * @param range a non-null PortRange + */ + protected IPAddressAttribute(InetAddress address, InetAddress mask, + PortRange range) { + super(identifierURI); + + // shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + this.address = address; + this.mask = mask; + this.range = range; + } + + /** + * Returns a new IPAddressAttribute that represents + * the name at a particular DOM node. + * + * @param root the Node that contains the desired value + * + * @return a new IPAddressAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParsingException if any of the address components is invalid + */ + public static IPAddressAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a IPAddressAttribute"); + } + + /** + * Returns a new IPAddressAttribute that represents + * the name indicated by the String provided. + * + * @param value a string representing the address + * + * @return a new IPAddressAttribute + * + * @throws ParsingException if any of the address components is invalid + */ + public static IPAddressAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "IPAddressAttribute from null input"); + } + try { + // an IPv6 address starts with a '[' + if (value.indexOf('[') == 0) { + return IPv6AddressAttribute.getV6Instance(value); + } + return IPv4AddressAttribute.getV4Instance(value); + } catch (UnknownHostException uhe) { + throw new ParsingException("Failed to parse an IPAddress", uhe); + } + } + + /** + * Returns the address represented by this object. + * + * @return the address + */ + public InetAddress getAddress() { + return this.address; + } + + /** + * Returns the mask represented by this object, or null if there is no + * mask. + * + * @return the mask or null + */ + public InetAddress getMask() { + return this.mask; + } + + /** + * Returns the port range represented by this object which will be + * unbound if no range was specified. + * + * @return the range + */ + public PortRange getRange() { + return this.range; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof IPAddressAttribute)) { + return false; + } + + IPAddressAttribute other = (IPAddressAttribute)o; + + if (! this.address.equals(other.address)) { + return false; + } + + if (this.mask != null) { + if (other.mask == null) { + return false; + } + + if (! this.mask.equals(other.mask)) { + return false; + } + } else { + if (other.mask != null) { + return false; + } + } + + if (! this.range.equals(other.range)) { + return false; + } + + return true; + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. + * + * @return the object's hashcode value + */ + public int hashCode() { + return encode().hashCode(); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + return "IPAddressAttribute: \"" + encode() + "\""; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv4AddressAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv4AddressAttribute.java new file mode 100644 index 0000000..3cecaf9 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv4AddressAttribute.java @@ -0,0 +1,179 @@ + +/* + * @(#)IPv4AddressAttribute.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import com.sun.xacml.ParsingException; + + +/** + * Subclass of IPAddressAttribute that handles the specifics + * of IPv4. In general, you shouldn't need to interact with this class + * except to create an instance directly. + * + * @since 2.0 + * @author Seth Proctor + */ +public class IPv4AddressAttribute extends IPAddressAttribute +{ + + /** + * Creates the new IPv4AddressAttribute with just the required + * address component. + * + * @param address a non-null InetAddress + */ + public IPv4AddressAttribute(InetAddress address) { + this(address, null, new PortRange()); + } + + /** + * Creates the new IPv4AddressAttribute with the optional + * address mask. + * + * @param address a non-null InetAddress + * @param mask an InetAddress or null if there is no mask + */ + public IPv4AddressAttribute(InetAddress address, InetAddress mask) { + this(address, mask, new PortRange()); + } + + /** + * Creates the new IPv4AddressAttribute with the optional + * port range. + * + * @param address a non-null InetAddress + * @param range a non-null PortRange + */ + public IPv4AddressAttribute(InetAddress address, PortRange range) { + this(address, null, range); + } + + /** + * Creates the new IPv4AddressAttribute with all the optional + * components. + * + * @param address a non-null InetAddress + * @param mask an InetAddress or null if there is no mask + * @param range a non-null PortRange + */ + public IPv4AddressAttribute(InetAddress address, InetAddress mask, + PortRange range) { + super(address, mask, range); + } + + /** + * Returns a new IPv4AddressAttribute that represents + * the name indicated by the String provided. This is a + * protected method because you should never call it directly. + * Instead, you should call getInstance on + * IPAddressAttribute which provides versions that + * take both a String and a Node and + * will determine the protocol version correctly. + * + * @param value a string representing the address + * + * @return a new IPAddressAttribute + * + * @throws UnknownHostException if the address components is invalid + * @throws ParsingException + */ + protected static IPAddressAttribute getV4Instance(String value) + throws UnknownHostException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "IPv4AddressAttribute from null input"); + } + InetAddress address = null; + InetAddress mask = null; + PortRange range = null; + + // start out by seeing where the delimiters are + int maskPos = value.indexOf("/"); + int rangePos = value.indexOf(":"); + + // now check to see which components we have + if (maskPos == rangePos) { + // the sting is just an address + address = InetAddress.getByName(value); + } else if (maskPos != -1) { + // there is also a mask (and maybe a range) + address = InetAddress.getByName(value.substring(0, maskPos)); + if (rangePos != -1) { + // there's a range too, so get it and the mask + mask = + InetAddress.getByName(value.substring(maskPos + 1, + rangePos)); + range = + PortRange.getInstance(value.substring(rangePos + 1, + value.length())); + } else { + // there's no range, so just get the mask + mask = InetAddress.getByName(value.substring(maskPos + 1, + value.length())); + } + } else { + // there is a range, but no mask + address = InetAddress.getByName(value.substring(0, rangePos)); + range = PortRange.getInstance(value.substring(rangePos + 1, + value.length())); + } + + // if the range is null, then create it as unbound + range = new PortRange(); + + return new IPv4AddressAttribute(address, mask, range); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + String str = getAddress().getHostAddress(); + + if (getMask() != null) { + str += getMask().getHostAddress(); + } + if (! getRange().isUnbound()) { + str += ":" + getRange().encode(); + } + return str; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv6AddressAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv6AddressAttribute.java new file mode 100644 index 0000000..0d54f8a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IPv6AddressAttribute.java @@ -0,0 +1,170 @@ + +/* + * @(#)IPv6AddressAttribute.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import com.sun.xacml.ParsingException; + + +/** + * Subclass of IPAddressAttribute that handles the specifics + * of IPv6. In general, you shouldn't need to interact with this class + * except to create an instance directly. + * + * @since 2.0 + * @author Seth Proctor + */ +public class IPv6AddressAttribute extends IPAddressAttribute +{ + + /** + * Creates the new IPv6AddressAttribute with just the required + * address component. + * + * @param address a non-null InetAddress + */ + public IPv6AddressAttribute(InetAddress address) { + this(address, null, new PortRange()); + } + + /** + * Creates the new IPv6AddressAttribute with the optional + * address mask. + * + * @param address a non-null InetAddress + * @param mask an InetAddress or null if there is no mask + */ + public IPv6AddressAttribute(InetAddress address, InetAddress mask) { + this(address, mask, new PortRange()); + } + + /** + * Creates the new IPv6AddressAttribute with the optional + * port range. + * + * @param address a non-null InetAddress + * @param range a non-null PortRange + */ + public IPv6AddressAttribute(InetAddress address, PortRange range) { + this(address, null, range); + } + + /** + * Creates the new IPv6AddressAttribute with all the optional + * components. + * + * @param address a non-null InetAddress + * @param mask an InetAddress or null if there is no mask + * @param range a non-null PortRange + */ + public IPv6AddressAttribute(InetAddress address, InetAddress mask, + PortRange range) { + super(address, mask, range); + } + + /** + * Returns a new IPv6AddressAttribute that represents + * the name indicated by the String provided. This is a + * protected method because you should never call it directly. + * Instead, you should call getInstance on + * IPAddressAttribute which provides versions that + * take both a String and a Node and + * will determine the protocol version correctly. + * + * @param value a string representing the address + * + * @return a new IPAddressAttribute + * + * @throws UnknownHostException if the address components is invalid + * @throws ParsingException + */ + protected static IPAddressAttribute getV6Instance(String value) + throws UnknownHostException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "IPv6AddressAttribute from null input"); + } + InetAddress address = null; + InetAddress mask = null; + PortRange range = null; + int len = value.length(); + + // get the required address component + int endIndex = value.indexOf(']'); + address = InetAddress.getByName(value.substring(1, endIndex)); + + // see if there's anything left in the string + if (endIndex != (len - 1)) { + // if there's a mask, it's also an IPv6 address + if (value.charAt(endIndex + 1) == '/') { + int startIndex = endIndex + 3; + endIndex = value.indexOf(']', startIndex); + mask = InetAddress.getByName(value.substring(startIndex, + endIndex)); + } + + // finally, see if there's a port range, if we're not finished + if ((endIndex != (len - 1)) && (value.charAt(endIndex + 1) == ':')) { + range = PortRange.getInstance(value.substring(endIndex + 2, + len)); + } + } + + // if the range is null, then create it as unbound + range = new PortRange(); + + return new IPv6AddressAttribute(address, mask, range); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + String str = "[" + getAddress().getHostAddress() + "]"; + + if (getMask() != null) { + str += "/[" + getMask().getHostAddress() + "]"; + } + if (! getRange().isUnbound()) { + str += ":" + getRange().encode(); + } + return str; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IntegerAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IntegerAttribute.java new file mode 100644 index 0000000..ac0f890 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/IntegerAttribute.java @@ -0,0 +1,202 @@ + +/* + * @(#)IntegerAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an xs:integer value. This class supports parsing + * xs:integer values. All objects of this class are immutable and + * all methods of the class are thread-safe. + * + * @since 1.0 + * @author Marco Barreno + * @author Steve Hanna + */ +public class IntegerAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.INTEGER; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual long value that this object represents. + */ + private long value; + + /** + * Creates a new IntegerAttribute that represents + * the long value supplied. + * + * @param value the long value to be represented + */ + public IntegerAttribute(long value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + this.value = value; + } + + /** + * Returns a new IntegerAttribute that represents + * the xs:integer at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new IntegerAttribute representing the + * appropriate value (null if there is a parsing error) + * @throws NumberFormatException if the string form isn't a number + * @throws ParsingException + */ + public static IntegerAttribute getInstance(Node root) + throws NumberFormatException, ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "an IntegerAttribute"); + } + + /** + * Returns a new IntegerAttribute that represents + * the xs:integer value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new IntegerAttribute representing the + * appropriate value (null if there is a parsing error) + * @throws NumberFormatException if the string isn't a number + * @throws ParsingException + */ + public static IntegerAttribute getInstance(String value) + throws NumberFormatException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "IntegerAttribute from null input"); + } + // Leading '+' is allowed per XML schema and not + // by Long.parseLong. Strip it, if present. + if ((value.length() >= 1) && (value.charAt(0) == '+')) { + value = value.substring(1); + } + return new IntegerAttribute(Long.parseLong(value)); + } + + /** + * Returns the long value represented by this object. + * + * @return the long value + */ + public long getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof IntegerAttribute)) { + return false; + } + IntegerAttribute other = (IntegerAttribute)o; + + return (this.value == other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return (int)this.value; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + return String.valueOf(this.value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/PortRange.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/PortRange.java new file mode 100644 index 0000000..7690afb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/PortRange.java @@ -0,0 +1,264 @@ + +/* + * @(#)PortRange.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.ParsingException; + + +/** + * This class represents a port range as specified in the XACML 2.0 description + * of dnsName and ipAddress. The range may have + * upper and lower bounds, be specified by a single port number, or may be + * unbound. + * + * @since 2.0 + * @author Seth Proctor + */ +public class PortRange +{ + + /** + * Constant used to specify that the range is unbound on one side. + */ + public static final int UNBOUND = -1; + + // the port bound values + private int lowerBound; + private int upperBound; + + /** + * Default constructor used to represent an unbound range. This is + * typically used when an address has no port information. + */ + public PortRange() { + this(UNBOUND, UNBOUND); + } + + /** + * Creates a PortRange that represents a single port value + * instead of a range of values. + * + * @param singlePort the single port number + */ + public PortRange(int singlePort) { + this(singlePort, singlePort); + } + + /** + * Creates a PortRange with upper and lower bounds. Either + * of the parameters may have the value UNBOUND meaning + * that there is no bound at the respective end. + * + * @param lowerBound the lower-bound port number or UNBOUND + * @param upperBound the upper-bound port number or UNBOUND + */ + public PortRange(int lowerBound, int upperBound) { + this.lowerBound = lowerBound; + this.upperBound = upperBound; + } + + /** + * Creates an instance of PortRange based on the given value. + * + * @param value a String representing the range + * + * @return a new PortRange + * + * @throws NumberFormatException if a port value isn't an integer + */ + public static PortRange getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create PortRange" + + " from null input"); + } + int lowerBound = UNBOUND; + int upperBound = UNBOUND; + + // first off, make sure there's actually content here + if ((value.length() == 0) || (value.equals("-"))) { + return new PortRange(); + } + + // there's content, so figure where the '-' is, if at all + int dashPos = value.indexOf('-'); + + if (dashPos == -1) { + // there's no dash, so it's just a single number + lowerBound = upperBound = Integer.parseInt(value); + } else if (dashPos == 0) { + // it starts with a dash, so it's just upper-range bound + upperBound = Integer.parseInt(value.substring(1)); + } else { + // it's a number followed by a dash, so get the lower-bound... + lowerBound = Integer.parseInt(value.substring(0, dashPos)); + int len = value.length(); + + // ... and see if there is a second port number + if (dashPos != (len - 1)) { + // the dash wasn't at the end, so there's an upper-bound + upperBound = Integer.parseInt(value.substring(dashPos + 1, + len)); + } + } + + return new PortRange(lowerBound, upperBound); + } + + /** + * Returns the lower-bound port value. If the range is not lower-bound, + * then this returns UNBOUND. If the range is actually a + * single port number, then this returns the same value as + * getUpperBound. + * + * @return the upper-bound + */ + public int getLowerBound() { + return this.lowerBound; + } + + /** + * Returns the upper-bound port value. If the range is not upper-bound, + * then this returns UNBOUND. If the range is actually a + * single port number, then this returns the same value as + * getLowerBound. + * + * @return the upper-bound + */ + public int getUpperBound() { + return this.upperBound; + } + + /** + * Returns whether the range is bounded by a lower port number. + * + * @return true if lower-bounded, false otherwise + */ + public boolean isLowerBounded() { + return (this.lowerBound != -1); + } + + /** + * Returns whether the range is bounded by an upper port number. + * + * @return true if upper-bounded, false otherwise + */ + public boolean isUpperBounded() { + return (this.upperBound != -1); + } + + /** + * Returns whether the range is actually a single port number. + * + * @return true if the range is a single port number, false otherwise + */ + public boolean isSinglePort() { + return ((this.lowerBound == this.upperBound) + && (this.lowerBound != UNBOUND)); + } + + /** + * Returns whether the range is unbound, which means that it specifies + * no port number or range. This is typically used with addresses that + * include no port information. + * + * @return true if the range is unbound, false otherwise + */ + public boolean isUnbound() { + return ((this.lowerBound == UNBOUND) && (this.upperBound == UNBOUND)); + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof PortRange)) { + return false; + } + + PortRange other = (PortRange)o; + + if (this.lowerBound != other.lowerBound) { + return false; + } + + if (this.upperBound != other.upperBound) { + return false; + } + + return true; + } + + /** + * Override the hashCode method. + * + * @return The hashCode. + */ + public int hashCode() { + return this.upperBound + this.lowerBound; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + if (isUnbound()) { + return ""; + } + + if (isSinglePort()) { + return String.valueOf(this.lowerBound); + } + + if (! isLowerBounded()) { + return "-" + String.valueOf(this.upperBound); + } + + if (! isUpperBounded()) { + return String.valueOf(this.lowerBound) + "-"; + } + + return String.valueOf(this.lowerBound) + "-" + + String.valueOf(this.upperBound); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/RFC822NameAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/RFC822NameAttribute.java new file mode 100644 index 0000000..d1ef4bf --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/RFC822NameAttribute.java @@ -0,0 +1,199 @@ + +/* + * @(#)RFC822NameAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an rfc822Name (ie, an email address). + * + * @since 1.0 + * @author Seth Proctor + */ +public class RFC822NameAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.RFC822NAME; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + // the actual value being stored + private String value; + + /** + * Creates a new RFC822NameAttribute that represents the + * value supplied. + * + * @param value the email address to be represented + */ + public RFC822NameAttribute(String value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + if (value == null) { + throw new IllegalArgumentException("Can't create RFC822Name from" + + "null input"); + } + // check that the string is an address, ie, that it has one and only + // one '@' character in it + String [] parts = value.split("@"); + if (parts.length != 2) { + // this is malformed input + throw new IllegalArgumentException("invalid RFC822Name: " + value); + } + + // cannonicalize the name + this.value = parts[0] + "@" + parts[1].toLowerCase(); + } + + /** + * Returns a new RFC822NameAttribute that represents + * the email address at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new RFC822NameAttribute representing the + * appropriate value + * @throws ParsingException + */ + public static RFC822NameAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a RFC822NameAttribute"); + } + + /** + * Returns a new RFC822NameAttribute that represents + * the email address value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new RFC822NameAttribute representing the + * appropriate value + */ + public static RFC822NameAttribute getInstance(String value) { + return new RFC822NameAttribute(value); + } + + /** + * Returns the name value represented by this object + * + * @return the name + */ + public String getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof RFC822NameAttribute)) { + return false; + } + RFC822NameAttribute other = (RFC822NameAttribute)o; + + return this.value.equals(other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return this.value.hashCode(); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + return this.value; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StandardAttributeFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StandardAttributeFactory.java new file mode 100644 index 0000000..c8f8220 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StandardAttributeFactory.java @@ -0,0 +1,265 @@ + +/* + * @(#)StandardAttributeFactory + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.UnknownIdentifierException; + +import com.sun.xacml.attr.proxy.AnyURIAttributeProxy; +import com.sun.xacml.attr.proxy.Base64BinaryAttributeProxy; +import com.sun.xacml.attr.proxy.BooleanAttributeProxy; +import com.sun.xacml.attr.proxy.DateAttributeProxy; +import com.sun.xacml.attr.proxy.DateTimeAttributeProxy; +import com.sun.xacml.attr.proxy.DayTimeDurationAttributeProxy; +import com.sun.xacml.attr.proxy.DNSNameAttributeProxy; +import com.sun.xacml.attr.proxy.DoubleAttributeProxy; +import com.sun.xacml.attr.proxy.HexBinaryAttributeProxy; +import com.sun.xacml.attr.proxy.IntegerAttributeProxy; +import com.sun.xacml.attr.proxy.IPAddressAttributeProxy; +import com.sun.xacml.attr.proxy.RFC822NameAttributeProxy; +import com.sun.xacml.attr.proxy.StringAttributeProxy; +import com.sun.xacml.attr.proxy.TimeAttributeProxy; +import com.sun.xacml.attr.proxy.YearMonthDurationAttributeProxy; +import com.sun.xacml.attr.proxy.X500NameAttributeProxy; + +//import foo.xacml.attr.proxy.EmergencyLevelAttributeProxy; +//import foo.xacml.attr.proxy.EvaluationIdAttributeProxy; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; + + + +/** + * This factory supports the standard set of datatypes specified in XACML +! * 1.x and 2.0. It is the default factory used by the system, and imposes + * a singleton pattern insuring that there is only ever one instance of + * this class. + *

    + * Note that because this supports only the standard datatypes, this + * factory does not allow the addition of any other datatypes. If you call + * addDatatype on an instance of this class, an exception + * will be thrown. If you need a standard factory that is modifiable, you + * should create a new BaseAttributeFactory (or some other + * AttributeFactory) and configure it with the standard + * datatypes using addStandardDatatypes (or, in the case of + * BaseAttributeFactory, by providing the datatypes in the + * constructor). + * + * @since 1.2 + * @author Seth Proctor + */ +public class StandardAttributeFactory extends BaseAttributeFactory +{ + + // the one instance of this factory + private static StandardAttributeFactory factoryInstance = null; + + // the datatypes supported by this factory + private static HashMap supportedDatatypes = null; + + // the supported identifiers for each version of XACML + private static Set supportedV1Identifiers; + private static Set supportedV2Identifiers; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(StandardAttributeFactory.class.getName()); + + /** + * Private constructor that sets up proxies for all of the standard + * datatypes. + */ + private StandardAttributeFactory() { + super(supportedDatatypes); + } + + /** + * Private initializer for the supported datatypes. This isn't called + * until something needs these values, and is only called once. + */ + private static void initDatatypes() { + logger.debug("Initializing standard datatypes"); + + supportedDatatypes = new HashMap(); + + // the 1.x datatypes + supportedDatatypes.put(BooleanAttribute.identifier, + new BooleanAttributeProxy()); + supportedDatatypes.put(StringAttribute.identifier, + new StringAttributeProxy()); + supportedDatatypes.put(DateAttribute.identifier, + new DateAttributeProxy()); + supportedDatatypes.put(TimeAttribute.identifier, + new TimeAttributeProxy()); + supportedDatatypes.put(DateTimeAttribute.identifier, + new DateTimeAttributeProxy()); + supportedDatatypes.put(DayTimeDurationAttribute.identifier, + new DayTimeDurationAttributeProxy()); + supportedDatatypes.put(YearMonthDurationAttribute.identifier, + new YearMonthDurationAttributeProxy()); + supportedDatatypes.put(DoubleAttribute.identifier, + new DoubleAttributeProxy()); + supportedDatatypes.put(IntegerAttribute.identifier, + new IntegerAttributeProxy()); + supportedDatatypes.put(AnyURIAttribute.identifier, + new AnyURIAttributeProxy()); + supportedDatatypes.put(HexBinaryAttribute.identifier, + new HexBinaryAttributeProxy()); + supportedDatatypes.put(Base64BinaryAttribute.identifier, + new Base64BinaryAttributeProxy()); + supportedDatatypes.put(X500NameAttribute.identifier, + new X500NameAttributeProxy()); + supportedDatatypes.put(RFC822NameAttribute.identifier, + new RFC822NameAttributeProxy()); + /* + supportedDatatypes.put(EmergencyLevelAttribute.identifier, + new EmergencyLevelAttributeProxy()); + supportedDatatypes.put(EvaluationIdAttribute.identifier, + new EvaluationIdAttributeProxy()); + */ + + supportedV1Identifiers = + Collections.unmodifiableSet(supportedDatatypes.keySet()); + + // the 2.0 datatypes + supportedDatatypes.put(DNSNameAttribute.identifier, + new DNSNameAttributeProxy()); + supportedDatatypes.put(IPAddressAttribute.identifier, + new IPAddressAttributeProxy()); + + supportedV2Identifiers = + Collections.unmodifiableSet(supportedDatatypes.keySet()); + } + + /** + * Returns an instance of this factory. This method enforces a singleton + * model, meaning that this always returns the same instance, creating + * the factory if it hasn't been requested before. This is the default + * model used by the AttributeFactory, ensuring quick + * access to this factory. + * + * @return the factory instance + */ + public static synchronized StandardAttributeFactory getFactory() { + if (factoryInstance == null) { + initDatatypes(); + factoryInstance = new StandardAttributeFactory(); + } + return factoryInstance; + } + + /** + * A convenience method that returns a new instance of an + * that supports all of the standard + * datatypes. The new factory allows adding support for new datatypes. + * This method should only be used when you need a new, mutable instance + * (eg, when you want to create a new factory that extends the set of + * supported datatypes). In general, you should use + * getFactory which is more efficient and enforces a + * singleton pattern. + * + * @return a new factory supporting the standard datatypes + */ + public static AttributeFactory getNewFactory() { + // first we make sure that everything has been initialized... + getFactory(); + + // ...then we create the new instance + return new BaseAttributeFactory(supportedDatatypes); + } + + /** + * Returns the identifiers supported for the given version of XACML. + * Because this factory supports identifiers from all versions of the + * XACML specifications, this method is useful for getting a list of + * which specific identifiers are supported by a given version of XACML. + * + * @param xacmlVersion a standard XACML identifier string, as provided + * in PolicyMetaData + * + * @return a Set of identifiers + * + * @throws UnknownIdentifierException if the version string is unknown + */ + public static Set getStandardDatatypes(String xacmlVersion) + throws UnknownIdentifierException + { + if (xacmlVersion.equals(Constants.XACML_1_0_IDENTIFIER)) { + return supportedV1Identifiers; + } else if (xacmlVersion.equals(Constants.XACML_2_0_IDENTIFIER)) { + return supportedV2Identifiers; + } else if (xacmlVersion.equals(Constants.XACML_3_0_IDENTIFIER)) { + return supportedV2Identifiers; + } + + throw new UnknownIdentifierException("Unknown XACML version: " + + xacmlVersion); + } + + /** + * Returns all supported datatypes. + * + * + * @return a Map of attribute proxys keyed by their + * identifier. + */ + public static Map getStandardDatatypes() { + StandardAttributeFactory.initDatatypes(); + return new HashMap(StandardAttributeFactory.supportedDatatypes); + + } + + /** + * Throws an UnsupportedOperationException since you are not + * allowed to modify what a standard factory supports. + * + * @param id the name of the attribute type + * @param proxy the proxy used to create new attributes of the given type + * + * @throws UnsupportedOperationException always + */ + public void addDatatype(String id, AttributeProxy proxy) { + throw new UnsupportedOperationException("a standard factory cannot " + + "support new datatypes"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StringAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StringAttribute.java new file mode 100644 index 0000000..bdf36f9 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/StringAttribute.java @@ -0,0 +1,228 @@ + +/* + * @(#)StringAttribute.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an xs:string value. This class supports parsing + * xs:string values. All objects of this class are immutable and + * all methods of the class are thread-safe. + *

    + * Note that there was some confusion in the XACML specification + * about whether this datatype should be able to handle XML elements (ie, + * whether <AttributeValue DataType="...string"><foo/> + * </AttributeValue> is valid). This has been clarified to provide + * the correct requirement that a string may not contain mixed content (ie, + * the example provided here is invalid). If you need to specify something + * like this with the string datatype, then you must escape the + * < and > characters. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + * @author Steve Hanna + */ +public class StringAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.STRING; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * The actual String value that this object represents. + */ + private String value; + + /** + * Creates a new StringAttribute that represents + * the String value supplied. + * + * @param value the String value to be represented + */ + public StringAttribute(String value) { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + if (value == null) { + this.value = ""; + } else { + this.value = value; + } + } + + /** + * Returns a new StringAttribute that represents + * the xs:string at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new StringAttribute representing the + * appropriate value (null if there is a parsing error) + * @throws ParsingException + */ + public static StringAttribute getInstance(Node root) + throws ParsingException { + Node node = root.getFirstChild(); + + // Strings are allowed to have an empty AttributeValue element and are + // just treated as empty strings...we have to handle this case + if (node == null) { + return new StringAttribute(""); + } + // get the type of the node + short type = node.getNodeType(); + + // now see if we have (effectively) a simple string value + if ((type == Node.TEXT_NODE) || (type == Node.CDATA_SECTION_NODE) || + (type == Node.COMMENT_NODE)) { + return getInstance(node.getNodeValue()); + } + + // there is some confusion in the specifications about what should + // happen at this point, but the strict reading of the XMLSchema + // specification suggests that this should be an error + throw new ParsingException("Can't create a StringAttribute from " + + "given xml node type: " + root.getNodeType()); + } + + /** + * Returns a new StringAttribute that represents + * the xs:string value indicated by the String provided. + * + * @param value a string representing the desired value + * @return a new StringAttribute representing the + * appropriate value + */ + public static StringAttribute getInstance(String value) { + return new StringAttribute(value); + } + + /** + * Returns the String value represented by this object. + * + * @return the String value + */ + public String getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof StringAttribute)) { + return false; + } + StringAttribute other = (StringAttribute)o; + + return this.value.equals(other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return this.value.hashCode(); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + return "StringAttribute: \"" + this.value + "\""; + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + return this.value; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TimeAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TimeAttribute.java new file mode 100644 index 0000000..80eb3d4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TimeAttribute.java @@ -0,0 +1,522 @@ + +/* + * @(#)TimeAttribute.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; +import com.sun.xacml.ProcessingException; + +import java.net.URI; + +import java.text.ParseException; + +import java.util.Date; + +import org.w3c.dom.Node; + + +/** + * Representation of an xs:time value. This class supports parsing + * xs:time values. All objects of this class are immutable and + * thread-safe. The Date objects returned are not, but + * these objects are cloned before being returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class TimeAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.TIME; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + *

    + * This object is used for synchronization whenever we need + * protection across this whole class. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Time zone value that indicates that the time zone was not + * specified. + */ + public static final int TZ_UNSPECIFIED = -1000000; + + /** + * The time that this object represents in second resolution, in + * milliseconds GMT, with zero being midnight. If no time zone was + * specified, the local time zone is used to convert to milliseconds + * relative to GMT. + */ + private long timeGMT; + + /** + * The number of nanoseconds beyond the time given by the timeGMT + * field. The XML Query document says that fractional seconds + * must be supported down to at least 100 nanosecond resolution. + * The Date class only supports milliseconds, so we include here + * support for nanosecond resolution. + */ + private int nanoseconds; + + // NOTE: now that we're not using a Date object, the above two variables + // could be condensed, and the interface could be changed so we don't + // need to worry about tracking the time values separately + + /** + * The time zone specified for this object (or TZ_UNSPECIFIED if + * unspecified). The offset to GMT, in minutes. + */ + private int timeZone; + + /** + * The time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * The offset to GMT, in minutes. + */ + private int defaultedTimeZone; + + /** + * Cached encoded value (null if not cached yet). + */ + private String encodedValue = null; + + /** + * Creates a new TimeAttribute that represents + * the current time in the current time zone. + */ + public TimeAttribute() { + this(new Date()); + } + + /** + * Creates a new TimeAttribute that represents + * the given time but uses the default timezone and offset values. + * + * @param time a Date object representing the + * specified time down to second resolution. This + * date should have a date of 01/01/1970. If it does + * not, such a date will be forced. If this object + * has non-zero milliseconds, they are combined + * with the nanoseconds parameter. + */ + public TimeAttribute(Date time) { + super(identifierURI); + + int currOffset = DateTimeAttribute.getDefaultTZOffset(time); + init(time, 0, currOffset, currOffset); + } + + /** + * Creates a new TimeAttribute that represents + * the time supplied. + * + * @param time a Date object representing the + * specified time down to second resolution. This + * date should have a date of 01/01/1970. If it does + * not, such a date will be forced. If this object + * has non-zero milliseconds, they are combined + * with the nanoseconds parameter. + * @param nanoseconds the number of nanoseconds beyond the + * Date specified in the date parameter + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object, which must be specified. + * The offset to GMT, in minutes. + */ + public TimeAttribute(Date time, int nanoseconds, int timeZone, + int defaultedTimeZone) { + super(identifierURI); + + // if the timezone is unspecified, it's illegal for the defaulted + // timezone to also be unspecified + if ((timeZone == TZ_UNSPECIFIED) && + (defaultedTimeZone == TZ_UNSPECIFIED)) { + throw new ProcessingException("default timezone must be specified" + + "when a timezone is provided"); + } + + init(time, nanoseconds, timeZone, defaultedTimeZone); + } + + /** + * Initialization code shared by constructors. + * + * @param date a Date object representing the + * specified time down to second resolution. This + * date should have a date of 01/01/1970. If it does + * not, such a date will be forced. If this object + * has non-zero milliseconds, they are combined + * with the nanoseconds parameter. + * @param nanoseconds the number of nanoseconds beyond the + * Date specified in the date parameter + * @param timeZone the time zone specified for this object + * (or TZ_UNSPECIFIED if unspecified). The + * offset to GMT, in minutes. + * @param defaultedTimeZone the time zone actually used for this + * object (if it was originally unspecified, + * the default time zone used). + * The offset to GMT, in minutes. + */ + private void init(Date date, int nanoseconds, int timeZone, + int defaultedTimeZone) { + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + // get a temporary copy of the date + Date tmpDate = (Date)(date.clone()); + + // Combine the nanoseconds so they are between 0 and 999,999,999 + this.nanoseconds = + DateTimeAttribute.combineNanos(tmpDate, nanoseconds); + + // now that the date has been (potentially) updated, store the time + this.timeGMT = tmpDate.getTime(); + + // keep track of the timezone values + this.timeZone = timeZone; + this.defaultedTimeZone = defaultedTimeZone; + + // Check that the date is normalized to 1/1/70 + if ((this.timeGMT >= DateAttribute.MILLIS_PER_DAY) + || (this.timeGMT < 0)) { + this.timeGMT = this.timeGMT % DateAttribute.MILLIS_PER_DAY; + + // if we had a negative value then we need to shift by a day + if (this.timeGMT < 0) { + this.timeGMT += DateAttribute.MILLIS_PER_DAY; + } + } + } + + /** + * Returns a new TimeAttribute that represents + * the xs:time at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new TimeAttribute representing the + * appropriate value (null if there is a parsing error) + * + * @throws ParsingException + * @throws NumberFormatException + * @throws ParseException + */ + public static TimeAttribute getInstance(Node root) + throws ParsingException, NumberFormatException, ParseException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new IllegalArgumentException("Error while parsing" + + "a TimeAttribute"); + } + + /** + * Returns a new TimeAttribute that represents + * the xs:time value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new TimeAttribute representing the + * desired value (null if there is a parsing error) + * + * @throws ParsingException if any problems occurred while parsing + * @throws NumberFormatException + * @throws ParseException + */ + public static TimeAttribute getInstance(String value) + throws ParsingException, NumberFormatException, ParseException { + if (value == null) { + throw new ParsingException("Can't create a " + + "TimeAttribute from empty input"); + } + // Prepend date string for Jan 1 1970 and use the + // DateTimeAttribute parsing code. + + value = "1970-01-01T" + value; + + DateTimeAttribute dateTime = DateTimeAttribute.getInstance(value); + + // if there was no explicit TZ provided, then we want to make sure + // the that the defaulting is done correctly, especially since 1/1/70 + // is always out of daylight savings time + + Date dateValue = dateTime.getValue(); + int defaultedTimeZone = dateTime.getDefaultedTimeZone(); + if (dateTime.getTimeZone() == TZ_UNSPECIFIED) { + int newDefTimeZone = + DateTimeAttribute.getDefaultTZOffset(new Date()); + // Multiplication with 1L to avoid overflows in the + // integer multiplication, since it's converted to long anyway + dateValue = new Date(dateValue.getTime() - + 1L *(newDefTimeZone - defaultedTimeZone) * + DateAttribute.MILLIS_PER_MINUTE); + defaultedTimeZone = newDefTimeZone; + } + + return new TimeAttribute(dateValue, + dateTime.getNanoseconds(), + dateTime.getTimeZone(), + defaultedTimeZone); + } + + /** + * Gets the time represented by this object. The return + * value is a Date object representing the + * specified time down to second resolution with a date + * of January 1, 1970. Subsecond values are handled by the + * {@link #getNanoseconds getNanoseconds} method. + * + * @return a Date object representing the + * time represented by this object + */ + public Date getValue() { + return new Date(this.timeGMT); + } + + /** + * Gets the number of milliseconds since midnight GMT that this attribute + * value represents. This is the same time returned by + * getValue, and likewise the milliseconds are provided + * with second resolution. + * + * @return milliseconds since midnight GMT + */ + public long getMilliseconds() { + return this.timeGMT; + } + + /** + * Gets the nanoseconds of this object. + * + * @return the number of nanoseconds + */ + public int getNanoseconds() { + return this.nanoseconds; + } + + /** + * Gets the time zone of this object (or TZ_UNSPECIFIED if + * unspecified). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getTimeZone() { + return this.timeZone; + } + + /** + * Gets the time zone actually used for this object (if it was + * originally unspecified, the default time zone used). + * + * @return the offset to GMT in minutes (positive or negative) + */ + public int getDefaultedTimeZone() { + return this.defaultedTimeZone; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof TimeAttribute)) { + return false; + } + TimeAttribute other = (TimeAttribute)o; + + return (this.timeGMT == other.timeGMT && + (this.nanoseconds == other.nanoseconds)); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + // the standard Date hashcode is used here... + int hashCode = (int)(this.timeGMT ^ (this.timeGMT >>> 32)); + + // ...but both the timeGMT and the nanoseconds fields are considered + // by the equals method, so it's best if the hashCode is derived + // from both of those fields. + hashCode = (31 * hashCode) + this.nanoseconds; + + return hashCode; + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("TimeAttribute: [" + Constants.nl); + + // calculate the GMT value of this time + long secsGMT = this.timeGMT / 1000; + long minsGMT = secsGMT / 60; + secsGMT = secsGMT % 60; + long hoursGMT = minsGMT / 60; + minsGMT = minsGMT % 60; + + // put the right number of zeros in place + String hoursStr = (hoursGMT < 10) ? "0" + hoursGMT : "" + hoursGMT; + String minsStr = (minsGMT < 10) ? "0" + minsGMT : "" + minsGMT; + String secsStr = (secsGMT < 10) ? "0" + secsGMT : "" + secsGMT; + + sb.append(" Time GMT: " + hoursStr + ":" + minsStr + ":" + secsStr); + sb.append(" Nanoseconds: " + this.nanoseconds); + sb.append(" TimeZone: " + this.timeZone); + sb.append(" Defaulted TimeZone: " + this.defaultedTimeZone); + sb.append("]"); + + return sb.toString(); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This returns a time value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public String encode() { + if (this.encodedValue != null) { + return this.encodedValue; + } + // "hh:mm:ss.sssssssss+hh:mm".length() = 27 + StringBuffer buf = new StringBuffer(27); + + // get the correct time for the timezone being used + int millis = (int)this.timeGMT; + if (this.timeZone == TZ_UNSPECIFIED) { + millis += (this.defaultedTimeZone + * DateAttribute.MILLIS_PER_MINUTE); + } else { + millis += (this.timeZone * DateAttribute.MILLIS_PER_MINUTE); + } + if (millis < 0) { + millis += DateAttribute.MILLIS_PER_DAY; + } else if (millis >= DateAttribute.MILLIS_PER_DAY) { + millis -= DateAttribute.MILLIS_PER_DAY; + } + + // now generate the time string + int hour = millis / DateAttribute.MILLIS_PER_HOUR; + millis = millis % DateAttribute.MILLIS_PER_HOUR; + buf.append(DateAttribute.zeroPadInt(hour, 2)); + buf.append(':'); + int minute = millis / DateAttribute.MILLIS_PER_MINUTE; + millis = millis % DateAttribute.MILLIS_PER_MINUTE; + buf.append(DateAttribute.zeroPadInt(minute, 2)); + buf.append(':'); + int second = millis / DateAttribute.MILLIS_PER_SECOND; + buf.append(DateAttribute.zeroPadInt(second, 2)); + + // add any nanoseconds + if (this.nanoseconds != 0) { + buf.append('.'); + buf.append(DateAttribute.zeroPadInt(this.nanoseconds, 9)); + } + + // if there is a specified timezone, then include that in the encoding + if (this.timeZone != TZ_UNSPECIFIED) { + int tzNoSign = this.timeZone; + if (this.timeZone < 0) { + tzNoSign = -tzNoSign; + buf.append('-'); + } else { + buf.append('+'); + } + int tzHours = tzNoSign / 60; + buf.append(DateAttribute.zeroPadInt(tzHours, 2)); + buf.append(':'); + int tzMinutes = tzNoSign % 60; + buf.append(DateAttribute.zeroPadInt(tzMinutes, 2)); + } + + // remember the encoding for later + this.encodedValue = buf.toString(); + + return this.encodedValue; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TypeIdentifierConstants.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TypeIdentifierConstants.java new file mode 100644 index 0000000..96f4023 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/TypeIdentifierConstants.java @@ -0,0 +1,78 @@ +package com.sun.xacml.attr; + +import java.net.URI; + +public class TypeIdentifierConstants { + + public static final String ANYURI = + "http://www.w3.org/2001/XMLSchema#anyURI"; + public static final String BASE64BINARY = + "http://www.w3.org/2001/XMLSchema#base64Binary"; + public static final String BOOLEAN = + "http://www.w3.org/2001/XMLSchema#boolean"; + public static final String DATE = + "http://www.w3.org/2001/XMLSchema#date"; + public static final String DATETIME = + "http://www.w3.org/2001/XMLSchema#dateTime"; + public static final String DAYTIMEDURATION = + "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration"; + public static final String DECISION = + "urn:oasis:names:tc:xacml:3.0:delegation:decision"; + public static final String DNSNAME = + "urn:oasis:names:tc:xacml:2.0:data-type:dnsName"; + public static final String DOUBLE = + "http://www.w3.org/2001/XMLSchema#double"; + public static final String HEXBINARY = + "http://www.w3.org/2001/XMLSchema#hexBinary"; + public static final String INTEGER = + "http://www.w3.org/2001/XMLSchema#integer"; + public static final String IPADDRESS = + "urn:oasis:names:tc:xacml:2.0:data-type:ipAddress"; + public static final String RFC822NAME = + "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name"; + public static final String STRING = + "http://www.w3.org/2001/XMLSchema#string"; + public static final String TIME = + "http://www.w3.org/2001/XMLSchema#time"; + public static final String X500NAME = + "urn:oasis:names:tc:xacml:1.0:data-type:x500Name"; + public static final String YEARMONTHDURATION = + "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration"; + + public static final URI ANYURI_URI = + URI.create(ANYURI); + public static final URI BASE64BINARY_URI = + URI.create(BASE64BINARY); + public static final URI BOOLEAN_URI = + URI.create(BOOLEAN); + public static final URI DATE_URI = + URI.create(DATE); + public static final URI DATETIME_URI = + URI.create(DATETIME); + public static final URI DAYTIMEDURATION_URI = + URI.create(DAYTIMEDURATION); + public static final URI DECISION_URI = + URI.create(DECISION); + public static final URI DNSNAME_URI = + URI.create(DNSNAME); + public static final URI DOUBLE_URI = + URI.create(DOUBLE); + public static final URI HEXBINARY_URI = + URI.create(HEXBINARY); + public static final URI INTEGER_URI = + URI.create(INTEGER); + public static final URI IPADDRESS_URI = + URI.create(IPADDRESS); + public static final URI RFC822NAME_URI = + URI.create(RFC822NAME); + public static final URI STRING_URI = + URI.create(STRING); + public static final URI TIME_URI = + URI.create(TIME); + public static final URI X500NAME_URI = + URI.create(X500NAME); + public static final URI YEARMONTHDURATION_URI = + URI.create(YEARMONTHDURATION); + + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/X500NameAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/X500NameAttribute.java new file mode 100644 index 0000000..66246e5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/X500NameAttribute.java @@ -0,0 +1,203 @@ + +/* + * @(#)X500NameAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import java.net.URI; + +import javax.security.auth.x500.X500Principal; + +import org.w3c.dom.Node; + +import com.sun.xacml.ParsingException; + + +/** + * Representation of an X500 Name. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + */ +public class X500NameAttribute extends AttributeValue +{ + + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.X500NAME; + + // the actual value being stored + private X500Principal value; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Creates a new X500NameAttribute that represents the + * value supplied. + * + * @param value the X500 Name to be represented + */ + public X500NameAttribute(X500Principal value) { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + + this.value = value; + } + + /** + * Returns a new that represents + * the X500 Name at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new X500NameAttribute representing the + * appropriate value + * @throws IllegalArgumentException if value is improperly specified + */ + public static X500NameAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing" + + "a X500NameAttribute"); + } + + /** + * Returns a new X500NameAttribute that represents + * the X500 Name value indicated by the string provided. + * + * @param value a string representing the desired value + * @return a new X500NameAttribute representing the + * appropriate value + * @throws IllegalArgumentException if value is improperly specified + */ + public static X500NameAttribute getInstance(String value) + throws IllegalArgumentException, ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "X500NameAttribute from null input"); + } + return new X500NameAttribute(new X500Principal(value)); + } + + /** + * Returns the name value represented by this object + * + * @return the name + */ + public X500Principal getValue() { + return this.value; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. This method + * deviates slightly from the XACML spec in the way that it handles + * RDNs with multiple attributeTypeAndValue pairs and some + * additional canonicalization steps. This method uses + * the procedure used by + * javax.security.auth.x500.X500Principal.equals(), while the + * XACML spec uses a slightly different procedure. In practice, it is + * expected that this difference will not be noticeable. For more + * details, refer to the javadoc for X500Principal.equals() + * and the XACML specification. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof X500NameAttribute)) { + return false; + } + X500NameAttribute other = (X500NameAttribute)o; + + return this.value.equals(other.value); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return this.value.hashCode(); + } + + /** + * @return The String encoding this AttributeValue. + */ + public String encode() { + return this.value.getName(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/YearMonthDurationAttribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/YearMonthDurationAttribute.java new file mode 100644 index 0000000..60890ce --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/YearMonthDurationAttribute.java @@ -0,0 +1,428 @@ + +/* + * @(#)YearMonthDurationAttribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.math.BigInteger; + +import java.net.URI; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import java.util.regex.Matcher; + +import org.w3c.dom.Node; + + +/** + * Representation of an xf:yearMonthDuration value. This class supports parsing + * xd:yearMonthDuration values. All objects of this class are immutable and + * thread-safe. The Date objects returned are not, but + * these objects are cloned before being returned. + * + * @since 1.0 + * @author Steve Hanna + */ +public class YearMonthDurationAttribute extends AttributeValue +{ + /** + * Official name of this type + */ + public static final String identifier = + TypeIdentifierConstants.YEARMONTHDURATION; + + /** + * URI version of name for this type + *

    + * This field is initialized by a static initializer so that + * we can catch any exceptions thrown by URI(String) and + * transform them into a RuntimeException, since this should + * never happen but should be reported properly if it ever does. + */ + private static URI identifierURI; + + /** + * RuntimeException that wraps an Exception thrown during the + * creation of identifierURI, null if none. + */ + private static RuntimeException earlyException; + + /** + * Static initializer that initializes the identifierURI + * class field so that we can catch any exceptions thrown + * by URI(String) and transform them into a RuntimeException. + * Such exceptions should never happen but should be reported + * properly if they ever do. + */ + static { + try { + identifierURI = URI.create(identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Regular expression for yearMonthDuration (a la java.util.regex) + */ + private static final String patternString = + "(\\-)?P((\\d+)?Y)?((\\d+)?M)?"; + + /** + * The index of the capturing group for the negative sign. + */ + private static final int GROUP_SIGN = 1; + + /** + * The index of the capturing group for the number of years. + */ + private static final int GROUP_YEARS = 3; + + /** + * The index of the capturing group for the number of months. + */ + private static final int GROUP_MONTHS = 5; + + /** + * Static BigInteger values. We only use these if one of + * the components is bigger than Integer.MAX_LONG and we + * want to detect overflow. + */ + private static BigInteger big12 = BigInteger.valueOf(12); + private static BigInteger bigMaxLong = BigInteger.valueOf(Long.MAX_VALUE); + + /** + * A shared Pattern object, only initialized if needed + */ + private static Pattern pattern; + + /** + * Negative flag. true if duration is negative, false otherwise + */ + private boolean negative; + + /** + * Number of years + */ + private long years; + + /** + * Number of months + */ + private long months; + + /** + * Total number of months (used for equals) + */ + private long totalMonths; + + /** + * Cached encoded value (null if not cached yet). + */ + private String encodedValue = null; + + /** + * Creates a new YearMonthDurationAttribute that represents + * the duration supplied. + * + * @param negative true if the duration is negative, false otherwise + * @param years the number of years in the duration (must be positive) + * @param months the number of months in the duration (must be positive) + * @throws IllegalArgumentException if the total number of months + * exceeds Long.MAX_LONG or the number + * of months or years is negative + */ + public YearMonthDurationAttribute(boolean negative, long years, + long months) + throws IllegalArgumentException { + super(identifierURI); + + // Shouldn't happen, but just in case... + if (earlyException != null) { + throw earlyException; + } + + this.negative = negative; + this.years = years; + this.months = months; + + // Convert all the components except nanoseconds to milliseconds + + // If any of the components is big (too big to be an int), + // use the BigInteger class to do the math so we can detect + // overflow. + if ((years > Integer.MAX_VALUE) || (months > Integer.MAX_VALUE)) { + BigInteger bigMonths = BigInteger.valueOf(months); + BigInteger bigYears = BigInteger.valueOf(years); + + BigInteger bigTotal = bigYears.multiply(big12).add(bigMonths); + + // If the result is bigger than Long.MAX_VALUE, we have an + // overflow. Indicate an error (should be a processing error, + // since it can be argued that we should handle gigantic + // values for this). + if (bigTotal.compareTo(bigMaxLong) == 1) { + throw new IllegalArgumentException("total number of " + + "months " + + "exceeds Long.MAX_VALUE"); + } + // If no overflow, convert to a long. + this.totalMonths = bigTotal.longValue(); + if (negative) { + this.totalMonths = - this.totalMonths; + } + } else { + // The numbers are small, so do it the fast way. + this.totalMonths = ((years * 12) + months) * (negative ? -1 : 1); + } + } + + /** + * Returns a new YearMonthDurationAttribute that represents + * the xf:yearMonthDuration at a particular DOM node. + * + * @param root the Node that contains the desired value + * @return a new YearMonthDurationAttribute representing the + * appropriate value + * @throws ParsingException if any problems occurred while parsing + */ + public static YearMonthDurationAttribute getInstance(Node root) + throws ParsingException { + if (root.getFirstChild() != null) { + return getInstance(root.getFirstChild().getNodeValue()); + } + throw new ParsingException("Error while parsing a " + + "YearMonthDurationAttribute"); + } + + /** + * Returns the long value for the capturing group groupNumber. + * This method takes a Matcher that has been used to match a + * Pattern against a String, fetches the value for the specified + * capturing group, converts that value to an long, and returns + * the value. If that group did not match, 0 is returned. + * If the matched value is not a valid long, NumberFormatException + * is thrown. + * + * @param matcher the Matcher from which to fetch the group + * @param groupNumber the group number to fetch + * @return the long value for that groupNumber + * @throws NumberFormatException if the string value for that + * groupNumber is not a valid long + */ + private static long parseGroup(Matcher matcher, int groupNumber) + throws NumberFormatException { + long groupLong = 0; + + if (matcher.start(groupNumber) != -1) { + String groupString = matcher.group(groupNumber); + groupLong = Long.parseLong(groupString); + } + return groupLong; + } + + /** + * Returns a new YearMonthDurationAttribute that represents + * the xf:yearMonthDuration value indicated by the string provided. + * + * @param value a string representing the desired value + * + * @return a new YearMonthDurationAttribute representing the + * desired value + * + * @throws ParsingException if any problems occurred while parsing + */ + public static YearMonthDurationAttribute getInstance(String value) + throws ParsingException { + if (value == null) { + throw new ParsingException("Can't create a " + + "YearMonthDurationAttribute from empty input"); + } + boolean negative = false; + long years = 0; + long months = 0; + + // Compile the pattern, if not already done. + if (pattern == null) { + try { + pattern = Pattern.compile(patternString); + } catch (PatternSyntaxException e) { + // This should never happen + throw new ParsingException("unexpected pattern syntax error"); + } + } + + // See if the value matches the pattern. + Matcher matcher = pattern.matcher(value); + boolean matches = matcher.matches(); + + // If not, syntax error! + if (!matches) { + throw new ParsingException("Syntax error in yearMonthDuration"); + } + + // If the negative group matched, the value is negative. + if (matcher.start(GROUP_SIGN) != -1) { + negative = true; + } + + try { + // If the years group matched, parse that value. + years = parseGroup(matcher, GROUP_YEARS); + + // If the months group matched, parse that value. + months = parseGroup(matcher, GROUP_MONTHS); + } catch (NumberFormatException e) { + // If we run into a number that's too big to be a long + // that's an error. Really, it's a processing error, + // since one can argue that we should handle that. + throw new ParsingException("Unable to handle number size"); + } + + // If parsing went OK, create a new YearMonthDurationAttribute + // object and return it. + return new YearMonthDurationAttribute(negative, years, months); + } + + /** + * Returns true if the duration is negative. + * + * @return true if the duration is negative, false otherwise + */ + public boolean isNegative() { + return this.negative; + } + + /** + * Gets the number of years. + * + * @return the number of years + */ + public long getYears() { + return this.years; + } + + /** + * Gets the number of months. + * + * @return the number of months + */ + public long getMonths() { + return this.months; + } + + /** + * Returns true if the input is an instance of this class and if its + * value equals the value contained in this class. + * + * @param o the object to compare + * + * @return true if this object and the input represent the same value + */ + public boolean equals(Object o) { + if (! (o instanceof YearMonthDurationAttribute)) { + return false; + } + + YearMonthDurationAttribute other = (YearMonthDurationAttribute)o; + + return (this.totalMonths == other.totalMonths); + } + + /** + * Returns the hashcode value used to index and compare this object with + * others of the same type. Typically this is the hashcode of the backing + * data object. + * + * @return the object's hashcode value + */ + public int hashCode() { + return (int) this.totalMonths ^ (int) (this.totalMonths >> 32); + } + + /** + * Converts to a String representation. + * + * @return the String representation + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("YearMonthDurationAttribute: [" + Constants.nl); + sb.append(" Negative: " + this.negative); + sb.append(" Years: " + this.years); + sb.append(" Months: " + this.months); + sb.append("]"); + + return sb.toString(); + } + + /** + * Encodes the value in a form suitable for including in XML data like + * a request or an obligation. This must return a value that could in + * turn be used by the factory to create a new instance with the same + * value. + * + * @return a String form of the value + */ + public String encode() { + if (this.encodedValue != null) { + return this.encodedValue; + } + + // Length is variable + StringBuffer buf = new StringBuffer(10); + + if (this.negative) { + buf.append('-'); + } + buf.append('P'); + if ((this.years != 0) || (this.months == 0)) { + buf.append(Long.toString(this.years)); + buf.append('Y'); + } + if (this.months != 0) { + buf.append(Long.toString(this.months)); + buf.append('M'); + } + + this.encodedValue = buf.toString(); + + return this.encodedValue; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/package.html new file mode 100644 index 0000000..80a1d3a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/package.html @@ -0,0 +1,7 @@ + + Contains many of the classes related to attributes and attribute + retrieval. This package contains the base class for all attributes, as + well as implementations of all of the standard attribute types. The + AttributeDesignatorType and the AttributeSelectorType are also + represented here. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/AnyURIAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/AnyURIAttributeProxy.java new file mode 100644 index 0000000..4a71921 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/AnyURIAttributeProxy.java @@ -0,0 +1,70 @@ + +/* + * @(#)AnyURIAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class AnyURIAttributeProxy implements AttributeProxy +{ + + /** + * @see com.sun.xacml.attr.AttributeProxy#getInstance(org.w3c.dom.Node) + */ + public AttributeValue getInstance(Node root) throws Exception { + return AnyURIAttribute.getInstance(root); + } + + /** + * @see com.sun.xacml.attr.AttributeProxy#getInstance(java.lang.String) + */ + public AttributeValue getInstance(String value) throws Exception { + return AnyURIAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/Base64BinaryAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/Base64BinaryAttributeProxy.java new file mode 100644 index 0000000..8268078 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/Base64BinaryAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)Base64BinaryAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.Base64BinaryAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class Base64BinaryAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return Base64BinaryAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return Base64BinaryAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/BooleanAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/BooleanAttributeProxy.java new file mode 100644 index 0000000..41c2e64 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/BooleanAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)BooleanAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class BooleanAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return BooleanAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return BooleanAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DNSNameAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DNSNameAttributeProxy.java new file mode 100644 index 0000000..e5c3677 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DNSNameAttributeProxy.java @@ -0,0 +1,65 @@ + +/* + * @(#)DNSNameAttributeProxy.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DNSNameAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 2.0 + * @author Seth Proctor + */ +public class DNSNameAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return DNSNameAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws ParsingException { + return DNSNameAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateAttributeProxy.java new file mode 100644 index 0000000..ab057c3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)DateAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DateAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DateAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return DateAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return DateAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateTimeAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateTimeAttributeProxy.java new file mode 100644 index 0000000..764acb4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DateTimeAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)DateTimeAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DateTimeAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DateTimeAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return DateTimeAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return DateTimeAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DayTimeDurationAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DayTimeDurationAttributeProxy.java new file mode 100644 index 0000000..1c4174f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DayTimeDurationAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)DayTimeDurationAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DayTimeDurationAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DayTimeDurationAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return DayTimeDurationAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return DayTimeDurationAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DoubleAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DoubleAttributeProxy.java new file mode 100644 index 0000000..9538fb8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/DoubleAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)DoubleAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DoubleAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return DoubleAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return DoubleAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/HexBinaryAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/HexBinaryAttributeProxy.java new file mode 100644 index 0000000..06d0702 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/HexBinaryAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)HexBinaryAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.HexBinaryAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class HexBinaryAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return HexBinaryAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return HexBinaryAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IPAddressAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IPAddressAttributeProxy.java new file mode 100644 index 0000000..a2d8a57 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IPAddressAttributeProxy.java @@ -0,0 +1,66 @@ + +/* + * @(#)IPAddressAttributeProxy.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.ParsingException; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.IPAddressAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 2.0 + * @author Seth Proctor + */ +public class IPAddressAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws ParsingException { + return IPAddressAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws ParsingException { + return IPAddressAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IntegerAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IntegerAttributeProxy.java new file mode 100644 index 0000000..2081239 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/IntegerAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)IntegerAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.IntegerAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class IntegerAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return IntegerAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return IntegerAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/RFC822NameAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/RFC822NameAttributeProxy.java new file mode 100644 index 0000000..d7adcb3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/RFC822NameAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)RFC822NameAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.RFC822NameAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class RFC822NameAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return RFC822NameAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return RFC822NameAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/StringAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/StringAttributeProxy.java new file mode 100644 index 0000000..c04677a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/StringAttributeProxy.java @@ -0,0 +1,65 @@ + +/* + * @(#)StringAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StringAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class StringAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws ParsingException { + return StringAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) { + return StringAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/TimeAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/TimeAttributeProxy.java new file mode 100644 index 0000000..9b877b4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/TimeAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)TimeAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.TimeAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class TimeAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return TimeAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return TimeAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/X500NameAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/X500NameAttributeProxy.java new file mode 100644 index 0000000..257ecaa --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/X500NameAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)X500NameAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.X500NameAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class X500NameAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return X500NameAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return X500NameAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/YearMonthDurationAttributeProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/YearMonthDurationAttributeProxy.java new file mode 100644 index 0000000..874014f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/YearMonthDurationAttributeProxy.java @@ -0,0 +1,64 @@ + +/* + * @(#)YearMonthDurationAttributeProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.attr.proxy; + +import com.sun.xacml.attr.AttributeProxy; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.YearMonthDurationAttribute; + +import org.w3c.dom.Node; + + +/** + * A proxy class that is provided mainly for the run-time configuration + * code to use. + * + * @since 1.2 + * @author Seth Proctor + */ +public class YearMonthDurationAttributeProxy implements AttributeProxy +{ + + public AttributeValue getInstance(Node root) throws Exception { + return YearMonthDurationAttribute.getInstance(root); + } + + public AttributeValue getInstance(String value) throws Exception { + return YearMonthDurationAttribute.getInstance(value); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/package.html new file mode 100644 index 0000000..9da00b5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/attr/proxy/package.html @@ -0,0 +1,8 @@ + + This package defines proxy classes for all of the standard + datatypes. This package was introduced in version 1.2 with the new + run-time configuration code, which needs concrete proxy classes to add + datatype support to a factory. Before 1.2, the + AttributeFactory used annonymous classes to cut down on + the total number of files in this project. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/BaseCombiningAlgFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/BaseCombiningAlgFactory.java new file mode 100644 index 0000000..972c058 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/BaseCombiningAlgFactory.java @@ -0,0 +1,156 @@ + +/* + * @(#)BaseCombiningAlgFactory.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.UnknownIdentifierException; + +import java.net.URI; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + + +/** + * This is a basic implementation of CombiningAlgFactory. It + * implements the insertion and retrieval methods, but doesn't actually + * setup the factory with any algorithms. + *

    + * Note that while this class is thread-safe on all creation methods, it + * is not safe to add support for a new algorithm while creating an instance + * of an algorithm. This follows from the assumption that most people will + * initialize these factories up-front, and then start processing without + * ever modifying the factories. If you need these mutual operations to + * be thread-safe, then you should write a wrapper class that implements + * the right synchronization. + * + * @since 1.2 + * @author Seth Proctor + */ +public class BaseCombiningAlgFactory extends CombiningAlgFactory +{ + + // the map of available combining algorithms + private HashMap algMap; + + /** + * Default constructor. + */ + public BaseCombiningAlgFactory() { + this.algMap = new HashMap(); + } + + /** + * Constructor that configures this factory with an initial set of + * supported algorithms. + * + * @param algorithms a Set of + * CombiningAlgorithms + * + * @throws IllegalArgumentException if any elements of the set are not + * CombiningAlgorithms + */ + public BaseCombiningAlgFactory(Set algorithms) { + this.algMap = new HashMap(); + + Iterator it = algorithms.iterator(); + while (it.hasNext()) { + try { + CombiningAlgorithm alg = it.next(); + this.algMap.put(alg.getIdentifier().toString(), alg); + } catch (ClassCastException cce) { + throw new IllegalArgumentException("an element of the set " + + "was not an instance of " + + "CombiningAlgorithm"); + } + } + } + + /** + * Adds a combining algorithm to the factory. This single instance will + * be returned to anyone who asks the factory for an algorithm with the + * id given here. + * + * @param alg the combining algorithm to add + * + * @throws IllegalArgumentException if the algId is already registered + */ + public void addAlgorithm(CombiningAlgorithm alg) { + String algId = alg.getIdentifier().toString(); + + // check that the id doesn't already exist in the factory + if (this.algMap.containsKey(algId)) { + throw new IllegalArgumentException("algorithm already registered: " + + algId); + } + // add the algorithm + this.algMap.put(algId, alg); + } + + /** + * Returns the algorithm identifiers supported by this factory. + * + * @return a Set of Strings + */ + public Set getSupportedAlgorithms() { + return Collections.unmodifiableSet(this.algMap.keySet()); + } + + /** + * Tries to return the correct combinging algorithm based on the + * given algorithm ID. + * + * @param algId the identifier by which the algorithm is known + * + * @return a combining algorithm + * + * @throws UnknownIdentifierException algId is unknown + */ + public CombiningAlgorithm createAlgorithm(URI algId) + throws UnknownIdentifierException + { + String id = algId.toString(); + + if (this.algMap.containsKey(id)) { + return (CombiningAlgorithm)(this.algMap.get(algId.toString())); + } + throw new UnknownIdentifierException("unknown combining algId: " + + id); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerElement.java new file mode 100644 index 0000000..6186d2b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerElement.java @@ -0,0 +1,130 @@ + +/* + * @(#)CombinerElement.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.Indenter; +import com.sun.xacml.PolicyTreeElement; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + + +/** + * Represents one input (a Rule, Policy, PolicySet, or reference) to a + * combining algorithm and combiner parameters associated with that input. + * + * @since 2.0 + * @author Seth Proctor + */ +public abstract class CombinerElement +{ + + // the element to be combined + private PolicyTreeElement element; + + // the parameters used with this element + private List parameters; + + /** + * Constructor that only takes an element. No parameters are associated + * with this element when combining. + * + * @param element a PolicyTreeElement to use in combining + */ + public CombinerElement(PolicyTreeElement element) { + this(element, null); + } + + /** + * Constructor that takes both the element to combine and its associated + * combiner parameters. + * + * @param element a PolicyTreeElement to use in combining + * @param parameters a (possibly empty) non-null List of + * CombinerParameters provided for general + * use (for all pre-2.0 policies this must be empty) + */ + public CombinerElement(PolicyTreeElement element, List parameters) { + this.element = element; + + if (parameters == null) { + this.parameters = Collections.unmodifiableList(new ArrayList()); + } else { + this.parameters = Collections. + unmodifiableList(new ArrayList(parameters)); + } + } + + /** + * Returns the PolicyTreeElement in this element. + * + * @return the PolicyTreeElement + */ + public PolicyTreeElement getElement() { + return this.element; + } + + /** + * Returns the CombinerParameters associated with this + * element. + * + * @return a List of CombinerParameters + */ + public List getParameters() { + return this.parameters; + } + + /** + * Encodes the element and parameters in this CombinerElement + * into their XML representation and writes this encoding to the given + * OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + */ + public abstract void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerParameter.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerParameter.java new file mode 100644 index 0000000..e3d4c96 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombinerParameter.java @@ -0,0 +1,204 @@ + +/* + * @(#)CombinerParameter.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; + +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.debug.Locatable; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents a single named parameter to a combining algorithm. Parameters + * are only used by XACML 2.0 and later policies. + * + * @since 2.0 + * @author Seth Proctor + */ +public class CombinerParameter implements Locatable +{ + + // the name of this parameter + private String name; + + // the value of this parameter + private AttributeValue value; + + public static final List EMPTY_LIST = Collections.emptyList(); + + private RuntimeInfo src; + + /** + * Creates a new CombinerParameter. + * + * @param name the parameter's name + * @param value the parameter's value + */ + public CombinerParameter(String name, AttributeValue value) { + this.name = name; + this.value = value; + } + + /** + * Returns a new instance of the CombinerParameter class + * based on a DOM node. The node must be the root of an XML + * CombinerParameterType. + * + * @param root the DOM root of a CombinerParameterType XML type + * + * @return The combiner parameter. + * + * @throws ParsingException if the CombinerParameterType is invalid + */ + public static CombinerParameter getInstance(Node root) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.COMBINER_PARAMETER); + // check if this really is a CombinerParameter + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("CombinerParameter")) { + throw new ParsingException("Can't create a CombinerParameter " + + "from a " + root.getLocalName() + " element" + + ( src == null ? "" : src.getLocationMsgForError())); + } + // get the name, which is a required attribute + String name = null; + if (root.getAttributes().getNamedItem("ParameterName") != null) { + name = root.getAttributes().getNamedItem("ParameterName") + .getNodeValue(); + } else { + throw new ParsingException("Required XML attribute ParameterName" + + " not found while parsing a CombinerParameter" + + ( src == null ? "" : src.getLocationMsgForError())); + } + + // get the attribute value, the only child of this element + AttributeFactory attrFactory = AttributeFactory.getInstance(); + AttributeValue value = null; + + NodeList children = root.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if ( child.getNodeType() == Node.ELEMENT_NODE ) { + try { + value = attrFactory.createValue(child); + break; + } catch (UnknownIdentifierException uie) { + throw new ParsingException("Unknown AttributeId" + + ( src == null ? "" : src.getLocationMsgForError()), uie); + } + } + } + if ( value == null ) { + throw new ParsingException("Missing AttributeValue for CombinerParameter" + + ( src == null ? "" : src.getLocationMsgForError())); + } + + CombinerParameter param = new CombinerParameter(name, value); + param.src = src; + return param; + } + + /** + * Returns the name of this parameter. + * + * @return the name of this parameter + */ + public String getName() { + return this.name; + } + + /** + * Returns the value provided by this parameter. + * + * @return the value provided by this parameter + */ + public AttributeValue getValue() { + return this.value; + } + + /** + * Encodes this parameter into its XML representation and writes this + * encoding to the given OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + getValue().encode(output, charsetName, indenter); + + out.println(indent + ""); + indenter.out(); + } + + public RuntimeInfo getRuntimeInfo() { + return src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactory.java new file mode 100644 index 0000000..bff1eb4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactory.java @@ -0,0 +1,273 @@ + +/* + * @(#)CombiningAlgFactory.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.Constants; +import com.sun.xacml.UnknownIdentifierException; + +import java.net.URI; + +import java.util.HashMap; +import java.util.Set; + + +/** + * Provides a factory mechanism for installing and retrieving combining + * algorithms. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class CombiningAlgFactory +{ + + // the proxy used to get the default factory + private static CombiningAlgFactoryProxy defaultFactoryProxy; + + // the map of registered factories + private static HashMap registeredFactories + = new HashMap(); + + // ignores the configuration, i.e., +// /** +// * static intialiazer that sets up the default factory proxy and +// * registers the standard namespaces +// */ +// static { +// CombiningAlgFactoryProxy proxy = new CombiningAlgFactoryProxy() { +// public CombiningAlgFactory getFactory() { +// return StandardCombiningAlgFactory.getFactory(); +// } +// }; +// +// registeredFactories = new HashMap(); +// registeredFactories.put(Constants.XACML_1_0_IDENTIFIER, proxy); +// registeredFactories.put(Constants.XACML_2_0_IDENTIFIER, proxy); +// registeredFactories.put(Constants.XACML_3_0_IDENTIFIER, proxy); +// +// defaultFactoryProxy = proxy; +// } + // + + /** + * Default constructor. Used only by subclasses. + */ + protected CombiningAlgFactory() { + //used only by subclasses + } + + /** + * Returns the default factory. Depending on the default factory's + * implementation, this may return a singleton instance or new instances + * with each invokation. + * + * @return the default CombiningAlgFactory + */ + public static final CombiningAlgFactory getInstance() { + return defaultFactoryProxy.getFactory(); + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0, 2.0 and 3.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return a CombiningAlgFactory + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final CombiningAlgFactory getInstance(String identifier) + throws UnknownIdentifierException + { + CombiningAlgFactoryProxy proxy = + (CombiningAlgFactoryProxy)(registeredFactories.get(identifier)); + + if (proxy == null) { + throw new UnknownIdentifierException("Uknown CombiningAlgFactory " + + "identifier: " + + identifier); + } + return proxy.getFactory(); + } + + /** + * Sets the default factory. This does not register the factory proxy as + * an identifiable factory. + * + * @param proxy the CombiningAlgFactoryProxy to set as the + * new default factory proxy + */ + public static final void setDefaultFactory(CombiningAlgFactoryProxy proxy) + { + defaultFactoryProxy = proxy; + } + + public static final void setAllFactories(CombiningAlgFactory factory) { + + CombiningAlgFactoryProxyImpl proxy = new CombiningAlgFactoryProxyImpl(factory); + + registeredFactories.put(Constants.XACML_1_0_IDENTIFIER, proxy); + registeredFactories.put(Constants.XACML_2_0_IDENTIFIER, proxy); + registeredFactories.put(Constants.XACML_3_0_IDENTIFIER, proxy); + + defaultFactoryProxy = proxy; + } + + /** + * Registers the given factory proxy with the given identifier. If the + * identifier is already used, then this throws an exception. If the + * identifier is not already used, then it will always be bound to the + * given proxy. + * + * @param identifier the identifier for the proxy + * @param proxy the CombiningAlgFactoryProxy to register with + * the given identifier + * + * @throws IllegalArgumentException if the identifier is already used + */ + public static final void registerFactory(String identifier, + CombiningAlgFactoryProxy proxy) + throws IllegalArgumentException + { + synchronized (registeredFactories) { + if (registeredFactories.containsKey(identifier)) { + throw new IllegalArgumentException("Identifier is already " + + "registered as " + + "CombiningAlgFactory: " + + identifier); + } + + registeredFactories.put(identifier, proxy); + } + } + + + + /** + * Adds a combining algorithm to the factory. This single instance will + * be returned to anyone who asks the factory for an algorithm with the + * id given here. + * + * @param alg the combining algorithm to add + * + * @throws IllegalArgumentException if the algorithm is already registered + */ + public abstract void addAlgorithm(CombiningAlgorithm alg); + + /** + * Adds a combining algorithm to the factory. This single instance will + * be returned to anyone who asks the factory for an algorithm with the + * id given here. + * + * @deprecated As of version 1.2, replaced by + * {@link #addAlgorithm(CombiningAlgorithm)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param alg the combining algorithm to add + * + * @throws IllegalArgumentException if the algorithm is already registered + */ + public static void addCombiningAlg(CombiningAlgorithm alg) { + getInstance().addAlgorithm(alg); + } + + /** + * Returns the algorithm identifiers supported by this factory. + * + * @return a Set of Strings + */ + public abstract Set getSupportedAlgorithms(); + + /** + * Tries to return the correct combinging algorithm based on the + * given algorithm ID. + * + * @param algId the identifier by which the algorithm is known + * + * @return a combining algorithm + * + * @throws UnknownIdentifierException algId is unknown + */ + public abstract CombiningAlgorithm createAlgorithm(URI algId) + throws UnknownIdentifierException; + + /** + * Tries to return the correct combinging algorithm based on the + * given algorithm ID. + * + * @deprecated As of version 1.2, replaced by + * {@link #createAlgorithm(URI)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param algId the identifier by which the algorithm is known + * + * @return a combining algorithm + * + * @throws UnknownIdentifierException algId is unknown + */ + public static CombiningAlgorithm createCombiningAlg(URI algId) + throws UnknownIdentifierException + { + return getInstance().createAlgorithm(algId); + } + + private static class CombiningAlgFactoryProxyImpl implements CombiningAlgFactoryProxy { + + CombiningAlgFactory factory; + + CombiningAlgFactoryProxyImpl(CombiningAlgFactory factory) { + this.factory = factory; + } + + public CombiningAlgFactory getFactory() { + return factory; + } + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactoryProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactoryProxy.java new file mode 100644 index 0000000..48802a0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgFactoryProxy.java @@ -0,0 +1,58 @@ + +/* + * @(#)CombiningAlgFactoryProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + + +/** + * A simple proxy interface used to install new + * CombiningAlgFactorys. + * + * @since 1.2 + * @author Seth Proctor + */ +public interface CombiningAlgFactoryProxy +{ + + /** + * Returns an instance of the CombiningAlgFactory for which + * this is a proxy. + * + * @return a CombiningAlgFactory instance + */ + public CombiningAlgFactory getFactory(); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgorithm.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgorithm.java new file mode 100644 index 0000000..2607a39 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/CombiningAlgorithm.java @@ -0,0 +1,161 @@ + +/* + * @(#)CombiningAlgorithm.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.ctx.Result; +import com.sun.xacml.debug.IndirectLocatable; +import com.sun.xacml.debug.RuntimeInfo; + +import java.net.URI; + +import java.util.List; +import java.util.Stack; + +import org.apache.log4j.Logger; + + +/** + * The base type for all combining algorithms. It provides one method that + * must be implemented. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class CombiningAlgorithm implements IndirectLocatable +{ + + // the identifier for the algorithm + private URI identifier; + + //private RuntimeInfo src; + private Stack src; + + private static Logger logger = Logger.getLogger(CombiningAlgorithm.class); + + + + /** + * Constructor that takes the algorithm's identifier. + * + * @param identifier the algorithm's identifier + */ + public CombiningAlgorithm(URI identifier) { + this.identifier = identifier; + } + + /** + * Combines the results of the inputs based on the context to produce + * some unified result. This is the one function of a combining algorithm. + * + * @param context the representation of the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters provided for general + * use (for all pre-2.0 policies this must be empty) + * @param inputs a List of CombinerElementss to + * evaluate and combine + * + * @return a single unified result based on the combining logic + */ + public abstract Result combine(EvaluationCtx context, List parameters, + List inputs); + + /** + * Returns the identifier for this algorithm. + * + * @return the algorithm's identifier + */ + public URI getIdentifier() { + return this.identifier; + } + + public RuntimeInfo getRuntimeInfo() { + if ( this.src != null && this.src.size() > 0 ) { + return this.src.get(this.src.size()-1); + } else { + return null; + } + + //return this.src; + } + + /** + * Implements the IndirectLocatable interface + */ + public void setRuntimeInfo(RuntimeInfo src) { + if ( this.src == null ) { + this.src = new Stack(); + } + this.src.push(src); +// if ( this.src != null ) { +// logger.warn("Overwriting SourceLocator! This indicates that " + +// "serveral threads are used to query the enginge which " + +// "should NOT be the case when the source locator feature " + +// "is enabled (overwrite" + +// ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + +// ( src == null ? "null" : src.getLocationMsgForError())); +// try { +// throw new Exception(); +// } catch(Exception e) { +// e.printStackTrace(); +// } +// } +// this.src = src; + } + + /** + * Implements the IndirectLocatable interface + */ + public void unsetRuntimeInfo(RuntimeInfo src) { + if ( this.src != null ) { + RuntimeInfo src_pop = this.src.pop(); + if ( src_pop != src ) { + logger.warn("Unset Source Locator Object which did not match the current " + + "element on the stack"); + this.src.removeAllElements(); + } + } +// if ( src != this.src ) { +// logger.warn("Unset Source Locator Object which is currently unvalid! (from " + +// ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + +// ( src == null ? "null" : src.getLocationMsgForError())); +// } +// this.src = null; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesPolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesPolicyAlg.java new file mode 100644 index 0000000..85e46f1 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesPolicyAlg.java @@ -0,0 +1,179 @@ + +/* + * @(#)DenyOverridesPolicyAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.MatchResult; +import com.sun.xacml.Obligation; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * This is the standard Deny Overrides policy combining algorithm. It + * allows a single evaluation of Deny to take precedence over any number + * of permit, not applicable or indeterminate results. Note that since + * this implementation does an ordered evaluation, this class also + * supports the Ordered Deny Overrides algorithm. + * + * @since 1.0 + * @author Seth Proctor + */ +public class DenyOverridesPolicyAlg extends PolicyCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:" + + "deny-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public DenyOverridesPolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + /** + * Protected constructor used by the ordered version of this algorithm. + * + * @param identifier the algorithm's identifier + */ + protected DenyOverridesPolicyAlg(URI identifier) { + super(identifier); + } + + /** + * Applies the combining rule to the set of policies based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param policyElements the policies to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List policyElements) { + boolean atLeastOnePermit = false; + Set permitObligations = new HashSet(); + Iterator it = policyElements.iterator(); + + while (it.hasNext()) { + AbstractPolicy policy = ((PolicyCombinerElement) it.next()).getPolicy(); + + // make sure that the policy matches the context + context.newEvent(policy); + MatchResult match = policy.match(context); + + if (match.getResult() == MatchResult.INDETERMINATE) { + Result result = new Result(Result.DECISION_DENY, context); + context.closeCurrentEvent(result); + return result; + } + + if (match.getResult() == MatchResult.NO_MATCH) { + context.closeCurrentEvent( + new Result(Result.DECISION_NOT_APPLICABLE)); + } + + if (match.getResult() == MatchResult.MATCH) { + // evaluate the policy + Result result = policy.evaluate(context); + context.closeCurrentEvent(result); + // do not treat the discarded values + if (result != null) { + int effect = result.getDecision(); + + // unlike in the RuleCombining version of this alg, we + // always return DENY if any Policy returns DENY or + // INDETERMINATE + if ((effect == Result.DECISION_DENY) || + (effect == Result.DECISION_INDETERMINATE)) { + return new Result(Result.DECISION_DENY, + context, + result.getObligations()); + } + + // remember if at least one Policy said PERMIT + if (effect == Result.DECISION_PERMIT) { + atLeastOnePermit = true; + permitObligations.addAll(result.getObligations()); + } + } + } + } + + // if we got a PERMIT, return it, otherwise it's NOT_APPLICABLE + if (atLeastOnePermit) { + return new Result(Result.DECISION_PERMIT, + context, + permitObligations); + } + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesRuleAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesRuleAlg.java new file mode 100644 index 0000000..4d08803 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/DenyOverridesRuleAlg.java @@ -0,0 +1,184 @@ + +/* + * @(#)DenyOverridesRuleAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Rule; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.Iterator; +import java.util.List; + + +/** + * This is the standard Deny Overrides rule combining algorithm. It + * allows a single evaluation of Deny to take precedence over any number + * of permit, not applicable or indeterminate results. Note that since + * this implementation does an ordered evaluation, this class also + * supports the Ordered Deny Overrides algorithm. + * + * @since 1.0 + * @author Seth Proctor + */ +public class DenyOverridesRuleAlg extends RuleCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:" + + "deny-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public DenyOverridesRuleAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + /** + * Protected constructor used by the ordered version of this algorithm. + * + * @param identifier the algorithm's identifier + */ + protected DenyOverridesRuleAlg(URI identifier) { + super(identifier); + } + + /** + * Applies the combining rule to the set of rules based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param ruleElements the rules to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List ruleElements) { + boolean atLeastOneError = false; + boolean potentialDeny = false; + boolean atLeastOnePermit = false; + Result firstIndeterminateResult = null; + Iterator it = ruleElements.iterator(); + + while (it.hasNext()) { + Rule rule = ((RuleCombinerElement)(it.next())).getRule(); + Result result = rule.evaluate(context); + int value = result.getDecision(); + + // if there was a value of DENY, then regardless of what else + // we've seen, we always return DENY + if (value == Result.DECISION_DENY) { + return result; + } + + // if it was INDETERMINATE, then we couldn't figure something + // out, so we keep track of these cases... + if (value == Result.DECISION_INDETERMINATE) { + atLeastOneError = true; + + // there are no rules about what to do if multiple cases + // cause errors, so we'll just return the first one + if (firstIndeterminateResult == null) { + firstIndeterminateResult = result; + } + + // if the Rule's effect is DENY, then we can't let this + // alg return PERMIT, since this Rule might have denied + // if it could do its stuff + if (rule.getEffect() == Result.DECISION_DENY) { + potentialDeny = true; + } + } else { + // keep track of whether we had at least one rule that + // actually pertained to the request + if (value == Result.DECISION_PERMIT) { + atLeastOnePermit = true; + } + } + } + + // we didn't explicitly DENY, but we might have had some Rule + // been evaluated, so we have to return INDETERMINATE + if (potentialDeny) { + return firstIndeterminateResult; + } + + // some Rule said PERMIT, so since nothing could have denied, + // we return PERMIT + if (atLeastOnePermit) { + return new Result(Result.DECISION_PERMIT, + context); + } + + // we didn't find anything that said PERMIT, but if we had a + // problem with one of the Rules, then we're INDETERMINATE + if (atLeastOneError) { + return firstIndeterminateResult; + } + + // if we hit this point, then none of the rules actually applied + // to us, so we return NOT_APPLICABLE + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicablePolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicablePolicyAlg.java new file mode 100644 index 0000000..72bd17d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicablePolicyAlg.java @@ -0,0 +1,152 @@ + +/* + * @(#)FirstApplicablePolicyAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.MatchResult; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.Iterator; +import java.util.List; + + +/** + * This is the standard First Applicable policy combining algorithm. It looks + * through the set of policies, finds the first one that applies, and returns + * that evaluation result. + * + * @since 1.0 + * @author Seth Proctor + */ +public class FirstApplicablePolicyAlg extends PolicyCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:" + + "first-applicable"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public FirstApplicablePolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + /** + * Applies the combining rule to the set of policies based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param policyElements the policies to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List policyElements) { + Iterator it = policyElements.iterator(); + + while (it.hasNext()) { + AbstractPolicy policy = + ((PolicyCombinerElement)(it.next())).getPolicy(); + + // make sure that the policy matches the context + context.newEvent(policy); + MatchResult match = policy.match(context); + + if (match.getResult() == MatchResult.INDETERMINATE) { + Result result = new Result(Result.DECISION_INDETERMINATE, + match.getStatus(), + context); + context.closeCurrentEvent(result); + return result; + } + + if (match.getResult() == MatchResult.NO_MATCH) { + context.closeCurrentEvent( + new Result(Result.DECISION_NOT_APPLICABLE)); + } + + if (match.getResult() == MatchResult.MATCH) { + // evaluate the policy + Result result = policy.evaluate(context); + context.closeCurrentEvent(result); + // do not treat the discarded values + if (result != null) { + int effect = result.getDecision(); + + // in the case of PERMIT, DENY, or INDETERMINATE, we always + // just return that result, so only on a rule that doesn't + // apply do we keep going... + if (effect != Result.DECISION_NOT_APPLICABLE) { + return result; + } + } + } + } + + // if we got here, then none of the rules applied + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicableRuleAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicableRuleAlg.java new file mode 100644 index 0000000..4adddb4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/FirstApplicableRuleAlg.java @@ -0,0 +1,128 @@ + +/* + * @(#)FirstApplicableRuleAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Rule; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.Iterator; +import java.util.List; + + +/** + * This is the standard First Applicable rule combining algorithm. It looks + * through the set of rules, finds the first one that applies, and returns + * that evaluation result. + * + * @since 1.0 + * @author Seth Proctor + */ +public class FirstApplicableRuleAlg extends RuleCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:" + + "first-applicable"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public FirstApplicableRuleAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + + + /** + * Applies the combining rule to the set of rules based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param ruleElements the rules to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List ruleElements) { + + Iterator it = ruleElements.iterator(); + + while (it.hasNext()) { + Rule rule = ((RuleCombinerElement)(it.next())).getRule(); + Result result = rule.evaluate(context); + int value = result.getDecision(); + + // in the case of PERMIT, DENY, or INDETERMINATE, we always + // just return that result, so only on a rule that doesn't + // apply do we keep going... + if (value != Result.DECISION_NOT_APPLICABLE) { + return result; + } + } + + // if we got here, then none of the rules applied + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OnlyOneApplicablePolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OnlyOneApplicablePolicyAlg.java new file mode 100644 index 0000000..5ad2861 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OnlyOneApplicablePolicyAlg.java @@ -0,0 +1,175 @@ + +/* + * @(#)OnlyOneApplicablePolicyAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.MatchResult; + +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +/** + * This is the standard Only One Applicable Policy combining algorithm. This + * is a special algorithm used at the root of a policy/pdp to make sure that + * pdp only selects one policy per request. + * + * @since 1.0 + * @author Seth Proctor + */ +public class OnlyOneApplicablePolicyAlg extends PolicyCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:" + + "only-one-applicable"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public OnlyOneApplicablePolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + + + /** + * Applies the combining rule to the set of policies based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param policyElements the policies to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List policyElements) { + boolean atLeastOne = false; + AbstractPolicy selectedPolicy = null; + Iterator it = policyElements.iterator(); + + while (it.hasNext()) { + AbstractPolicy policy = + ((PolicyCombinerElement)(it.next())).getPolicy(); + + // see if the policy matches the context + context.newEvent(policy); + MatchResult match = policy.match(context); + + // if there is an error in trying to match any of the targets, + // we always return INDETERMINATE immediately + if (match.getResult() == MatchResult.INDETERMINATE) { + Result result = new Result(Result.DECISION_INDETERMINATE, + match.getStatus(), + context); + context.closeCurrentEvent(result); + return result; + } + + if (match.getResult() == MatchResult.NO_MATCH) { + context.closeCurrentEvent( + new Result(Result.DECISION_NOT_APPLICABLE)); + } + + if (match.getResult() == MatchResult.MATCH) { + // if this isn't the first match, then this is an error + if (atLeastOne) { + List code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + String message = "Too many applicable policies"; + Result result = new Result(Result.DECISION_INDETERMINATE, + new Status(code, message), + context); + context.closeCurrentEvent(result); + return result; + } + + // if this was the first applicable policy in the set, then + // remember it for later + atLeastOne = true; + selectedPolicy = policy; + context.closeCurrentEvent("Evaluated later"); + } + } + + // if we got through the loop and found exactly one match, then + // we return the evaluation result of that policy + if (atLeastOne) { + context.newEvent(selectedPolicy); + Result result = selectedPolicy.evaluate(context); + context.closeCurrentEvent(result); + // do not treat the discarded values + if (result != null) { + return result; + } + } + + // if we didn't find a matching policy, then we don't apply + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesPolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesPolicyAlg.java new file mode 100644 index 0000000..5e03fcb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesPolicyAlg.java @@ -0,0 +1,85 @@ + +/* + * OrderedDenyOverridesPolicyAlg.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import java.net.URI; + + +/** + * This is the standard Ordered Deny Overrides policy combining algorithm. It + * allows a single evaluation of Deny to take precedence over any number + * of permit, not applicable or indeterminate results. Note that this uses + * the regular Deny Overrides implementation since it is also orderd. + * + * @since 1.1 + * @author seth proctor + */ +public class OrderedDenyOverridesPolicyAlg extends DenyOverridesPolicyAlg +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:" + + "ordered-deny-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public OrderedDenyOverridesPolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesRuleAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesRuleAlg.java new file mode 100644 index 0000000..9969dcf --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedDenyOverridesRuleAlg.java @@ -0,0 +1,85 @@ + +/* + * @(#)OrderedDenyOverridesRuleAlg.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import java.net.URI; + + +/** + * This is the standard Ordered Deny Overrides rule combining algorithm. It + * allows a single evaluation of Deny to take precedence over any number + * of permit, not applicable or indeterminate results. Note that this uses + * the regular Deny Overrides implementation since it is also orderd. + * + * @since 1.1 + * @author seth proctor + */ +public class OrderedDenyOverridesRuleAlg extends DenyOverridesRuleAlg +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:" + + "ordered-deny-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public OrderedDenyOverridesRuleAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesPolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesPolicyAlg.java new file mode 100644 index 0000000..0f63ede --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesPolicyAlg.java @@ -0,0 +1,85 @@ + +/* + * @(#)OrderedPermitOverridesPolicyAlg.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import java.net.URI; + + +/** + * This is the standard Ordered Permit Overrides policy combining algorithm. + * It allows a single evaluation of Permit to take precedence over any number + * of deny, not applicable or indeterminate results. Note that this uses + * the regular Permit Overrides implementation since it is also orderd. + * + * @since 1.1 + * @author seth proctor + */ +public class OrderedPermitOverridesPolicyAlg extends PermitOverridesPolicyAlg +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.1:policy-combining-algorithm:" + + "ordered-permit-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public OrderedPermitOverridesPolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesRuleAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesRuleAlg.java new file mode 100644 index 0000000..2859dd0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/OrderedPermitOverridesRuleAlg.java @@ -0,0 +1,85 @@ + +/* + * @(#)OrderedPermitOverridesRuleAlg.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import java.net.URI; + + +/** + * This is the standard Ordered Permit Overrides rule combining algorithm. It + * allows a single evaluation of Permit to take precedence over any number + * of deny, not applicable or indeterminate results. Note that this uses + * the regular Permit Overrides implementation since it is also orderd. + * + * @since 1.1 + * @author seth proctor + */ +public class OrderedPermitOverridesRuleAlg extends PermitOverridesRuleAlg +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:" + + "ordered-permit-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public OrderedPermitOverridesRuleAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesPolicyAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesPolicyAlg.java new file mode 100644 index 0000000..b988858 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesPolicyAlg.java @@ -0,0 +1,195 @@ + +/* + * @(#)PermitOverridesPolicyAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.MatchResult; +import com.sun.xacml.Obligation; + +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; + +import java.net.URI; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * This is the standard Permit Overrides policy combining algorithm. It + * allows a single evaluation of Permit to take precedence over any number + * of deny, not applicable or indeterminate results. Note that since + * this implementation does an ordered evaluation, this class also + * supports the Ordered Permit Overrides algorithm. + * + * @since 1.0 + * @author Seth Proctor + */ +public class PermitOverridesPolicyAlg extends PolicyCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:" + + "permit-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public PermitOverridesPolicyAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + /** + * Protected constructor used by the ordered version of this algorithm. + * + * @param identifier the algorithm's identifier + */ + protected PermitOverridesPolicyAlg(URI identifier) { + super(identifier); + } + + /** + * Applies the combining rule to the set of policies based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param policyElements the policies to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List policyElements) { + boolean atLeastOneError = false; + boolean atLeastOneDeny = false; + Set denyObligations = new HashSet(); + Status firstIndeterminateStatus = null; + Iterator it = policyElements.iterator(); + + while (it.hasNext()) { + AbstractPolicy policy = + ((PolicyCombinerElement)(it.next())).getPolicy(); + + // make sure that the policy matches the context + context.newEvent(policy); + MatchResult match = policy.match(context); + + if (match.getResult() == MatchResult.INDETERMINATE) { + context.closeCurrentEvent( + new Result(Result.DECISION_INDETERMINATE, context)); + atLeastOneError = true; + + // keep track of the first error, regardless of cause + if (firstIndeterminateStatus == null) { + firstIndeterminateStatus = match.getStatus(); + } + } else if (match.getResult() == MatchResult.NO_MATCH) { + context.closeCurrentEvent( + new Result(Result.DECISION_NOT_APPLICABLE)); + } else if (match.getResult() == MatchResult.MATCH) { + // now we evaluate the policy + Result result = policy.evaluate(context); + context.closeCurrentEvent(result); + + // do not treat the discarded values + if (result != null) { + int effect = result.getDecision(); + + // this is a little different from DenyOverrides... + if (effect == Result.DECISION_PERMIT) { + return result; + } + + if (effect == Result.DECISION_DENY) { + atLeastOneDeny = true; + denyObligations.addAll(result.getObligations()); + } else if (effect == Result.DECISION_INDETERMINATE) { + atLeastOneError = true; + + // keep track of the first error, regardless of cause + if (firstIndeterminateStatus == null) { + firstIndeterminateStatus = result.getStatus(); + } + } + } + } + } + + // if we got a DENY, return it + if (atLeastOneDeny) { + return new Result(Result.DECISION_DENY, + context, + denyObligations); + } + + // if we got an INDETERMINATE, return it + if (atLeastOneError) { + return new Result(Result.DECISION_INDETERMINATE, + firstIndeterminateStatus, + context); + } + + // if we got here, then nothing applied to us + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesRuleAlg.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesRuleAlg.java new file mode 100644 index 0000000..ab92f13 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PermitOverridesRuleAlg.java @@ -0,0 +1,184 @@ + +/* + * @(#)PermitOverridesRuleAlg.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Rule; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.Iterator; +import java.util.List; + + +/** + * This is the standard Permit Overrides rule combining algorithm. It + * allows a single evaluation of Permit to take precedence over any number + * of deny, not applicable or indeterminate results. Note that since + * this implementation does an ordered evaluation, this class also + * supports the Ordered Permit Overrides algorithm. + * + * @since 1.0 + * @author Seth Proctor + */ +public class PermitOverridesRuleAlg extends RuleCombiningAlgorithm +{ + + /** + * The standard URN used to identify this algorithm + */ + public static final String algId = + "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:" + + "permit-overrides"; + + // a URI form of the identifier + private static URI identifierURI; + // exception if the URI was invalid, which should never be a problem + private static RuntimeException earlyException; + + static { + try { + identifierURI = URI.create(algId); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Standard constructor. + */ + public PermitOverridesRuleAlg() { + super(identifierURI); + + if (earlyException != null) { + throw earlyException; + } + } + + /** + * Protected constructor used by the ordered version of this algorithm. + * + * @param identifier the algorithm's identifier + */ + protected PermitOverridesRuleAlg(URI identifier) { + super(identifier); + } + + /** + * Applies the combining rule to the set of rules based on the + * evaluation context. + * + * @param context the context from the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param ruleElements the rules to combine + * + * @return the result of running the combining algorithm + */ + public Result combine(EvaluationCtx context, List parameters, + List ruleElements) { + boolean atLeastOneError = false; + boolean potentialPermit = false; + boolean atLeastOneDeny = false; + Result firstIndeterminateResult = null; + Iterator it = ruleElements.iterator(); + + while (it.hasNext()) { + Rule rule = ((RuleCombinerElement)(it.next())).getRule(); + Result result = rule.evaluate(context); + int value = result.getDecision(); + + // if there was a value of PERMIT, then regardless of what + // else we've seen, we always return PERMIT + if (value == Result.DECISION_PERMIT) { + return result; + } + + // if it was INDETERMINATE, then we couldn't figure something + // out, so we keep track of these cases... + if (value == Result.DECISION_INDETERMINATE) { + atLeastOneError = true; + + // there are no rules about what to do if multiple cases + // cause errors, so we'll just return the first one + if (firstIndeterminateResult == null) { + firstIndeterminateResult = result; + } + + // if the Rule's effect is PERMIT, then we can't let this + // alg return DENY, since this Rule might have permitted + // if it could do its stuff + if (rule.getEffect() == Result.DECISION_PERMIT) { + potentialPermit = true; + } + } else { + // keep track of whether we had at least one rule that + // actually pertained to the request + if (value == Result.DECISION_DENY) { + atLeastOneDeny = true; + } + } + } + + // we didn't explicitly PERMIT, but we might have had some Rule + // been evaluated, so we have to return INDETERMINATE + if (potentialPermit) { + return firstIndeterminateResult; + } + + // some Rule said DENY, so since nothing could have permitted, + // we return DENY + if (atLeastOneDeny) { + return new Result(Result.DECISION_DENY, + context); + } + + // we didn't find anything that said DENY, but if we had a + // problem with one of the Rules, then we're INDETERMINATE + if (atLeastOneError) { + return firstIndeterminateResult; + } + + // if we hit this point, then none of the rules actually applied + // to us, so we return NOT_APPLICABLE + return new Result(Result.DECISION_NOT_APPLICABLE, + context); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombinerElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombinerElement.java new file mode 100644 index 0000000..e89bdbe --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombinerElement.java @@ -0,0 +1,167 @@ + +/* + * @(#)PolicyCombinerElement.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.Indenter; +import com.sun.xacml.Policy; +import com.sun.xacml.PolicyReference; +import com.sun.xacml.PolicySet; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.Iterator; +import java.util.List; + + +/** + * Specific version of CombinerElement used for policy combining. + * + * @since 2.0 + * @author Seth Proctor + */ +public class PolicyCombinerElement extends CombinerElement +{ + + /** + * Constructor that only takes an AbstractPolicyAbstractPolicy when combining. + * + * @param policy an AbstractPolicy to use in combining + */ + public PolicyCombinerElement(AbstractPolicy policy) { + super(policy); + } + + /** + * Constructor that takes both the AbstractPolicy to combine + * and its associated combiner parameters. + * + * @param policy an AbstractPolicy to use in combining + * @param parameters a (possibly empty) non-null List of + * CombinerParameters provided for general + * use (for all pre-2.0 policies this must be empty) + */ + public PolicyCombinerElement(AbstractPolicy policy, List parameters) { + super(policy, parameters); + } + + /** + * Returns the AbstractPolicy in this element. + * + * @return the element's AbstractPolicy + */ + public AbstractPolicy getPolicy() { + return (AbstractPolicy)(getElement()); + } + + /** + * Encodes this element's AbstractPolicy and parameters into + * their XML representation and writes this encoding to the given + * OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + if (! getParameters().isEmpty()) { + AbstractPolicy policy = getPolicy(); + + // XXX: This is ugly and happens in several places...maybe this + // should get folded into the AbstractPolicy API? + if (policy instanceof Policy) { + encodeParamaters(output, charsetName, indenter, "Policy", + policy.getId().toString()); + } else if (policy instanceof PolicySet) { + encodeParamaters(output, charsetName, indenter, "PolicySet", + policy.getId().toString()); + } else { + PolicyReference ref = (PolicyReference)policy; + if (ref.getReferenceType() + == PolicyReference.POLICY_REFERENCE) { + encodeParamaters(output, charsetName, indenter, "Policy", + ref.getReference().toString()); + } else { + encodeParamaters(output, charsetName, indenter, + "PolicySet", ref.getReference().toString()); + } + } + } + + getPolicy().encode(output, charsetName, indenter); + } + + /** + * Private helper that encodes the parameters based on the type + * + * @throws UnsupportedEncodingException + */ + private void encodeParamaters(OutputStream output, String charsetName, + Indenter indenter, String prefix, String id) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + Iterator it = getParameters().iterator(); + + out.println(indent + "<" + prefix + "CombinerParameters " + + prefix + "IdRef=\"" + id + "\">"); + indenter.in(); + + while (it.hasNext()) { + CombinerParameter param = it.next(); + param.encode(output, charsetName, indenter); + } + + out.println(indent + ""); + indenter.out(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombiningAlgorithm.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombiningAlgorithm.java new file mode 100644 index 0000000..3b4700f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/PolicyCombiningAlgorithm.java @@ -0,0 +1,93 @@ + +/* + * @(#)PolicyCombiningAlgorithm.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.List; + + +/** + * The base type for all Policy combining algorithms. Unlike in Rule + * Combining Algorithms, each policy must be matched before they're evaluated + * to make sure they apply. Also, in combining policies, obligations must be + * handled correctly. Specifically, no obligation may be included in the + * Result that doesn't match the effect being returned. So, if + * INDETERMINATE or NOT_APPLICABLE is the returned effect, no obligations + * may be included in the result. If the effect of the combining algorithm + * is PERMIT or DENY, then obligations with a matching fulfillOn effect + * are also included in the result. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + */ +public abstract class PolicyCombiningAlgorithm extends CombiningAlgorithm +{ + /** + * Constructor that takes the algorithm's identifier. + * + * @param identifier the algorithm's identifier + */ + public PolicyCombiningAlgorithm(URI identifier) { + super(identifier); + } + + /** + * Combines the policies based on the context to produce some unified + * result. This is the one function of a combining algorithm. + *

    + * Note that unlike in the RuleCombiningAlgorithms, here you must + * explicitly match the sub-policies to make sure that you should + * consider them, and you must handle Obligations. + * + * @param context the representation of the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param policyElements a List of + * CombinerElements + * + * @return a single unified result based on the combining logic + */ + public abstract Result combine(EvaluationCtx context, List parameters, + List policyElements); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombinerElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombinerElement.java new file mode 100644 index 0000000..2e00c55 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombinerElement.java @@ -0,0 +1,134 @@ + +/* + * @(#)RuleCombinerElement.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.Indenter; +import com.sun.xacml.Rule; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.Iterator; +import java.util.List; + + +/** + * Specific version of CombinerElement used for rule combining. + * + * @since 2.0 + * @author Seth Proctor + */ +public class RuleCombinerElement extends CombinerElement +{ + + /** + * Constructor that only takes a RuleRule when combining. + * + * @param rule a Rule to use in combining + */ + public RuleCombinerElement(Rule rule) { + super(rule); + } + + /** + * Constructor that takes both the Rule to combine and its + * associated combiner parameters. + * + * @param rule a Rule to use in combining + * @param parameters a (possibly empty) non-null List of + * CombinerParameters provided for general + * use (for all pre-2.0 policies this must be empty) + */ + public RuleCombinerElement(Rule rule, List parameters) { + super(rule, parameters); + } + + /** + * Returns the Rule in this element. + * + * @return the element's Rule + */ + public Rule getRule() { + return (Rule)(getElement()); + } + + /** + * Encodes this element's Rule and parameters into their + * XML representation and writes this encoding to the given + * OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + Iterator it = getParameters().iterator(); + + if (it.hasNext()) { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + while (it.hasNext()) { + CombinerParameter param = (CombinerParameter)(it.next()); + param.encode(output, charsetName, indenter); + } + + out.println(indent + ""); + indenter.out(); + } + + getRule().encode(output, charsetName, indenter); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombiningAlgorithm.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombiningAlgorithm.java new file mode 100644 index 0000000..918e054 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/RuleCombiningAlgorithm.java @@ -0,0 +1,81 @@ + +/* + * @(#)RuleCombiningAlgorithm.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.ctx.Result; + +import java.net.URI; + +import java.util.List; + + +/** + * The base type for all Rule combining algorithms. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + */ +public abstract class RuleCombiningAlgorithm extends CombiningAlgorithm +{ + + /** + * Constructor that takes the algorithm's identifier. + * + * @param identifier the algorithm's identifier + */ + public RuleCombiningAlgorithm(URI identifier) { + super(identifier); + } + + /** + * Combines the rules based on the context to produce some unified + * result. This is the one function of a combining algorithm. + * + * @param context the representation of the request + * @param parameters a (possibly empty) non-null List of + * CombinerParameters + * @param ruleElements a List of CombinerElements + * + * @return a single unified result based on the combining logic + */ + public abstract Result combine(EvaluationCtx context, List parameters, + List ruleElements); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/StandardCombiningAlgFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/StandardCombiningAlgFactory.java new file mode 100644 index 0000000..0b9d3e2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/StandardCombiningAlgFactory.java @@ -0,0 +1,209 @@ + +/* + * @(#)StandardCombiningAlgFactory.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.combine; + +import com.sun.xacml.Constants; +import com.sun.xacml.UnknownIdentifierException; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.apache.log4j.Logger; + + +/** + * This factory supports the standard set of algorithms specified in XACML + * 1.x and 2.0. It is the default factory used by the system, and imposes + * a singleton pattern insuring that there is only ever one instance of + * this class. + *

    + * Note that because this supports only the standard algorithms, this + * factory does not allow the addition of any other algorithms. If you call + * addAlgorithm on an instance of this class, an exception + * will be thrown. If you need a standard factory that is modifiable, you + * should create a new BaseCombiningAlgFactory (or some other + * CombiningAlgFactory) and configure it with the standard + * algorithms using getStandardAlgorithms (or, in the case of + * BaseAttributeFactory, by providing the datatypes in the + * constructor). + * + * @since 1.2 + * @author Seth Proctor + */ +public class StandardCombiningAlgFactory extends BaseCombiningAlgFactory +{ + + // the single factory instance + private static StandardCombiningAlgFactory factoryInstance = null; + + // the algorithms supported by this factory + private static Set supportedAlgorithms = null; + + // identifiers for the supported algorithms + private static Set supportedAlgIds; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(StandardCombiningAlgFactory.class.getName()); + + /** + * Default constructor. + */ + private StandardCombiningAlgFactory() { + super(supportedAlgorithms); + } + + /** + * Private initializer for the supported algorithms. This isn't called + * until something needs these values, and is only called once. + */ + private static void initAlgorithms() { + logger.debug("Initializing standard combining algorithms"); + + supportedAlgorithms = new HashSet(); + supportedAlgIds = new HashSet(); + + supportedAlgorithms.add(new DenyOverridesRuleAlg()); + supportedAlgIds.add(DenyOverridesRuleAlg.algId); + supportedAlgorithms.add(new DenyOverridesPolicyAlg()); + supportedAlgIds.add(DenyOverridesPolicyAlg.algId); + + supportedAlgorithms.add(new OrderedDenyOverridesRuleAlg()); + supportedAlgIds.add(OrderedDenyOverridesRuleAlg.algId); + supportedAlgorithms.add(new OrderedDenyOverridesPolicyAlg()); + supportedAlgIds.add(OrderedDenyOverridesPolicyAlg.algId); + + supportedAlgorithms.add(new PermitOverridesRuleAlg()); + supportedAlgIds.add(PermitOverridesRuleAlg.algId); + supportedAlgorithms.add(new PermitOverridesPolicyAlg()); + supportedAlgIds.add(PermitOverridesPolicyAlg.algId); + + supportedAlgorithms.add(new OrderedPermitOverridesRuleAlg()); + supportedAlgIds.add(OrderedPermitOverridesRuleAlg.algId); + supportedAlgorithms.add(new OrderedPermitOverridesPolicyAlg()); + supportedAlgIds.add(OrderedPermitOverridesPolicyAlg.algId); + + supportedAlgorithms.add(new FirstApplicableRuleAlg()); + supportedAlgIds.add(FirstApplicableRuleAlg.algId); + supportedAlgorithms.add(new FirstApplicablePolicyAlg()); + supportedAlgIds.add(FirstApplicablePolicyAlg.algId); + + supportedAlgorithms.add(new OnlyOneApplicablePolicyAlg()); + supportedAlgIds.add(OnlyOneApplicablePolicyAlg.algId); + + supportedAlgIds = Collections.unmodifiableSet(supportedAlgIds); + } + + /** + * Returns an instance of this factory. This method enforces a singleton + * model, meaning that this always returns the same instance, creating + * the factory if it hasn't been requested before. This is the default + * model used by the CombiningAlgFactory, ensuring quick + * access to this factory. + * + * @return the factory instance + */ + public static synchronized StandardCombiningAlgFactory getFactory() { + if (factoryInstance == null) { + initAlgorithms(); + factoryInstance = new StandardCombiningAlgFactory(); + } + + return factoryInstance; + } + + /** + * A convenience method that returns a new instance of a + * CombiningAlgFactory that supports all of the standard + * algorithms. The new factory allows adding support for new algorithms. + * This method should only be used when you need a new, mutable instance + * (eg, when you want to create a new factory that extends the set of + * supported algorithms). In general, you should use + * getFactory which is more efficient and enforces a + * singleton pattern. + * + * @return a new factory supporting the standard algorithms + */ + public static CombiningAlgFactory getNewFactory() { + // first we make sure everything's been initialized... + getFactory(); + + // ...then we create the new instance + return new BaseCombiningAlgFactory(supportedAlgorithms); + } + + /** + * Returns the identifiers supported for the given version of XACML. + * Because this factory supports identifiers from all versions of the + * XACML specifications, this method is useful for getting a list of + * which specific identifiers are supported by a given version of XACML. + * + * @param xacmlVersion a standard XACML identifier string, as provided + * in PolicyMetaData + * + * @return a Set of identifiers + * + * @throws UnknownIdentifierException if the version string is unknown + */ + public static Set getStandardAlgorithms(String xacmlVersion) + throws UnknownIdentifierException + { + if ((xacmlVersion.equals(Constants.XACML_1_0_IDENTIFIER)) || + (xacmlVersion.equals(Constants.XACML_2_0_IDENTIFIER)) || + (xacmlVersion.equals(Constants.XACML_3_0_IDENTIFIER))) { + return supportedAlgIds; + } + + throw new UnknownIdentifierException("Unknown XACML version: " + + xacmlVersion); + } + + /** + * Throws an UnsupportedOperationException since you are not + * allowed to modify what a standard factory supports. + * + * @param alg the combining algorithm to add + * + * @throws UnsupportedOperationException always + */ + public void addAlgorithm(CombiningAlgorithm alg) { + throw new UnsupportedOperationException("a standard factory cannot " + + "support new algorithms"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/package.html new file mode 100644 index 0000000..53f45ba --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/combine/package.html @@ -0,0 +1,7 @@ + + All of the combining algorithm support is in this package. There are + base classes that all combining algorithms need to extend, and a + factory for getting algorithms and adding new algorithms to the + system. There are also implementations of all of the standard + combining algorithms. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AbsFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AbsFunction.java new file mode 100644 index 0000000..ea532ef --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AbsFunction.java @@ -0,0 +1,168 @@ + +/* + * @(#)AbsFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-abs functions. It takes one + * operand of the appropriate type and returns the absolute value of the + * operand. If the operand is indeterminate, an indeterminate result + * is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class AbsFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-abs function. + */ + public static final String NAME_INTEGER_ABS = + FUNCTION_NS + "integer-abs"; + + /** + * Standard identifier for the double-abs function. + */ + public static final String NAME_DOUBLE_ABS = + FUNCTION_NS + "double-abs"; + + // inernal identifiers for each of the supported functions + private static final int ID_INTEGER_ABS = 0; + private static final int ID_DOUBLE_ABS = 1; + + /** + * Creates a new AbsFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is known + */ + public AbsFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 1, getArgumentType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_INTEGER_ABS)) { + return ID_INTEGER_ABS; + } else if (functionName.equals(NAME_DOUBLE_ABS)) { + return ID_DOUBLE_ABS; + } else { + throw new IllegalArgumentException("unknown abs function " + + functionName); + } + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_INTEGER_ABS)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_ABS); + set.add(NAME_DOUBLE_ABS); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // evaluate the inputs, returning any error that may occur + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the abs operation + // in the manner appropriate for the type of the arguments. + if (getFunctionId() == ID_INTEGER_ABS) { + long arg = ((IntegerAttribute) argValues[0]).getValue(); + long absValue = Math.abs(arg); + result = new EvaluationResult(new IntegerAttribute(absValue)); + } else if (getFunctionId() == ID_DOUBLE_ABS) { + double arg = ((DoubleAttribute) argValues[0]).getValue(); + double absValue = Math.abs(arg); + result = new EvaluationResult(new DoubleAttribute(absValue)); + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AddFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AddFunction.java new file mode 100644 index 0000000..ca0a593 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/AddFunction.java @@ -0,0 +1,187 @@ + +/* + * @(#)AddFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-add functions. It takes two or more + * operands of the appropriate type and returns the sum of the operands. + * If any of the operands is indeterminate, an indeterminate result is + * returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class AddFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-add function. + */ + public static final String NAME_INTEGER_ADD = + FUNCTION_NS + "integer-add"; + + /** + * Standard identifier for the double-add function. + */ + public static final String NAME_DOUBLE_ADD = + FUNCTION_NS + "double-add"; + + // inernal identifiers for each of the supported functions + private static final int ID_INTEGER_ADD = 0; + private static final int ID_DOUBLE_ADD = 1; + + /** + * Creates a new AddFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public AddFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, -1, 2, getArgumentType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_INTEGER_ADD)) { + return ID_INTEGER_ADD; + } else if (functionName.equals(NAME_DOUBLE_ADD)) { + return ID_DOUBLE_ADD; + } else { + throw new IllegalArgumentException("unknown add function " + + functionName); + } + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_INTEGER_ADD)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_ADD); + set.add(NAME_DOUBLE_ADD); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the add operation + if (getFunctionId() == ID_INTEGER_ADD) { + long sum = 0; + for (int index = 0; index < argValues.length; index++) { + long arg = ((IntegerAttribute) argValues[index]).getValue(); + sum += arg; + } + result = new EvaluationResult(new IntegerAttribute(sum)); + } else if (getFunctionId() == ID_DOUBLE_ADD) { + double sum = 0; + for (int index = 0; index < argValues.length; index++) { + double arg = + ((DoubleAttribute) argValues[index]).getValue(); + sum = sum + arg; + } + // Make it round half even, not round nearest + double lower = Math.floor(sum); + double higher = lower + 1; + //Equality test for floating point numbers that is + //resilient against errors. + if (Math.abs((sum - lower) - (higher - sum)) < .0000001) { + if ((lower % 2) == 0) { + sum = lower; + } else { + sum = higher; + } + } + result = new EvaluationResult(new DoubleAttribute(sum)); + } + + return result; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Apply.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Apply.java new file mode 100644 index 0000000..9434cbe --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Apply.java @@ -0,0 +1,459 @@ + +/* + * @(#)Apply.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the XACML ApplyType and ConditionType XML types. + *

    + * Note well: as of 2.0, there is no longer a notion of a separate higher- + * order bag function. Instead, if needed, it is supplied as one of the + * Expressions in the parameter list. As such, when this + * Apply is evaluated, it no longer pre-evaluates all the + * parameters if a bag function is used. It is now up to the implementor + * of a higher-order function to do this. + *

    + * Also, as of 2.0, the Apply is no longer used to represent + * a Condition, since the XACML 2.0 specification changed how Condition + * works. Instead, there is now a Condition class that + * represents both 1.x and 2.0 style Conditions. + * + * @since 1.0 + * @author Seth Proctor + */ +public class Apply implements Evaluatable +{ + + // the function used to evaluate the contents of the apply + private Function function; + + // the paramaters to the function...ie, the contents of the apply + private List xprs; + + private RuntimeInfo src; + + //private Logger logger = Logger.getLogger(Apply.class); + + /** + * Constructs an Apply instance. + * + * @param function the Function to use in evaluating the + * elements in the apply + * @param xprs the contents of the apply which will be the parameters + * to the function, each of which is an + * Expression + * + * @throws IllegalArgumentException if the input expressions don't + * match the signature of the function + */ + public Apply(Function function, List xprs) + throws IllegalArgumentException { + this(function, xprs, null); + } + + /** + * Constructs an Apply instance. + * + * @param function the Function to use in evaluating the + * elements in the apply + * @param xprs the contents of the apply which will be the parameters + * to the function, each of which is an + * Expression + * + * @throws IllegalArgumentException if the input expressions don't + * match the signature of the function + */ + public Apply(Function function, List xprs, RuntimeInfo src) + throws IllegalArgumentException { + // check that the given inputs work for the function + function.checkInputs(xprs, src); + + // if everything checks out, then store the inputs + this.function = function; + this.xprs = Collections.unmodifiableList(new ArrayList(xprs)); + this.src = src; + } + + /** + * Constructs an Apply instance. + * + * @deprecated As of 2.0 Apply is no longer used for + * Conditions, so the isCondition parameter + * is no longer needed. You should now use the 2 parameter + * constructor. This constructor will be removed in a + * future release. + * + * @param function the Function to use in evaluating the + * elements in the apply + * @param xprs the contents of the apply which will be the parameters + * to the function, each of which is an + * Expression + * @param isCondition as of 2.0, this must always be false + * + * @throws IllegalArgumentException if the input expressions don't + * match the signature of the function or + * if isCondition is true + */ + public Apply(Function function, List xprs, boolean isCondition) + throws IllegalArgumentException { + // make sure that no is using this constructor to create a Condition + if (isCondition) { + throw new IllegalArgumentException("As of version 2.0 an Apply" + + " may not represent a" + + " Condition"); + } + // check that the given inputs work for the function + function.checkInputs(xprs); + + // if everything checks out, then store the inputs + this.function = function; + this.xprs = Collections.unmodifiableList(new ArrayList(xprs)); + } + + /** + * Returns an instance of an Apply based on the given DOM + * root node. This will actually return a special kind of + * Apply, namely an XML ConditionType, which is the root + * of the condition logic in a RuleType. A ConditionType is the same + * as an ApplyType except that it must use a FunctionId that returns + * a boolean value. + *

    + * Note that as of 2.0 there is a separate Condition class + * used to support the different kinds of Conditions in XACML 1.x and + * 2.0. As such, the system no longer treats a ConditionType as a + * special kind of ApplyType. You may still use this method to get a + * 1.x style ConditionType, but you will need to convert it into a + * Condition to use it in evaluation. The preferred way + * to create a Condition is now through the getInstance + * method on Condition. + * + * @param root the DOM root of a ConditionType XML type + * @param xpathVersion the XPath version to use in any selectors or XPath + * functions, or null if this is unspecified (ie, not + * supplied in the defaults section of the policy) + * @param manager VariableManager used to connect references + * and definitions while parsing + * + * @return The condition instance of this Apply. + * + * @throws ParsingException if this is not a valid ConditionType + */ + public static Apply getConditionInstance(Node root, String xpathVersion, + VariableManager manager) throws ParsingException { + return getInstance(root, FunctionFactory.getConditionInstance(), + new PolicyMetaData( + Constants.XACML_1_0_IDENTIFIER, + xpathVersion), + manager); + } + + /** + * Returns an instance of an Apply based on the given DOM + * root node. This will actually return a special kind of + * Apply, namely an XML ConditionType, which is the root + * of the condition logic in a RuleType. A ConditionType is the same + * as an ApplyType except that it must use a FunctionId that returns + * a boolean value. + * + * @deprecated As of 2.0 you should avoid using this method, since it + * does not provide a Condition instance and + * does not handle XACML 2.0 policies correctly. If you need + * a similar method you can use the new version that + * accepts a VariableManager. This will return + * an Apply instance for XACML 1.x policies. + * + * @param root the DOM root of a ConditionType XML type + * @param xpathVersion the XPath version to use in any selectors or XPath + * functions, or null if this is unspecified (ie, not + * supplied in the defaults section of the policy) + * + * @return The condition instance of this Apply. + * + * @throws ParsingException if this is not a valid ConditionType + */ + public static Apply getConditionInstance(Node root, String xpathVersion) + throws ParsingException { + return getInstance(root, FunctionFactory.getConditionInstance(), + new PolicyMetaData( + Constants.XACML_1_0_IDENTIFIER, + xpathVersion), + null); + } + + /** + * Returns an instance of Apply based on the given DOM root. + * + * @param root the DOM root of an ApplyType XML type + * @param metaData the meta-data associated with the containing policy + * @param manager VariableManager used to connect references + * and definitions while parsing + * + * @return An instance of this Apply. + * + * @throws ParsingException if this is not a valid ApplyType + */ + public static Apply getInstance(Node root, PolicyMetaData metaData, + VariableManager manager) throws ParsingException { + return getInstance(root, FunctionFactory.getGeneralInstance(), + metaData, manager); + } + + /** + * This is a helper method that is called by the two getInstance + * methods. It takes a factory so we know that we're getting the right + * kind of function. + */ + private static Apply getInstance(Node root, FunctionFactory factory, + PolicyMetaData metaData, VariableManager manager) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.APPLY); + // check if this really is an Apply + if (root.getNodeType() != Node.ELEMENT_NODE + || (!root.getLocalName().equals("Apply") + && !root.getLocalName().equals("Condition"))) { + throw new ParsingException("Can't create an Apply from a " + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + Function function = + ExpressionHandler.getFunction(root, metaData, factory); + List xprs = new ArrayList(); + + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Expression xpr = ExpressionHandler. + parseExpression(nodes.item(i), metaData, manager); + + if (xpr != null) { + xprs.add(xpr); + } + } + + Apply apply = new Apply(function, xprs, src); + if ( src != null ) { + apply.src = src; + src.setXACMLObject(apply); + } + return apply; + } + + /** + * Returns the Function used by this Apply. + * + * @return the Function + */ + public Function getFunction() { + return this.function; + } + + /** + * Returns the List of children for this Apply. + * The List contains Expressions. The list is + * unmodifiable, and may be empty. + * + * @return a List of Expressions + */ + public List getChildren() { + return this.xprs; + } + + /** + * Returns whether or not this ApplyType is actually a ConditionType. As + * of 2.0 this always returns false; + * + * @deprecated As of 2.0 this method should not be used, since an + * Apply is never a Condition. + * + * @return false + */ + public boolean isCondition() { + return false; + } + + /** + * Evaluates the apply object using the given function. This will in + * turn call evaluate on all the given parameters, some of which may be + * other Apply objects. + * + * @param context the representation of the request + * + * @return the result of trying to evaluate this apply object + */ + public EvaluationResult evaluate(EvaluationCtx context) { + // Note that prior to the 2.0 codebase, this method was much more + // complex, pre-evaluating the higher-order functions. Because this + // was never really the right behavior (there's no reason that a + // function can only be at the start of an Apply), we no longer make + // assumptions at this point, so the higher order functions are + // left to evaluate their own parameters. + context.newEvent(this); + + //set (context dependent) source locator for function + RuntimeInfo funcSrc = null; + if ( src != null ) { + funcSrc = src.getIndirectRuntimeInfo(function, ELEMENT_TYPE.FUNCTION); + this.function.setRuntimeInfo(funcSrc); + } + + EvaluationResult result = this.function.evaluate(this.xprs, context); + //unset source locator + if ( funcSrc != null ) { + this.function.unsetRuntimeInfo(funcSrc) ; + } + context.closeCurrentEvent(result); + return result; + } + + /** + * Returns the type of attribute that this object will return on a call + * to evaluate. In practice, this will always be the same as + * the result of calling getReturnType on the function used + * by this object. + * + * @return the type returned by evaluate + */ + public URI getType() { + return this.function.getReturnType(); + } + + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + /** + * Returns whether or not the Function will return a bag + * of values on evaluation. + * + * @return true if evaluation will return a bag of values, false otherwise + */ + public boolean returnsBag() { + return this.function.returnsBag(); + } + + /** + * Returns whether or not the Function will return a bag + * of values on evaluation. + * + * + * @deprecated As of 2.0, you should use the returnsBag + * method from the super-interface Expression. + * + * @return true if evaluation will return a bag of values, false otherwise + */ + public boolean evaluatesToBag() { + return this.function.returnsBag(); + } + + + /** + * Encodes this Apply into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Apply into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + Iterator it = this.xprs.iterator(); + while (it.hasNext()) { + Expression xpr = (Expression)(it.next()); + xpr.encode(output, charsetName, indenter); + } + + indenter.out(); + out.println(indent + ""); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BagFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BagFunction.java new file mode 100644 index 0000000..b80070d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BagFunction.java @@ -0,0 +1,289 @@ + +/* + * @(#)BagFunction.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.Base64BinaryAttribute; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DayTimeDurationAttribute; +import com.sun.xacml.attr.DNSNameAttribute; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.HexBinaryAttribute; +import com.sun.xacml.attr.IntegerAttribute; +import com.sun.xacml.attr.IPAddressAttribute; +import com.sun.xacml.attr.RFC822NameAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TimeAttribute; +import com.sun.xacml.attr.X500NameAttribute; +import com.sun.xacml.attr.YearMonthDurationAttribute; + +import java.util.HashSet; +import java.util.Set; + + +/** + * Represents all of the Bag functions, though the actual implementations + * are in two sub-classes specific to the condition and general bag + * functions. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class BagFunction extends FunctionBase +{ + + /** + * Base name for the type-one-and-only funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_ONE_AND_ONLY. + */ + public static final String NAME_BASE_ONE_AND_ONLY = + "-one-and-only"; + + /** + * Base name for the type-bag-size funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_BAG_SIZE. + */ + public static final String NAME_BASE_BAG_SIZE = + "-bag-size"; + + /** + * Base name for the type-is-in. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_IS_IN. + */ + public static final String NAME_BASE_IS_IN = + "-is-in"; + + /** + * Base name for the type-bag funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_BAG. + */ + public static final String NAME_BASE_BAG = + "-bag"; + + // bag parameter info for the functions that accept multiple args + private static final boolean bagParams [] = { false, true }; + + /** + * A complete list of all the XACML 1.x datatypes supported by the Bag + * functions + */ + protected final static String baseTypes [] = { + StringAttribute.identifier, + BooleanAttribute.identifier, + IntegerAttribute.identifier, + DoubleAttribute.identifier, + DateAttribute.identifier, + DateTimeAttribute.identifier, + TimeAttribute.identifier, + AnyURIAttribute.identifier, + HexBinaryAttribute.identifier, + Base64BinaryAttribute.identifier, + DayTimeDurationAttribute.identifier, + YearMonthDurationAttribute.identifier, + X500NameAttribute.identifier, + RFC822NameAttribute.identifier + }; + + /** + * A complete list of all the XACML 2.0 datatypes newly supported by the + * Bag functions + */ + protected static final String baseTypes2 [] = { + IPAddressAttribute.identifier, + DNSNameAttribute.identifier + }; + + /** + * A complete list of all the 1.x XACML datatypes supported by the + * Bag functions, using the "simple" form of the names (eg, string + * instead of http://www.w3.org/2001/XMLSchema#string) + */ + protected static final String simpleTypes [] = { + "string", "boolean", "integer", "double", "date", "dateTime", + "time", "anyURI", "hexBinary", "base64Binary", "dayTimeDuration", + "yearMonthDuration", "x500Name", "rfc822Name" + }; + + /** + * A complete list of all the 2.0 XACML datatypes newly supported by the + * Bag functions, using the "simple" form of the names (eg, string + * instead of http://www.w3.org/2001/XMLSchema#string) + */ + protected static final String simpleTypes2 [] = { + "ipAddress", "dnsName" + }; + + /** + * Returns a new BagFunction that provides the + * type-one-and-only functionality over the given attribute type. + * This should be used to create new function instances for any new + * attribute types, and the resulting object should be put into + * the FunctionFactory (instances already exist in the + * factory for the standard attribute types). + * + * @param functionName the name to use for the function + * @param argumentType the type to operate on + * + * @return a new BagFunction + */ + public static BagFunction getOneAndOnlyInstance(String functionName, + String argumentType) { + return new GeneralBagFunction(functionName, argumentType, + NAME_BASE_ONE_AND_ONLY); + } + + /** + * Returns a new BagFunction that provides the + * type-bag-size functionality over the given attribute type. This + * should be used to create new function instances for any new + * attribute types, and the resulting object should be put into + * the FunctionFactory (instances already exist in the + * factory for the standard attribute types). + * + * @param functionName the name to use for the function + * @param argumentType the type to operate on + * + * @return a new BagFunction + */ + public static BagFunction getBagSizeInstance(String functionName, + String argumentType) { + return new GeneralBagFunction(functionName, argumentType, + NAME_BASE_BAG_SIZE); + } + + /** + * Returns a new BagFunction that provides the + * type-is-in functionality over the given attribute type. This + * should be used to create new function instances for any new + * attribute types, and the resulting object should be put into + * the FunctionFactory (instances already exist in the + * factory for the standard attribute types). + * + * @param functionName the name to use for the function + * @param argumentType the type to operate on + * + * @return a new BagFunction + */ + public static BagFunction getIsInInstance(String functionName, + String argumentType) { + return new ConditionBagFunction(functionName, argumentType); + } + + /** + * Returns a new BagFunction that provides the + * type-bag functionality over the given attribute type. This + * should be used to create new function instances for any new + * attribute types, and the resulting object should be put into + * the FunctionFactory (instances already exist in the + * factory for the standard attribute types). + * + * @param functionName the name to use for the function + * @param argumentType the type to operate on + * + * @return a new BagFunction + */ + public static BagFunction getBagInstance(String functionName, + String argumentType) { + return new GeneralBagFunction(functionName, argumentType, + NAME_BASE_BAG); + } + + /** + * Protected constuctor used by the general and condition subclasses + * to create a non-boolean function with parameters of the same datatype. + * If you need to create a new BagFunction instance you + * should either use one of the getInstance methods or + * construct one of the sub-classes directly. + * + * @param functionName the identitifer for the function + * @param functionId an optional, internal numeric identifier + * @param paramType the datatype this function accepts + * @param paramIsBag whether the parameters are bags + * @param numParams number of parameters allowed or -1 for any number + * @param returnType the datatype this function returns + * @param returnsBag whether this function returns bags + */ + protected BagFunction(String functionName, int functionId, + String paramType, boolean paramIsBag, int numParams, + String returnType, boolean returnsBag) { + super(functionName, functionId, paramType, paramIsBag, numParams, + returnType, returnsBag); + } + + /** + * Protected constuctor used by the general and condition subclasses + * to create a boolean function with parameters of different datatypes. + * If you need to create a new BagFunction instance you + * should either use one of the getInstance methods or + * construct one of the sub-classes directly. + * + * @param functionName the identitifer for the function + * @param functionId an optional, internal numeric identifier + * @param paramTypes the datatype of each parameter + */ + protected BagFunction(String functionName, int functionId, + String [] paramTypes) { + super(functionName, functionId, paramTypes, bagParams, + BooleanAttribute.identifier, false); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.addAll(ConditionBagFunction.getSupportedIdentifiers()); + set.addAll(GeneralBagFunction.getSupportedIdentifiers()); + + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BaseFunctionFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BaseFunctionFactory.java new file mode 100644 index 0000000..e5146d2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BaseFunctionFactory.java @@ -0,0 +1,418 @@ + +/* + * @(#)BaseCombiningAlgFactory.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; + +import java.net.URI; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * This is a basic implementation of FunctionFactory. It + * implements the insertion and retrieval methods, but it doesn't actually + * setup the factory with any functions. It also assumes a certain model + * with regard to the different kinds of functions (Target, Condition, and + * General). For this reason, you may want to re-use this class, or you + * may want to extend FunctionFactory directly, if you're writing a new + * factory implementation. + *

    + * Note that while this class is thread-safe on all creation methods, it + * is not safe to add support for a new function while creating an instance + * of a function. This follows from the assumption that most people will + * initialize these factories up-front, and then start processing without + * ever modifying the factories. If you need these mutual operations to + * be thread-safe, then you should write a wrapper class that implements + * the right synchronization. + * + * @since 1.2 + * @author Seth Proctor + */ +public class BaseFunctionFactory extends FunctionFactory +{ + + // the backing maps for the Function objects or FunctionProxy objects + private HashMap functionMap = null; + + // the superset factory chained to this factory + private FunctionFactory superset = null; + + /** + * Default constructor. No superset factory is used. + */ + public BaseFunctionFactory() { + this(null); + } + + /** + * Constructor that sets a "superset factory". This is useful since + * the different function factories (Target, Condition, and General) + * have a superset relationship (Condition functions are a superset + * of Target functions, etc.). Adding a function to this factory will + * automatically add the same function to the superset factory. + * + * @param superset the superset factory or null + */ + public BaseFunctionFactory(FunctionFactory superset) { + this.functionMap = new HashMap(); + + this.superset = superset; + } + + /** + * Constructor that defines the initial functions supported by this + * factory but doesn't use a superset factory. + * + * @param supportedFunctions a Set of Functions + * @param supportedAbstractFunctions a mapping from URI to + * FunctionProxy + */ + public BaseFunctionFactory(Set supportedFunctions, + Map supportedAbstractFunctions) { + this(null, supportedFunctions, supportedAbstractFunctions); + } + + /** + * Constructor that defines the initial functions supported by this + * factory and uses a superset factory. Note that the functions + * supplied here are not propagated up to the superset factory, so + * you must either make sure the superst factory is correctly + * initialized or use BaseFunctionFactory(FunctionFactory) + * and then manually add each function. + * + * @param superset the superset factory or null + * @param supportedFunctions a Set of Functions + * @param supportedAbstractFunctions a mapping from URI to + * FunctionProxy + */ + public BaseFunctionFactory(FunctionFactory superset, + Set supportedFunctions, + Map supportedAbstractFunctions) { + this(superset); + + Iterator it = supportedFunctions.iterator(); + while (it.hasNext()) { + Function function = it.next(); + this.functionMap.put(function.getIdentifier().toString(), + function); + } + + Iterator> it2 = supportedAbstractFunctions.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it2.next(); + URI id = (URI)(entry.getKey()); + FunctionProxy proxy = + (FunctionProxy)(entry.getValue()); + this.functionMap.put(id.toString(), proxy); + } + } + + /** + * Adds the function to the factory. Most functions have no state, so + * the singleton model used here is typically desireable. The factory will + * not enforce the requirement that a Target or Condition matching function + * must be boolean. If a function is already contained in the factory, an + * error will be thrown. + * + * @param function the Function to add to the factory + * + * @throws IllegalArgumentException if the function's identifier is already + * used or if the function is non-boolean + * (when this is a Target or Condition + * factory) + */ + public void addFunction(Function function) + throws IllegalArgumentException + { + addFunction(function, false); + } + + /** + * Adds the function to the factory. Most functions have no state, so + * the singleton model used here is typically desireable. The factory will + * not enforce the requirement that a Target or Condition matching function + * must be boolean. + * + * Allows to define if an already existing function should be overwritten + * or not. + * + * * @param function the Function to add to the factory + * + * @throws IllegalArgumentException if the function's identifier is already + * used or if the function is non-boolean + * (when this is a Target or Condition + * factory) + */ + @Override + public void addFunction(Function function, boolean overwrite) + throws IllegalArgumentException { + + String id = function.getIdentifier().toString(); + + // make sure this doesn't already exist + if (! overwrite && this.functionMap.containsKey(id)) { + throw new IllegalArgumentException("function already exists"); + } + + // add to the superset factory + if (this.superset != null) { + this.superset.addFunction(function); + } + + // finally, add to this factory + this.functionMap.put(id, function); + + } + + /** + * Adds the abstract function proxy to the factory. This is used for + * those functions which have state, or change behavior (for instance + * the standard map function, which changes its return type based on + * how it is used). + * + * @param proxy the FunctionProxy to add to the factory + * @param identity the function's identifier + * + * @throws IllegalArgumentException if the function's identifier is already + * used + */ + public void addAbstractFunction(FunctionProxy proxy, + URI identity) + throws IllegalArgumentException + { + String id = identity.toString(); + + // make sure this doesn't already exist + if (this.functionMap.containsKey(id)) { + throw new IllegalArgumentException("function already exists"); + } + // add to the superset factory + if (this.superset != null) { + this.superset.addAbstractFunction(proxy, identity); + } + // finally, add to this factory + this.functionMap.put(id, proxy); + } + + /** + * Returns the function identifiers supported by this factory. + * + * @return a Set of Strings + */ + public Set getSupportedFunctions() { + Set set = new HashSet(this.functionMap.keySet()); + + if (this.superset != null) { + set.addAll(this.superset.getSupportedFunctions()); + } + return set; + } + + /** + * Tries to get an instance of the specified function. + * + * @param identity the name of the function + * + * @return The function. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to an + * abstract function, and should therefore + * be created through createAbstractFunction + */ + public Function createFunction(URI identity) + throws UnknownIdentifierException, FunctionTypeException + { + return createFunction(identity.toString()); + } + + /** + * Tries to get an instance of the specified function. + * + * @param identity the name of the function + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to an + * abstract function, and should therefore + * be created through createAbstractFunction + * + * @return The function. + */ + public Function createFunction(String identity) + throws UnknownIdentifierException, FunctionTypeException + { + Object entry = this.functionMap.get(identity); + + if (entry != null) { + if (entry instanceof Function) { + return (Function)entry; + } + // this is actually a proxy, which means the other create + // method should have been called + throw new FunctionTypeException("function is abstract"); + } + // we couldn't find a match + throw new UnknownIdentifierException("functions of type " + + identity + " are not supported by this factory"); + } + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * + * @return The function. + * + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public Function createAbstractFunction(URI identity, Node root) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException + { + return createAbstractFunction(identity.toString(), root, null); + } + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * @param xpathVersion the version specified in the contianing policy, or + * null if no version was specified + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * + * @return The function. + * + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public Function createAbstractFunction(URI identity, Node root, + String xpathVersion) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException + { + return createAbstractFunction(identity.toString(), root, xpathVersion); + } + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * + * @return The function. + * + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public Function createAbstractFunction(String identity, Node root) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException + { + return createAbstractFunction(identity, root, null); + } + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * @param xpathVersion the version specified in the contianing policy, or + * null if no version was specified + * + * @return The function. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public Function createAbstractFunction(String identity, Node root, + String xpathVersion) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException { + Object entry = this.functionMap.get(identity); + + if (entry != null) { + if (entry instanceof FunctionProxy) { + try { + return ((FunctionProxy)entry).getInstance(root, + xpathVersion); + } catch (Exception e) { + throw new ParsingException("couldn't create abstract" + + " function " + identity, e); + } + } + // this is actually a concrete function, which means that + // the other create method should have been called + throw new FunctionTypeException("function is concrete"); + } + // we couldn't find a match + throw new UnknownIdentifierException("abstract functions of " + + "type " + identity + + " are not supported by " + + "this factory"); + } + + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BasicFunctionFactoryProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BasicFunctionFactoryProxy.java new file mode 100644 index 0000000..17a64fb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/BasicFunctionFactoryProxy.java @@ -0,0 +1,81 @@ + +/* + * @(#)BasicFunctionFactoryProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + + +/** + * A simple utility class that manages triples of function factories. + * + * @since 1.2 + * @author Seth Proctor + */ +public class BasicFunctionFactoryProxy implements FunctionFactoryProxy +{ + + // the triple of factories + private FunctionFactory targetFactory; + private FunctionFactory conditionFactory; + private FunctionFactory generalFactory; + + /** + * Creates a new proxy. + * + * @param targetFactory the target factory provided by this proxy + * @param conditionFactory the target condition provided by this proxy + * @param generalFactory the general factory provided by this proxy + */ + public BasicFunctionFactoryProxy(FunctionFactory targetFactory, + FunctionFactory conditionFactory, + FunctionFactory generalFactory) { + this.targetFactory = targetFactory; + this.conditionFactory = conditionFactory; + this.generalFactory = generalFactory; + } + + public FunctionFactory getTargetFactory() { + return this.targetFactory; + } + + public FunctionFactory getConditionFactory() { + return this.conditionFactory; + } + + public FunctionFactory getGeneralFactory() { + return this.generalFactory; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ComparisonFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ComparisonFunction.java new file mode 100644 index 0000000..feba8cb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ComparisonFunction.java @@ -0,0 +1,711 @@ + +/* + * @(#)ComparisonFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TimeAttribute; + +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all of the standard comparison functions. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class ComparisonFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-greater-than function. + */ + public static final String NAME_INTEGER_GREATER_THAN = + FUNCTION_NS + "integer-greater-than"; + + /** + * Standard identifier for the integer-greater-than-or-equal function. + */ + public static final String NAME_INTEGER_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "integer-greater-than-or-equal"; + + /** + * Standard identifier for the integer-less-than function. + */ + public static final String NAME_INTEGER_LESS_THAN = + FUNCTION_NS + "integer-less-than"; + + /** + * Standard identifier for the integer-less-than-or-equal function. + */ + public static final String NAME_INTEGER_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "integer-less-than-or-equal"; + + + /** + * Standard identifier for the double-greater-than function. + */ + public static final String NAME_DOUBLE_GREATER_THAN = + FUNCTION_NS + "double-greater-than"; + + /** + * Standard identifier for the double-greater-than-or-equal function. + */ + public static final String NAME_DOUBLE_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "double-greater-than-or-equal"; + + /** + * Standard identifier for the double-less-than function. + */ + public static final String NAME_DOUBLE_LESS_THAN = + FUNCTION_NS + "double-less-than"; + + /** + * Standard identifier for the double-less-than-or-equal function. + */ + public static final String NAME_DOUBLE_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "double-less-than-or-equal"; + + + /** + * Standard identifier for the string-greater-than function. + */ + public static final String NAME_STRING_GREATER_THAN = + FUNCTION_NS + "string-greater-than"; + + /** + * Standard identifier for the string-greater-than-or-equal function. + */ + public static final String NAME_STRING_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "string-greater-than-or-equal"; + + /** + * Standard identifier for the string-less-than function. + */ + public static final String NAME_STRING_LESS_THAN = + FUNCTION_NS + "string-less-than"; + + /** + * Standard identifier for the string-less-than-or-equal function. + */ + public static final String NAME_STRING_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "string-less-than-or-equal"; + + + /** + * Standard identifier for the time-greater-than function. + */ + public static final String NAME_TIME_GREATER_THAN = + FUNCTION_NS + "time-greater-than"; + + /** + * Standard identifier for the time-greater-than-or-equal function. + */ + public static final String NAME_TIME_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "time-greater-than-or-equal"; + + /** + * Standard identifier for the time-less-than function. + */ + public static final String NAME_TIME_LESS_THAN = + FUNCTION_NS + "time-less-than"; + + /** + * Standard identifier for the time-less-than-or-equal function. + */ + public static final String NAME_TIME_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "time-less-than-or-equal"; + + + /** + * Standard identifier for the dateTime-greater-than function. + */ + public static final String NAME_DATETIME_GREATER_THAN = + FUNCTION_NS + "dateTime-greater-than"; + + /** + * Standard identifier for the dateTime-greater-than-or-equal function. + */ + public static final String NAME_DATETIME_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "dateTime-greater-than-or-equal"; + + /** + * Standard identifier for the dateTime-less-than function. + */ + public static final String NAME_DATETIME_LESS_THAN = + FUNCTION_NS + "dateTime-less-than"; + + /** + * Standard identifier for the dateTime-less-than-or-equal function. + */ + public static final String NAME_DATETIME_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "dateTime-less-than-or-equal"; + + + /** + * Standard identifier for the date-greater-than function. + */ + public static final String NAME_DATE_GREATER_THAN = + FUNCTION_NS + "date-greater-than"; + + /** + * Standard identifier for the date-greater-than-or-equal function. + */ + public static final String NAME_DATE_GREATER_THAN_OR_EQUAL = + FUNCTION_NS + "date-greater-than-or-equal"; + + /** + * Standard identifier for the date-less-than function. + */ + public static final String NAME_DATE_LESS_THAN = + FUNCTION_NS + "date-less-than"; + + /** + * Standard identifier for the date-less-than-or-equal function. + */ + public static final String NAME_DATE_LESS_THAN_OR_EQUAL = + FUNCTION_NS + "date-less-than-or-equal"; + + // private identifiers for the supported functions + private static final int ID_INTEGER_GREATER_THAN = 0; + private static final int ID_INTEGER_GREATER_THAN_OR_EQUAL = 1; + private static final int ID_INTEGER_LESS_THAN = 2; + private static final int ID_INTEGER_LESS_THAN_OR_EQUAL = 3; + private static final int ID_DOUBLE_GREATER_THAN = 4; + private static final int ID_DOUBLE_GREATER_THAN_OR_EQUAL = 5; + private static final int ID_DOUBLE_LESS_THAN = 6; + private static final int ID_DOUBLE_LESS_THAN_OR_EQUAL = 7; + private static final int ID_STRING_GREATER_THAN = 8; + private static final int ID_STRING_GREATER_THAN_OR_EQUAL = 9; + private static final int ID_STRING_LESS_THAN = 10; + private static final int ID_STRING_LESS_THAN_OR_EQUAL = 11; + private static final int ID_TIME_GREATER_THAN = 12; + private static final int ID_TIME_GREATER_THAN_OR_EQUAL = 13; + private static final int ID_TIME_LESS_THAN = 14; + private static final int ID_TIME_LESS_THAN_OR_EQUAL = 15; + private static final int ID_DATE_GREATER_THAN = 16; + private static final int ID_DATE_GREATER_THAN_OR_EQUAL = 17; + private static final int ID_DATE_LESS_THAN = 18; + private static final int ID_DATE_LESS_THAN_OR_EQUAL = 19; + private static final int ID_DATETIME_GREATER_THAN = 20; + private static final int ID_DATETIME_GREATER_THAN_OR_EQUAL = 21; + private static final int ID_DATETIME_LESS_THAN = 22; + private static final int ID_DATETIME_LESS_THAN_OR_EQUAL = 23; + + // mappings from name to private identifier and argument datatype + private static HashMap idMap; + private static HashMap typeMap; + + /** + * Static initializer to setup the two maps. + */ + static { + idMap = new HashMap(); + + idMap.put(NAME_INTEGER_GREATER_THAN, + Integer.valueOf(ID_INTEGER_GREATER_THAN)); + idMap.put(NAME_INTEGER_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_INTEGER_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_INTEGER_LESS_THAN, + Integer.valueOf(ID_INTEGER_LESS_THAN)); + idMap.put(NAME_INTEGER_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_INTEGER_LESS_THAN_OR_EQUAL)); + idMap.put(NAME_DOUBLE_GREATER_THAN, + Integer.valueOf(ID_DOUBLE_GREATER_THAN)); + idMap.put(NAME_DOUBLE_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_DOUBLE_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_DOUBLE_LESS_THAN, + Integer.valueOf(ID_DOUBLE_LESS_THAN)); + idMap.put(NAME_DOUBLE_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_DOUBLE_LESS_THAN_OR_EQUAL)); + idMap.put(NAME_STRING_GREATER_THAN, + Integer.valueOf(ID_STRING_GREATER_THAN)); + idMap.put(NAME_STRING_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_STRING_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_STRING_LESS_THAN, + Integer.valueOf(ID_STRING_LESS_THAN)); + idMap.put(NAME_STRING_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_STRING_LESS_THAN_OR_EQUAL)); + idMap.put(NAME_TIME_GREATER_THAN, + Integer.valueOf(ID_TIME_GREATER_THAN)); + idMap.put(NAME_TIME_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_TIME_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_TIME_LESS_THAN, + Integer.valueOf(ID_TIME_LESS_THAN)); + idMap.put(NAME_TIME_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_TIME_LESS_THAN_OR_EQUAL)); + idMap.put(NAME_DATE_GREATER_THAN, + Integer.valueOf(ID_DATE_GREATER_THAN)); + idMap.put(NAME_DATE_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_DATE_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_DATE_LESS_THAN, + Integer.valueOf(ID_DATE_LESS_THAN)); + idMap.put(NAME_DATE_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_DATE_LESS_THAN_OR_EQUAL)); + idMap.put(NAME_DATETIME_GREATER_THAN, + Integer.valueOf(ID_DATETIME_GREATER_THAN)); + idMap.put(NAME_DATETIME_GREATER_THAN_OR_EQUAL, + Integer.valueOf(ID_DATETIME_GREATER_THAN_OR_EQUAL)); + idMap.put(NAME_DATETIME_LESS_THAN, + Integer.valueOf(ID_DATETIME_LESS_THAN)); + idMap.put(NAME_DATETIME_LESS_THAN_OR_EQUAL, + Integer.valueOf(ID_DATETIME_LESS_THAN_OR_EQUAL)); + + typeMap = new HashMap(); + + typeMap.put(NAME_INTEGER_GREATER_THAN, IntegerAttribute.identifier); + typeMap.put(NAME_INTEGER_GREATER_THAN_OR_EQUAL, + IntegerAttribute.identifier); + typeMap.put(NAME_INTEGER_LESS_THAN, IntegerAttribute.identifier); + typeMap.put(NAME_INTEGER_LESS_THAN_OR_EQUAL, + IntegerAttribute.identifier); + typeMap.put(NAME_DOUBLE_GREATER_THAN, DoubleAttribute.identifier); + typeMap.put(NAME_DOUBLE_GREATER_THAN_OR_EQUAL, + DoubleAttribute.identifier); + typeMap.put(NAME_DOUBLE_LESS_THAN, DoubleAttribute.identifier); + typeMap.put(NAME_DOUBLE_LESS_THAN_OR_EQUAL, + DoubleAttribute.identifier); + typeMap.put(NAME_STRING_GREATER_THAN, StringAttribute.identifier); + typeMap.put(NAME_STRING_GREATER_THAN_OR_EQUAL, + StringAttribute.identifier); + typeMap.put(NAME_STRING_LESS_THAN, StringAttribute.identifier); + typeMap.put(NAME_STRING_LESS_THAN_OR_EQUAL, + StringAttribute.identifier); + typeMap.put(NAME_TIME_GREATER_THAN, TimeAttribute.identifier); + typeMap.put(NAME_TIME_GREATER_THAN_OR_EQUAL, TimeAttribute.identifier); + typeMap.put(NAME_TIME_LESS_THAN, TimeAttribute.identifier); + typeMap.put(NAME_TIME_LESS_THAN_OR_EQUAL, TimeAttribute.identifier); + typeMap.put(NAME_DATETIME_GREATER_THAN, DateTimeAttribute.identifier); + typeMap.put(NAME_DATETIME_GREATER_THAN_OR_EQUAL, + DateTimeAttribute.identifier); + typeMap.put(NAME_DATETIME_LESS_THAN, DateTimeAttribute.identifier); + typeMap.put(NAME_DATETIME_LESS_THAN_OR_EQUAL, + DateTimeAttribute.identifier); + typeMap.put(NAME_DATE_GREATER_THAN, DateAttribute.identifier); + typeMap.put(NAME_DATE_GREATER_THAN_OR_EQUAL, DateAttribute.identifier); + typeMap.put(NAME_DATE_LESS_THAN, DateAttribute.identifier); + typeMap.put(NAME_DATE_LESS_THAN_OR_EQUAL, DateAttribute.identifier); + } + + /** + * Creates a new ComparisonFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function isn't known + */ + public ComparisonFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 2, BooleanAttribute.identifier, false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + Integer i = (Integer)(idMap.get(functionName)); + + if (i == null) { + throw new IllegalArgumentException("unknown comparison function " + + functionName); + } + return i.intValue(); + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + return (String)(typeMap.get(functionName)); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(idMap.keySet()); + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue [inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have real values, perform the comparison operation + + boolean boolResult = false; + + switch (getFunctionId()) { + + case ID_INTEGER_GREATER_THAN: { + long arg0 = ((IntegerAttribute)(argValues[0])).getValue(); + long arg1 = ((IntegerAttribute)(argValues[1])).getValue(); + + boolResult = (arg0 > arg1); + + break; + } + + case ID_INTEGER_GREATER_THAN_OR_EQUAL: { + long arg0 = ((IntegerAttribute)(argValues[0])).getValue(); + long arg1 = ((IntegerAttribute)(argValues[1])).getValue(); + + boolResult = (arg0 >= arg1); + + break; + } + + case ID_INTEGER_LESS_THAN: { + long arg0 = ((IntegerAttribute)(argValues[0])).getValue(); + long arg1 = ((IntegerAttribute)(argValues[1])).getValue(); + + boolResult = (arg0 < arg1); + + break; + } + + case ID_INTEGER_LESS_THAN_OR_EQUAL: { + long arg0 = ((IntegerAttribute)(argValues[0])).getValue(); + long arg1 = ((IntegerAttribute)(argValues[1])).getValue(); + + boolResult = (arg0 <= arg1); + + break; + } + + case ID_DOUBLE_GREATER_THAN: { + double arg0 = ((DoubleAttribute)(argValues[0])).getValue(); + double arg1 = ((DoubleAttribute)(argValues[1])).getValue(); + + boolResult = (doubleCompare(arg0, arg1) > 0); + + break; + } + + case ID_DOUBLE_GREATER_THAN_OR_EQUAL: { + double arg0 = ((DoubleAttribute)(argValues[0])).getValue(); + double arg1 = ((DoubleAttribute)(argValues[1])).getValue(); + + boolResult = (doubleCompare(arg0, arg1) >= 0); + + break; + } + + case ID_DOUBLE_LESS_THAN: { + double arg0 = ((DoubleAttribute)(argValues[0])).getValue(); + double arg1 = ((DoubleAttribute)(argValues[1])).getValue(); + + boolResult = (doubleCompare(arg0, arg1) < 0); + + break; + } + + case ID_DOUBLE_LESS_THAN_OR_EQUAL: { + double arg0 = ((DoubleAttribute)(argValues[0])).getValue(); + double arg1 = ((DoubleAttribute)(argValues[1])).getValue(); + + boolResult = (doubleCompare(arg0, arg1) <= 0); + + break; + } + + case ID_STRING_GREATER_THAN: { + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((StringAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) > 0); + + break; + } + + case ID_STRING_GREATER_THAN_OR_EQUAL: { + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((StringAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) >= 0); + + break; + } + + case ID_STRING_LESS_THAN: { + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((StringAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) < 0); + + break; + } + + case ID_STRING_LESS_THAN_OR_EQUAL: { + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((StringAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) <= 0); + + break; + } + + case ID_TIME_GREATER_THAN: { + TimeAttribute arg0 = (TimeAttribute)(argValues[0]); + TimeAttribute arg1 = (TimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) > 0); + + break; + } + + case ID_TIME_GREATER_THAN_OR_EQUAL: { + TimeAttribute arg0 = (TimeAttribute)(argValues[0]); + TimeAttribute arg1 = (TimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) >= 0); + + break; + } + + case ID_TIME_LESS_THAN: { + TimeAttribute arg0 = (TimeAttribute)(argValues[0]); + TimeAttribute arg1 = (TimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) < 0); + + break; + } + + case ID_TIME_LESS_THAN_OR_EQUAL: { + TimeAttribute arg0 = (TimeAttribute)(argValues[0]); + TimeAttribute arg1 = (TimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) <= 0); + + break; + } + + case ID_DATETIME_GREATER_THAN: { + DateTimeAttribute arg0 = (DateTimeAttribute)(argValues[0]); + DateTimeAttribute arg1 = (DateTimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) > 0); + + break; + } + + case ID_DATETIME_GREATER_THAN_OR_EQUAL: { + DateTimeAttribute arg0 = (DateTimeAttribute)(argValues[0]); + DateTimeAttribute arg1 = (DateTimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) >= 0); + + break; + } + + case ID_DATETIME_LESS_THAN: { + DateTimeAttribute arg0 = (DateTimeAttribute)(argValues[0]); + DateTimeAttribute arg1 = (DateTimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) < 0); + + break; + } + + case ID_DATETIME_LESS_THAN_OR_EQUAL: { + DateTimeAttribute arg0 = (DateTimeAttribute)(argValues[0]); + DateTimeAttribute arg1 = (DateTimeAttribute)(argValues[1]); + + boolResult = + (dateCompare(arg0.getValue(), arg0.getNanoseconds(), + arg1.getValue(), arg1.getNanoseconds()) <= 0); + + break; + } + + case ID_DATE_GREATER_THAN: { + Date arg0 = ((DateAttribute)(argValues[0])).getValue(); + Date arg1 = ((DateAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) > 0); + + break; + } + + case ID_DATE_GREATER_THAN_OR_EQUAL: { + Date arg0 = ((DateAttribute)(argValues[0])).getValue(); + Date arg1 = ((DateAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) >= 0); + + break; + } + + case ID_DATE_LESS_THAN: { + Date arg0 = ((DateAttribute)(argValues[0])).getValue(); + Date arg1 = ((DateAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) < 0); + + break; + } + + case ID_DATE_LESS_THAN_OR_EQUAL: { + Date arg0 = ((DateAttribute)(argValues[0])).getValue(); + Date arg1 = ((DateAttribute)(argValues[1])).getValue(); + + boolResult = (arg0.compareTo(arg1) <= 0); + + break; + } + + } + + // Return the result as a BooleanAttribute. + return EvaluationResult.getInstance(boolResult); + } + + /** + * Helper function that does a comparison of the two doubles using the + * rules of XMLSchema. Like all compare methods, this returns 0 if they're + * equal, a positive value if d1 > d2, and a negative value if d1 < d2. + */ + private int doubleCompare(double d1, double d2) { + // see if the numbers equal each other + if (d1 == d2) { + // these are not NaNs, and therefore we just need to check that + // that they're not zeros, which may have different signs + if (d1 != 0) { + return 0; + } + + // they're both zeros, so we compare strings to figure out + // the significance of any signs + return Double.toString(d1).compareTo(Double.toString(d2)); + } + + // see if d1 is NaN + if (Double.isNaN(d1)) { + // d1 is NaN, so see if d2 is as well + if (Double.isNaN(d2)) { + // they're both NaNs, so they're equal + return 0; + } + // d1 is always bigger than d2 since it's a NaN + return 1; + } + + // see if d2 is NaN + if (Double.isNaN(d2)) { + // d2 is a NaN, though d1 isn't, so d2 is always bigger + return -1; + } + + // if we got here then neither is a NaN, and the numbers aren't + // equal...given those facts, basic comparison works the same in + // java as it's defined in XMLSchema, so now we can do the simple + // comparison and return whatever we find + return ((d1 > d2) ? 1 : -1); + } + + /** + * Helper function to compare two Date objects and their associated + * nanosecond values. Like all compare methods, this returns 0 if they're + * equal, a positive value if d1 > d2, and a negative value if d1 < d2. + */ + private int dateCompare(Date d1, int n1, Date d2, int n2) { + int compareResult = d1.compareTo(d2); + + // we only worry about the nanosecond values if the Dates are equal + if (compareResult != 0) { + return compareResult; + } + + // see if there's any difference + if (n1 == n2) { + return 0; + } + + // there is some difference in the nanoseconds, and that's how + // we'll determine the comparison + return ((n1 > n2) ? 1 : -1); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Condition.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Condition.java new file mode 100644 index 0000000..f644700 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Condition.java @@ -0,0 +1,409 @@ + +/* + * @(#)Condition.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the XACML ConditionType type. It contains exactly one child + * expression that is boolean and returns a single value. This class was + * added in XACML 2.0 + * + * @since 2.0 + * @author Seth Proctor + */ +public class Condition implements Evaluatable +{ + + // a local Boolean URI that is used as the return type + private static URI booleanIdentifier; + + // regardless of version, this contains the Condition's children + private List children; + + // regardless of version, this is an expression that can be evaluated + // directly + private Expression expression; + + // the condition function, which is only used if this is a 1.x condition + private Function function; + + // flags whether this is XACML 1.x or 2.0 + private boolean isVersionOne; + + private RuntimeInfo src; + + // initialize the boolean identifier + static { + try { + booleanIdentifier = new URI(BooleanAttribute.identifier); + } catch (Exception e) { + // we ignore this, since it cannot happen, but it should be + // flagged in case something changes to trip this case + booleanIdentifier = null; + } + } + + /** + * Constructs a Condition as used in XACML 1.x. + * + * @param function the Function to use in evaluating the + * elements in the Condition + * @param expressions the contents of the Condition which will be the + * parameters to the function, each of which is an + * Expression + * + * @throws IllegalArgumentException if the input expressions don't + * match the signature of the function or + * if the function is invalid for use + * in a Condition + */ + public Condition(Function function, List expressions) + throws IllegalArgumentException { + this(function, expressions, null); + } + + /** + * Constructs a Condition as used in XACML 1.x. + * + * @param function the Function to use in evaluating the + * elements in the Condition + * @param expressions the contents of the Condition which will be the + * parameters to the function, each of which is an + * Expression + * + * @throws IllegalArgumentException if the input expressions don't + * match the signature of the function or + * if the function is invalid for use + * in a Condition + */ + public Condition(Function function, List expressions, + RuntimeInfo src) + throws IllegalArgumentException + { + this.src = src; + this.isVersionOne = true; + + // check that the function is valid for a Condition + checkExpression(function); + + + // turn the parameters into an Apply for simplicity + if ( src == null ) { + this.expression = new Apply(function, expressions, null); + } else { + Apply apply = null; + apply = new Apply(function, expressions, src.getSourceLocator(apply, ELEMENT_TYPE.APPLY)); + apply.getRuntimeInfo().setXACMLObject(apply); + this.expression = apply; + } + + // keep track of the function and the children + this.function = function; + this.children = ((Apply)this.expression).getChildren(); + } + + + /** + * Constructs a Condition as used in XACML 2.0. + * + * @param expression the child Expression + * + * @throws IllegalArgumentException if the expression is not boolean or + * returns a bag + */ + public Condition(Expression expression) + throws IllegalArgumentException + { + this.isVersionOne = false; + + // check that the function is valid for a Condition + checkExpression(expression); + + // store the expression + this.expression = expression; + + // there is no function in a 2.0 Condition + this.function = null; + + // store the expression as the child + List list = new ArrayList(); + list.add(this.expression); + this.children = Collections.unmodifiableList(list); + } + + /** + * Private helper for the constructors that checks if a given expression + * is valid for the root of a Condition + */ + private void checkExpression(Expression xpr) { + // make sure it's a boolean expression... + if (! xpr.getType().equals(booleanIdentifier)) { + throw new IllegalArgumentException("A Condition must return a " + + "boolean... cannot create a condition with return typ " + + xpr.getType() + (src != null ? src.getLocationMsgForError() : "")); + } + // ...and that it never returns a bag + if (xpr.returnsBag()) { + throw new IllegalArgumentException("A Condition must not return " + + "a Bag" + (src != null ? src.getLocationMsgForError() : "")); + } + } + + /** + * Returns an instance of Condition based on the given + * DOM root. + * + * @param root the DOM root of a ConditionType XML type + * @param metaData the meta-data associated with the containing policy + * @param manager VariableManager used to connect references + * and definitions while parsing + * + * @return The instance of the condition. + * + * @throws ParsingException if this is not a valid ConditionType + */ + public static Condition getInstance(Node root, PolicyMetaData metaData, + VariableManager manager) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.CONDITION); + // check if this really is a Condition + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("Condition")) { + throw new ParsingException("Can't create a Condition from a" + + root.getLocalName() + " element" + + (src != null ? src.getLocationMsgForError() : "")); + } + if (metaData.getXACMLVersion() < Constants.XACML_VERSION_2_0) { + Apply apply = + Apply.getConditionInstance(root, metaData.getXPathIdentifier(), + manager); + + Condition cond = new Condition(apply.getFunction(), apply.getChildren(), src); + if ( src != null ) { + src.setXACMLObject(cond); + } + return cond; + } + Expression xpr = null; + NodeList nodes = root.getChildNodes(); + + for (int i = 0; i < nodes.getLength(); i++) { + if (nodes.item(i).getNodeType() == Node.ELEMENT_NODE) { + xpr = ExpressionHandler. + parseExpression(nodes.item(i), metaData, manager); + break; + } + } + + Condition cond = new Condition(xpr); + if ( src != null ) { + cond.src = src; + src.setXACMLObject(cond); + } + return cond; + } + + /** + * Returns the Function used by this Condition + * if this is a 1.x condition, or null if this is a 2.0 condition. + * + * @return a Function or null + */ + public Function getFunction() { + return this.function; + } + + /** + * Returns the List of children for this + * Condition. The List contains + * Expressions. The list is unmodifiable. + * + * @return a List of Expressions + */ + public List getChildren() { + return this.children; + } + + public Expression getExpression() { + return this.expression; + } + + /** + * Returns the type of attribute that this object will return on a call + * to evaluate. This is always a boolean, since that's + * all that a Condition is allowed to return. + * + * @return the boolean type + */ + public URI getType() { + return booleanIdentifier; + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + /** + * Returns whether or not this Condition will return a bag + * of values on evaluation. This always returns false, since a Condition + * isn't allowed to return a bag. + * + * @return false + */ + public boolean returnsBag() { + return false; + } + + /** + * Returns whether or not this Condition will return a bag + * of values on evaluation. This always returns false, since a Condition + * isn't allowed to return a bag. + * + * @deprecated As of 2.0, you should use the returnsBag + * method from the super-interface Expression. + * + * @return false + */ + public boolean evaluatesToBag() { + return false; + } + + /** + * Evaluates the Condition by evaluating its child + * Expression. + * + * @param context the representation of the request + * + * @return the result of trying to evaluate this condition object + */ + public EvaluationResult evaluate(EvaluationCtx context) { + context.newEvent(this); + + EvaluationResult result + = ((Evaluatable)this.expression).evaluate(context); + + context.closeCurrentEvent(result); + return result; + } + + /** + * Encodes this Condition into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Condition into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + if (this.isVersionOne) { + out.println(indent + ""); + indenter.in(); + + Iterator it = this.children.iterator(); + while (it.hasNext()) { + Expression xpr = it.next(); + xpr.encode(output, charsetName, indenter); + } + } else { + out.println(indent + ""); + indenter.in(); + + this.expression.encode(output, charsetName, indenter); + } + + indenter.out(); + out.println(indent + ""); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionBagFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionBagFunction.java new file mode 100644 index 0000000..fe1b3f7 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionBagFunction.java @@ -0,0 +1,167 @@ + +/* + * @(#)ConditionBagFunction.java + * + * Copyright 2004-206 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.BooleanAttribute; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + + +/** + * Specific BagFunction class that supports the single + * condition bag function: type-is-in. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ConditionBagFunction extends BagFunction +{ + + // mapping of function name to its associated argument type + private static HashMap argMap; + + /** + * Static initializer that sets up the argument info for all the + * supported functions. + */ + static { + argMap = new HashMap(); + + for (int i = 0; i < baseTypes.length; i++) { + String [] args = { baseTypes[i], baseTypes[i] }; + + argMap.put(FUNCTION_NS + simpleTypes[i] + NAME_BASE_IS_IN, + args); + } + + + + for (int i = 0; i < baseTypes2.length; i++) { + String [] args = { baseTypes2[i], baseTypes2[i] }; + + argMap.put(FUNCTION_NS_2 + simpleTypes2[i] + NAME_BASE_IS_IN, + args); + } + } + + /** + * Constructor that is used to create one of the condition standard bag + * functions. The name supplied must be one of the standard XACML + * functions supported by this class, including the full namespace, + * otherwise an exception is thrown. Look in BagFunction + * for details about the supported names. + * + * @param functionName the name of the function to create + * + * @throws IllegalArgumentException if the function is unknown + */ + public ConditionBagFunction(String functionName) { + super(functionName, 0, getArguments(functionName)); + } + + /** + * Constructor that is used to create instances of condition bag + * functions for new (non-standard) datatypes. This is equivalent to + * using the getInstance methods in BagFunction + * and is generally only used by the run-time configuration code. + * + * @param functionName the name of the new function + * @param datatype the full identifier for the supported datatype + */ + public ConditionBagFunction(String functionName, String datatype) { + super(functionName, 0, new String [] {datatype, datatype}); + } + + /** + * Private helper that returns the argument types for the given standard + * function. + */ + private static String [] getArguments(String functionName) { + String [] args = (String [])(argMap.get(functionName)); + + if (args == null) { + throw new IllegalArgumentException("unknown bag function: " + + functionName); + } + return args; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(argMap.keySet()); + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // *-is-in takes a bag and an element of baseType and + // returns a single boolean value + AttributeValue item = argValues[0]; + BagAttribute bag = (BagAttribute)(argValues[1]); + + return new EvaluationResult(BooleanAttribute. + getInstance(bag.contains(item))); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionSetFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionSetFunction.java new file mode 100644 index 0000000..fc3c3fd --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ConditionSetFunction.java @@ -0,0 +1,269 @@ + +/* + * @(#)ConditionSetFunction.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.BooleanAttribute; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * Specific SetFunction class that supports all of the + * condition set functions: type-at-least-one-member-of, type-subset, and + * type-set-equals. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ConditionSetFunction extends SetFunction +{ + + // private identifiers for the supported functions + private static final int ID_BASE_AT_LEAST_ONE_MEMBER_OF = 0; + private static final int ID_BASE_SUBSET = 1; + private static final int ID_BASE_SET_EQUALS = 2; + + // mapping of function name to its associated id and parameter type + private static HashMap idMap; + private static HashMap typeMap; + + // the actual supported ids + private static Set supportedIds; + + /** + * Static initializer that sets up the paramater info for all the + * supported functions. + */ + static { + idMap = new HashMap(); + typeMap = new HashMap(); + + for (int i = 0; i < baseTypes.length; i++) { + String baseName = FUNCTION_NS + simpleTypes[i]; + String baseType = baseTypes[i]; + + idMap.put(baseName + NAME_BASE_AT_LEAST_ONE_MEMBER_OF, + Integer.valueOf(ID_BASE_AT_LEAST_ONE_MEMBER_OF)); + idMap.put(baseName + NAME_BASE_SUBSET, + Integer.valueOf(ID_BASE_SUBSET)); + idMap.put(baseName + NAME_BASE_SET_EQUALS, + Integer.valueOf(ID_BASE_SET_EQUALS)); + + typeMap.put(baseName + NAME_BASE_AT_LEAST_ONE_MEMBER_OF, baseType); + typeMap.put(baseName + NAME_BASE_SUBSET, baseType); + typeMap.put(baseName + NAME_BASE_SET_EQUALS, baseType); + } + + for (int i = 0; i < baseTypes2.length; i++) { + String baseName = FUNCTION_NS_2 + simpleTypes2[i]; + String baseType = baseTypes2[i]; + + idMap.put(baseName + NAME_BASE_AT_LEAST_ONE_MEMBER_OF, + Integer.valueOf(ID_BASE_AT_LEAST_ONE_MEMBER_OF)); + idMap.put(baseName + NAME_BASE_SUBSET, + Integer.valueOf(ID_BASE_SUBSET)); + idMap.put(baseName + NAME_BASE_SET_EQUALS, + Integer.valueOf(ID_BASE_SET_EQUALS)); + + typeMap.put(baseName + NAME_BASE_AT_LEAST_ONE_MEMBER_OF, baseType); + typeMap.put(baseName + NAME_BASE_SUBSET, baseType); + typeMap.put(baseName + NAME_BASE_SET_EQUALS, baseType); + } + + supportedIds = Collections. + unmodifiableSet(new HashSet(idMap.keySet())); + + idMap.put(NAME_BASE_AT_LEAST_ONE_MEMBER_OF, + Integer.valueOf(ID_BASE_AT_LEAST_ONE_MEMBER_OF)); + idMap.put(NAME_BASE_SUBSET, Integer.valueOf(ID_BASE_SUBSET)); + idMap.put(NAME_BASE_SET_EQUALS, Integer.valueOf(ID_BASE_SET_EQUALS)); + } + + /** + * Constructor that is used to create one of the condition standard + * set functions. The name supplied must be one of the standard XACML + * functions supported by this class, including the full namespace, + * otherwise an exception is thrown. Look in SetFunction + * for details about the supported names. + * + * @param functionName the name of the function to create + * + * @throws IllegalArgumentException if the function is unknown + */ + public ConditionSetFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + BooleanAttribute.identifier, false); + } + + /** + * Constructor that is used to create instances of condition set + * functions for new (non-standard) datatypes. This is equivalent to + * using the getInstance methods in SetFunction + * and is generally only used by the run-time configuration code. + * + * @param functionName the name of the new function + * @param datatype the full identifier for the supported datatype + * @param functionType which kind of Set function, based on the + * NAME_BASE_* fields + */ + public ConditionSetFunction(String functionName, String datatype, + String functionType) { + super(functionName, getId(functionName), datatype, + BooleanAttribute.identifier, false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + Integer id = (Integer)(idMap.get(functionName)); + + if (id == null) { + throw new IllegalArgumentException("unknown set function " + + functionName); + } + return id.intValue(); + } + + /** + * Private helper that returns the argument type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + return (String)(typeMap.get(functionName)); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return supportedIds; + } + + /** + * Evaluates the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult evalResult = evalArgs(inputs, context, argValues); + if (evalResult != null) { + return evalResult; + } + // setup the two bags we'll be using + BagAttribute [] bags = new BagAttribute[2]; + bags[0] = (BagAttribute)(argValues[0]); + bags[1] = (BagAttribute)(argValues[1]); + + AttributeValue result = null; + + switch(getFunctionId()) { + // *-at-least-one-member-of takes two bags of the same type and + // returns a boolean + case ID_BASE_AT_LEAST_ONE_MEMBER_OF: + // true if at least one element in the first argument is in the + // second argument (using the *-is-in semantics) + + result = BooleanAttribute.getFalseInstance(); + Iterator it = bags[0].iterator(); + + while (it.hasNext()) { + if (bags[1].contains((AttributeValue)(it.next()))) { + result = BooleanAttribute.getTrueInstance(); + break; + } + } + + break; + + // *-set-equals takes two bags of the same type and returns + // a boolean + case ID_BASE_SUBSET: + // returns true if the first argument is a subset of the second + // argument (ie, all the elements in the first bag appear in + // the second bag) ... ignore all duplicate values in both + // input bags + + boolean subset = bags[1].containsAll(bags[0]); + result = BooleanAttribute.getInstance(subset); + + break; + + // *-set-equals takes two bags of the same type and returns + // a boolean + case ID_BASE_SET_EQUALS: + + // returns true if the two inputs contain the same elements + // discounting any duplicates in either input ... this is the same + // as applying the and function on the subset function with + // the two inputs, and then the two inputs reversed (ie, are the + // two inputs subsets of each other) + + boolean equals = (bags[1].containsAll(bags[0]) && + bags[0].containsAll(bags[1])); + result = BooleanAttribute.getInstance(equals); + + break; + } + + return new EvaluationResult(result); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DateMathFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DateMathFunction.java new file mode 100644 index 0000000..99efd63 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DateMathFunction.java @@ -0,0 +1,373 @@ + +/* + * @(#)DateMathFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DayTimeDurationAttribute; +import com.sun.xacml.attr.YearMonthDurationAttribute; + +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements several of the date math functions. They + * all take two arguments. The first is a DateTimeAttribute or a + * DateAttribute (as the case may be) and the second is a + * DayTimeDurationAttribute or a YearMonthDurationAttribute (as + * the case may be). The function adds or subtracts the second + * argument to/from the first and returns a value of the same + * type as the first argument. If either of the arguments evaluates + * to indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class DateMathFunction extends FunctionBase +{ + + /** + * Standard identifier for the dateTime-add-dayTimeDuration function. + */ + public static final String NAME_DATETIME_ADD_DAYTIMEDURATION = + FUNCTION_NS + "dateTime-add-dayTimeDuration"; + + /** + * Standard identifier for the dateTime-subtract-dayTimeDuration function. + */ + public static final String NAME_DATETIME_SUBTRACT_DAYTIMEDURATION = + FUNCTION_NS + "dateTime-subtract-dayTimeDuration"; + + /** + * Standard identifier for the dateTime-add-yearMonthDuration function. + */ + public static final String NAME_DATETIME_ADD_YEARMONTHDURATION = + FUNCTION_NS + "dateTime-add-yearMonthDuration"; + + /** + * Standard identifier for the dateTime-subtract-yearMonthDuration + * function. + */ + public static final String NAME_DATETIME_SUBTRACT_YEARMONTHDURATION = + FUNCTION_NS + "dateTime-subtract-yearMonthDuration"; + + /** + * Standard identifier for the date-add-yearMonthDuration function. + */ + public static final String NAME_DATE_ADD_YEARMONTHDURATION = + FUNCTION_NS + "date-add-yearMonthDuration"; + + /** + * Standard identifier for the date-subtract-yearMonthDuration function. + */ + public static final String NAME_DATE_SUBTRACT_YEARMONTHDURATION = + FUNCTION_NS + "date-subtract-yearMonthDuration"; + + // private identifiers for the supported functions + private static final int ID_DATETIME_ADD_DAYTIMEDURATION = 0; + private static final int ID_DATETIME_SUBTRACT_DAYTIMEDURATION = 1; + private static final int ID_DATETIME_ADD_YEARMONTHDURATION = 2; + private static final int ID_DATETIME_SUBTRACT_YEARMONTHDURATION = 3; + private static final int ID_DATE_ADD_YEARMONTHDURATION = 4; + private static final int ID_DATE_SUBTRACT_YEARMONTHDURATION = 5; + + // Argument types + private static final String dateTimeDayTimeDurationArgTypes [] = + { DateTimeAttribute.identifier, + DayTimeDurationAttribute.identifier }; + private static final String dateTimeYearMonthDurationArgTypes [] = + { DateTimeAttribute.identifier, + YearMonthDurationAttribute.identifier }; + private static final String dateYearMonthDurationArgTypes [] = + { DateAttribute.identifier, + YearMonthDurationAttribute.identifier }; + + // nothing here uses a bag + private static final boolean bagParams [] = { false, false }; + + // mapping from name to provide identifiers and argument types + private static HashMap idMap; + private static HashMap typeMap; + + /** + * Static initializer to setup the id and type maps + */ + static { + idMap = new HashMap(); + + idMap.put(NAME_DATETIME_ADD_DAYTIMEDURATION, + Integer.valueOf(ID_DATETIME_ADD_DAYTIMEDURATION)); + idMap.put(NAME_DATETIME_SUBTRACT_DAYTIMEDURATION, + Integer.valueOf(ID_DATETIME_SUBTRACT_DAYTIMEDURATION)); + idMap.put(NAME_DATETIME_ADD_YEARMONTHDURATION, + Integer.valueOf(ID_DATETIME_ADD_YEARMONTHDURATION)); + idMap.put(NAME_DATETIME_SUBTRACT_YEARMONTHDURATION, + Integer.valueOf(ID_DATETIME_SUBTRACT_YEARMONTHDURATION)); + idMap.put(NAME_DATE_ADD_YEARMONTHDURATION, + Integer.valueOf(ID_DATE_ADD_YEARMONTHDURATION)); + idMap.put(NAME_DATE_SUBTRACT_YEARMONTHDURATION, + Integer.valueOf(ID_DATE_SUBTRACT_YEARMONTHDURATION)); + + typeMap = new HashMap(); + + typeMap.put(NAME_DATETIME_ADD_DAYTIMEDURATION, + dateTimeDayTimeDurationArgTypes); + typeMap.put(NAME_DATETIME_SUBTRACT_DAYTIMEDURATION, + dateTimeDayTimeDurationArgTypes); + typeMap.put(NAME_DATETIME_ADD_YEARMONTHDURATION, + dateTimeYearMonthDurationArgTypes); + typeMap.put(NAME_DATETIME_SUBTRACT_YEARMONTHDURATION, + dateTimeYearMonthDurationArgTypes); + typeMap.put(NAME_DATE_ADD_YEARMONTHDURATION, + dateYearMonthDurationArgTypes); + typeMap.put(NAME_DATE_SUBTRACT_YEARMONTHDURATION, + dateYearMonthDurationArgTypes); + } + + /** + * Creates a new DateMathFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public DateMathFunction(String functionName) { + super(functionName, getId(functionName), + getArgumentTypes(functionName), bagParams, + getReturnType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + Integer i = (Integer)(idMap.get(functionName)); + + if (i == null) { + throw new IllegalArgumentException("unknown datemath function " + + functionName); + } + + return i.intValue(); + } + + /** + * Private helper that returns the types used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String [] getArgumentTypes(String functionName) { + return (String [])(typeMap.get(functionName)); + } + + /** + * Private helper that returns the return type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getReturnType(String functionName) { + if (functionName.equals(NAME_DATE_ADD_YEARMONTHDURATION) || + functionName.equals(NAME_DATE_SUBTRACT_YEARMONTHDURATION)) { + return DateAttribute.identifier; + } + return DateTimeAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(idMap.keySet()); + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the date math operation. + AttributeValue attrResult = null; + + switch (getFunctionId()) { + // These two functions are basically the same except for sign. + // And they both need to deal with sign anyway, so they share + // their code. + case ID_DATETIME_ADD_DAYTIMEDURATION: + case ID_DATETIME_SUBTRACT_DAYTIMEDURATION: { + DateTimeAttribute dateTime = (DateTimeAttribute) argValues[0]; + DayTimeDurationAttribute duration = + (DayTimeDurationAttribute) argValues[1]; + + // Decide what sign goes with duration + int sign = 1; + if (getFunctionId() == ID_DATETIME_SUBTRACT_DAYTIMEDURATION) { + sign = -sign; + } + if (duration.isNegative()) { + sign = -sign; + } + long millis = sign * duration.getTotalSeconds(); + long nanoseconds = dateTime.getNanoseconds(); + nanoseconds = nanoseconds + (sign * duration.getNanoseconds()); + if (nanoseconds >= 1000000000) { + nanoseconds -= 1000000000; + millis += 1000; + } + if (nanoseconds < 0) { + nanoseconds += 1000000000; + millis -= 1000; + } + millis = millis + dateTime.getValue().getTime(); + + attrResult = new DateTimeAttribute(new Date(millis), + (int) nanoseconds, + dateTime.getTimeZone(), + dateTime. + getDefaultedTimeZone()); + + break; + } + case ID_DATETIME_ADD_YEARMONTHDURATION: + case ID_DATETIME_SUBTRACT_YEARMONTHDURATION: { + DateTimeAttribute dateTime = (DateTimeAttribute) argValues[0]; + YearMonthDurationAttribute duration = + (YearMonthDurationAttribute) argValues[1]; + + // Decide what sign goes with duration + int sign = 1; + if (getFunctionId() == ID_DATETIME_SUBTRACT_YEARMONTHDURATION) { + sign = -sign; + } + if (duration.isNegative()) { + sign = -sign; + } + + // Add (or subtract) the years and months. + Calendar cal = new GregorianCalendar(); + cal.setTime(dateTime.getValue()); + long years = sign * duration.getYears(); + long months = sign * duration.getMonths(); + if ((years > Integer.MAX_VALUE) || (years < Integer.MIN_VALUE)) { + return makeProcessingError("years too large"); + } + if ((months > Integer.MAX_VALUE) || (months < Integer.MIN_VALUE)) { + return makeProcessingError("months too large"); + } + + cal.add(Calendar.YEAR, (int) years); + cal.add(Calendar.MONTH, (int) months); + + attrResult = new DateTimeAttribute(cal.getTime(), + dateTime.getNanoseconds(), + dateTime.getTimeZone(), + dateTime. + getDefaultedTimeZone()); + + break; + } + case ID_DATE_ADD_YEARMONTHDURATION: + case ID_DATE_SUBTRACT_YEARMONTHDURATION: { + DateAttribute date = (DateAttribute) argValues[0]; + YearMonthDurationAttribute duration = + (YearMonthDurationAttribute) argValues[1]; + + // Decide what sign goes with duration + int sign = 1; + if (getFunctionId() == ID_DATE_SUBTRACT_YEARMONTHDURATION) { + sign = -sign; + } + if (duration.isNegative()) { + sign = -sign; + } + + // Add (or subtract) the years and months. + Calendar cal = new GregorianCalendar(); + cal.setTime(date.getValue()); + long years = sign * duration.getYears(); + long months = sign * duration.getMonths(); + if ((years > Integer.MAX_VALUE) || (years < Integer.MIN_VALUE)) { + return makeProcessingError("years too large"); + } + if ((months > Integer.MAX_VALUE) || (months < Integer.MIN_VALUE)) { + return makeProcessingError("months too large"); + } + + cal.add(Calendar.YEAR, (int) years); + cal.add(Calendar.MONTH, (int) months); + + attrResult = new DateAttribute(cal.getTime(), + date.getTimeZone(), + date.getDefaultedTimeZone()); + + break; + } + } + + return new EvaluationResult(attrResult); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DivideFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DivideFunction.java new file mode 100644 index 0000000..6f0665a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/DivideFunction.java @@ -0,0 +1,179 @@ + +/* + * @(#)DivideFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-divide functions. It takes two + * operands of the appropriate type and returns the quotient of the + * operands. If either of the operands is indeterminate, an indeterminate + * result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class DivideFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-divide function. + */ + public static final String NAME_INTEGER_DIVIDE = + FUNCTION_NS + "integer-divide"; + + /** + * Standard identifier for the double-divide function. + */ + public static final String NAME_DOUBLE_DIVIDE = + FUNCTION_NS + "double-divide"; + + // inernal identifiers for each of the supported functions + private static final int ID_INTEGER_DIVIDE = 0; + private static final int ID_DOUBLE_DIVIDE = 1; + + /** + * Creates a new DivideFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public DivideFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 2, getArgumentType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_INTEGER_DIVIDE)) { + return ID_INTEGER_DIVIDE; + } else if (functionName.equals(NAME_DOUBLE_DIVIDE)) { + return ID_DOUBLE_DIVIDE; + } else { + throw new IllegalArgumentException("unknown divide function " + + functionName); + } + + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_INTEGER_DIVIDE)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_DIVIDE); + set.add(NAME_DOUBLE_DIVIDE); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the divide operation + // in the manner appropriate for the type of the arguments. + if (getFunctionId() == ID_INTEGER_DIVIDE) { + long dividend = ((IntegerAttribute) argValues[0]).getValue(); + long divisor = ((IntegerAttribute) argValues[1]).getValue(); + if (divisor == 0) { + result = makeProcessingError("divide by zero"); + } else { + long quotient = dividend / divisor; + result = new EvaluationResult(new IntegerAttribute(quotient)); + } + } else if (getFunctionId() == ID_DOUBLE_DIVIDE) { + double dividend = ((DoubleAttribute) argValues[0]).getValue(); + double divisor = ((DoubleAttribute) argValues[1]).getValue(); + if (divisor == 0) { + result = makeProcessingError("divide by zero"); + } else { + double quotient = dividend / divisor; + result = new EvaluationResult(new DoubleAttribute(quotient)); + } + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EqualFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EqualFunction.java new file mode 100644 index 0000000..d253fb5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EqualFunction.java @@ -0,0 +1,299 @@ + +/* + * @(#)EqualFunction.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.Base64BinaryAttribute; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DayTimeDurationAttribute; +import com.sun.xacml.attr.DNSNameAttribute; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.HexBinaryAttribute; +import com.sun.xacml.attr.IntegerAttribute; +import com.sun.xacml.attr.IPAddressAttribute; +import com.sun.xacml.attr.RFC822NameAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TimeAttribute; +import com.sun.xacml.attr.YearMonthDurationAttribute; +import com.sun.xacml.attr.X500NameAttribute; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-equal functions. It takes two operands + * of the appropriate type and returns a BooleanAttribute + * indicating whether both of the operands are equal. If either of the + * operands is indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class EqualFunction extends FunctionBase +{ + + /** + * Standard identifier for the string-equal function. + */ + public static final String NAME_STRING_EQUAL = + FUNCTION_NS + "string-equal"; + + /** + * Standard identifier for the boolean-equal function. + */ + public static final String NAME_BOOLEAN_EQUAL = + FUNCTION_NS + "boolean-equal"; + + /** + * Standard identifier for the integer-equal function. + */ + public static final String NAME_INTEGER_EQUAL = + FUNCTION_NS + "integer-equal"; + + /** + * Standard identifier for the double-equal function. + */ + public static final String NAME_DOUBLE_EQUAL = + FUNCTION_NS + "double-equal"; + + /** + * Standard identifier for the date-equal function. + */ + public static final String NAME_DATE_EQUAL = + FUNCTION_NS + "date-equal"; + + /** + * Standard identifier for the time-equal function. + */ + public static final String NAME_TIME_EQUAL = + FUNCTION_NS + "time-equal"; + + /** + * Standard identifier for the dateTime-equal function. + */ + public static final String NAME_DATETIME_EQUAL = + FUNCTION_NS + "dateTime-equal"; + + /** + * Standard identifier for the dayTimeDuration-equal function. + */ + public static final String NAME_DAYTIME_DURATION_EQUAL = + FUNCTION_NS + "dayTimeDuration-equal"; + + /** + * Standard identifier for the yearMonthDuration-equal function. + */ + public static final String NAME_YEARMONTH_DURATION_EQUAL = + FUNCTION_NS + "yearMonthDuration-equal"; + + /** + * Standard identifier for the anyURI-equal function. + */ + public static final String NAME_ANYURI_EQUAL = + FUNCTION_NS + "anyURI-equal"; + + /** + * Standard identifier for the x500Name-equal function. + */ + public static final String NAME_X500NAME_EQUAL = + FUNCTION_NS + "x500Name-equal"; + + /** + * Standard identifier for the rfc822Name-equal function. + */ + public static final String NAME_RFC822NAME_EQUAL = + FUNCTION_NS + "rfc822Name-equal"; + + /** + * Standard identifier for the hexBinary-equal function. + */ + public static final String NAME_HEXBINARY_EQUAL = + FUNCTION_NS + "hexBinary-equal"; + + /** + * Standard identifier for the base64Binary-equal function. + */ + public static final String NAME_BASE64BINARY_EQUAL = + FUNCTION_NS + "base64Binary-equal"; + + /** + * Standard identifier for the ipAddress-equal function. + */ + public static final String NAME_IPADDRESS_EQUAL = + FUNCTION_NS_2 + "ipAddress-equal"; + + /** + * Standard identifier for the dnsName-equal function. + */ + public static final String NAME_DNSNAME_EQUAL = + FUNCTION_NS_2 + "dnsName-equal"; + + // private mapping of standard functions to their argument types + private static HashMap typeMap; + + /** + * Static initializer sets up a map of standard function names to their + * associated datatypes + */ + static { + typeMap = new HashMap(); + + typeMap.put(NAME_STRING_EQUAL, StringAttribute.identifier); + typeMap.put(NAME_BOOLEAN_EQUAL, BooleanAttribute.identifier); + typeMap.put(NAME_INTEGER_EQUAL, IntegerAttribute.identifier); + typeMap.put(NAME_DOUBLE_EQUAL, DoubleAttribute.identifier); + typeMap.put(NAME_DATE_EQUAL, DateAttribute.identifier); + typeMap.put(NAME_TIME_EQUAL, TimeAttribute.identifier); + typeMap.put(NAME_DATETIME_EQUAL, DateTimeAttribute.identifier); + typeMap.put(NAME_DAYTIME_DURATION_EQUAL, + DayTimeDurationAttribute.identifier); + typeMap.put(NAME_YEARMONTH_DURATION_EQUAL, + YearMonthDurationAttribute.identifier); + typeMap.put(NAME_ANYURI_EQUAL, AnyURIAttribute.identifier); + typeMap.put(NAME_X500NAME_EQUAL, X500NameAttribute.identifier); + typeMap.put(NAME_RFC822NAME_EQUAL, RFC822NameAttribute.identifier); + typeMap.put(NAME_HEXBINARY_EQUAL, HexBinaryAttribute.identifier); + typeMap.put(NAME_BASE64BINARY_EQUAL, Base64BinaryAttribute.identifier); + typeMap.put(NAME_IPADDRESS_EQUAL, IPAddressAttribute.identifier); + typeMap.put(NAME_DNSNAME_EQUAL, DNSNameAttribute.identifier); + } + + /** + * Returns an EqualFunction that provides the type-equal + * functionality over the given attribute type. This should be used to + * create new function instances for any new attribute types, and the + * resulting object should be put into the FunctionFactory + * (instances for the standard types are pre-installed in the standard + * factory). + *

    + * Note that this method has the same affect as invoking the constructor + * with the same parameters. This method is provided as a convenience, + * and for symmetry with the bag and set functions. + * + * @param functionName the name to use for the function + * @param argumentType the type to operate on + * + * @return a new EqualFunction + */ + public static EqualFunction getEqualInstance(String functionName, + String argumentType) { + return new EqualFunction(functionName, argumentType); + } + + /** + * Creates a new EqualFunction object that supports one + * of the standard type-equal functions. If you need to create an + * instance for a custom type, use the getEqualInstance + * method or the alternate constructor. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function isn't standard + */ + public EqualFunction(String functionName) { + this(functionName, getArgumentType(functionName)); + } + + /** + * Creates a new EqualFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * @param argumentType the standard XACML name for the type of + * the arguments, inlcuding the full namespace + */ + public EqualFunction(String functionName, String argumentType) { + super(functionName, 0, argumentType, false, 2, + BooleanAttribute.identifier, false); + } + + /** + * Private helper that returns the type used for the given standard + * type-equal function. + */ + private static String getArgumentType(String functionName) { + String datatype = (String)(typeMap.get(functionName)); + + if (datatype == null) { + throw new IllegalArgumentException("not a standard function: " + + functionName); + } + return datatype; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(typeMap.keySet()); + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have real values, perform the equals operation + return EvaluationResult.getInstance(argValues[0].equals(argValues[1])); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Evaluatable.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Evaluatable.java new file mode 100644 index 0000000..e2e5baf --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Evaluatable.java @@ -0,0 +1,75 @@ + +/* + * @(#)Evaluatable.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import java.util.List; + + +/** + * Generic interface that is implemented by all objects that can be evaluated + * directly (AttributeDesignator, Apply, + * AttributeValue, etc.). As of version 2.0 several methods + * were extracted to the new Expression super-interface. + * + * @since 1.0 + * @author Seth Proctor + */ +public interface Evaluatable extends Expression +{ + + /** + * Evaluates the object using the given context, and either returns an + * error or a resulting value. + * + * @param context the representation of the request + * + * @return the result of evaluation + */ + public EvaluationResult evaluate(EvaluationCtx context); + + /** + * Returns all children, in order, of this element in the Condition + * tree, or en empty set if this element has no children. In XACML 1.x, + * only the ApplyType ever has children. + * + * @return a List of Evaluatables + */ + public List getChildren(); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EvaluationResult.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EvaluationResult.java new file mode 100644 index 0000000..16761c8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/EvaluationResult.java @@ -0,0 +1,195 @@ + +/* + * @(#)EvaluationResult.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import java.util.List; +import java.util.Vector; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; + +import com.sun.xacml.ctx.Status; + + +/** + * This is used in cases where a normal result is some AttributeValue, but + * if an attribute couldn't be resolved (or some other problem occurred), + * then a Status object needs to be returned instead. This is used instead of + * throwing an exception for performance, but mainly because failure to resolve + * an attribute is not an error case for the code, merely for the evaluation, + * and represents normal operation. Separate exception types will be added + * later to represent errors in pdp operation. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class EvaluationResult +{ + + /** + * This indicates that the result was indeterminate. + */ + private boolean wasInd; + + /** + * The attribute value returned by this evaluation. + */ + private AttributeValue value; + + /** + * The status of this evaluation (i.e. ok, missing attribute, + * syntax error, processing error) + */ + private Status status; + + /** + * Single instances of EvaluationResults with false and true + * BooleanAttributes in them. This avoids the need to create + * new objects when performing boolean operations, which we + * do a lot of. + */ + private static EvaluationResult falseBooleanResult; + private static EvaluationResult trueBooleanResult; + + /** + * Constructor that creates an EvaluationResult containing + * a single AttributeValue + * + * @param value the attribute value + */ + public EvaluationResult(AttributeValue value) { + this.wasInd = false; + this.value = value; + this.status = null; + } + + /** + * Constructor that creates an EvaluationResult of + * Indeterminate, including Status data. + * + * @param status the error information + */ + public EvaluationResult(Status status) { + this.wasInd = true; + this.value = null; + this.status = status; + } + + /** + * Returns true if the result was indeterminate + * + * @return true if there was an error + */ + public boolean indeterminate() { + return this.wasInd; + } + + /** + * Returns the attribute value, or null if there was an error + * + * @return the attribute value or null + */ + public AttributeValue getAttributeValue() { + return this.value; + } + + /** + * Returns the status if there was an error, or null it no error occurred + * + * @return the status or null + */ + public Status getStatus() { + return this.status; + } + + /** + * Returns an EvaluationResult that represents + * the boolean value provided. + * + * @param value a boolean representing the desired value + * @return an EvaluationResult representing the + * appropriate value + */ + public static EvaluationResult getInstance(boolean value) { + if (value) { + return getTrueInstance(); + } + return getFalseInstance(); + } + + /** + * Returns an EvaluationResult that represents + * a false value. + * + * @return an EvaluationResult representing a + * false value + */ + public static EvaluationResult getFalseInstance() { + if (falseBooleanResult == null) { + falseBooleanResult = + new EvaluationResult(BooleanAttribute.getFalseInstance()); + } + return falseBooleanResult; + } + + /** + * Returns an EvaluationResult that represents + * a true value. + * + * @return an EvaluationResult representing a + * true value + */ + public static EvaluationResult getTrueInstance() { + if (trueBooleanResult == null) { + trueBooleanResult = + new EvaluationResult(BooleanAttribute.getTrueInstance()); + } + return trueBooleanResult; + } + + /** + * Creates a missing attribute evaluation result. + * @param message + * @return + */ + public static EvaluationResult createMissingAttributeInstance(String message) { + List statusMsg = new Vector(); + statusMsg.add(Status.STATUS_MISSING_ATTRIBUTE); + return new EvaluationResult(new Status(statusMsg, message)); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Expression.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Expression.java new file mode 100644 index 0000000..ca708d4 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Expression.java @@ -0,0 +1,108 @@ + +/* + * @(#)Expression.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.Indenter; +import com.sun.xacml.debug.Locatable; + +import java.net.URI; +import java.util.Collections; +import java.util.List; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + + +/** + * This interface represents the expression type in the XACML 2.0 schema. + * + * @since 2.0 + * @author Seth Proctor + */ +public interface Expression extends Locatable +{ + public static List EMPTY_LIST = Collections.emptyList(); + + /** + * Returns the type of the expression. This may be the data type of + * an AttributeValue, the return type of a + * Function, etc. + * + * @return the attribute type of the referenced expression + */ + public URI getType(); + + /** + * Returns whether or not this expression returns, or evaluates to a + * Bag. Note that Evaluatable, which extends this interface, + * defines evaluatesToBag which is essentially the same + * function. This method has been deprecated, and returnsBag + * is now the preferred way to query all Expressions. + * + * @return true or false. + */ + public boolean returnsBag(); + + /** + * Encodes this Expression into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException; + + /** + * Encodes this Expression into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ExpressionHandler.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ExpressionHandler.java new file mode 100644 index 0000000..c20ed6b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ExpressionHandler.java @@ -0,0 +1,138 @@ + +/* + * ExpressionHandler.java + * + * Created by: seth proctor (stp) + * Created on: Wed Dec 29, 2004 8:24:30 PM + * Desc: + * + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.UnknownIdentifierException; + +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeSelector; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import org.w3c.dom.Node; + + +/** + * This is a package-private utility class that handles parsing all the + * possible expression types. It was added becuase in 2.0 multiple classes + * needed this. Note that this could also be added to Expression and + * that interface could be made an abstract class, but that would require + * substantial change. + * + * @since 2.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +class ExpressionHandler +{ + + /** + * Parses an expression, recursively handling any sub-elements. This is + * provided as a utility class, but in practice is used only by + * Apply, Condition, and + * VariableDefinition. + * + * @param root the DOM root of an ExpressionType XML type + * @param metaData the meta-data associated with the containing policy + * @param manager VariableManager used to connect references + * and definitions while parsing + * + * @return an Expression or null if the root node cannot be + * parsed as a valid Expression + * + * @throws ParsingException + */ + public static Expression parseExpression(Node root, + PolicyMetaData metaData, VariableManager manager ) + throws ParsingException { + if (root.getNodeType() != Node.ELEMENT_NODE) { + return null; + } + + String name = root.getLocalName(); + + if (name.equals("Apply")) { + return Apply.getInstance(root, metaData, manager); + } else if (name.equals("AttributeValue")) { + try { + return AttributeFactory.getInstance().createValue(root); + } catch (UnknownIdentifierException uie) { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.ATTRIBUTE_VALUE); + throw new ParsingException("Unknown DataType" + + (src != null ? src.getLocationMsgForError() : ""), uie); + } + } else if (name.endsWith("AttributeDesignator")) { + return AttributeDesignator.getInstance(root, metaData); + } else if (name.equals("AttributeSelector")) { + return AttributeSelector.getInstance(root, metaData); + } else if (name.equals("Function")) { + return getFunction(root, metaData, + FunctionFactory.getGeneralInstance()); + } else if (name.equals("VariableReference")) { + return VariableReference.getInstance(root, metaData, manager); + } + + // return null if it was none of these + return null; + } + + /** + * Helper method that tries to get a function instance + * + * @param root the root node of the XML defining this expression. + * @param metaData the policy meta data for this expression. + * @param factory the function factory for this expression. + * + * @return The function of this expression. + * + * @throws ParsingException + */ + public static Function getFunction(Node root, PolicyMetaData metaData, + FunctionFactory factory) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.FUNCTION); + if (root.getNodeType() != Node.ELEMENT_NODE || + root.getAttributes().getNamedItem("FunctionId") == null) { + throw new ParsingException("Error: tried to parse Function from" + + " non Element type node or with missing FunctionId (ELEMENT_NODE: " + + (root.getNodeType() == Node.ELEMENT_NODE) + ", Node: " + root.getLocalName() + + ", FunctionId: " + root.getAttributes().getNamedItem("FunctionId") + ")" + + (src != null ? src.getLocationMsgForError() : "")); + } + Node functionNode = root.getAttributes().getNamedItem("FunctionId"); + String functionName = functionNode.getNodeValue(); + + try { + // try to get an instance of the given function + return factory.createFunction(functionName); + } catch (UnknownIdentifierException uie) { + throw new ParsingException("Unknown FunctionId: " + uie.getMessage() + + (src != null ? src.getLocationMsgForError() : ""), uie); + } catch (FunctionTypeException fte) { + // try creating as an abstract function + try { + FunctionFactory ff = FunctionFactory.getGeneralInstance(); + return ff.createAbstractFunction(functionName, root, + metaData. + getXPathIdentifier()); + } catch (Exception e) { + // any exception at this point is a failure + throw new ParsingException("failed to create abstract function" + + " " + functionName + + (src != null ? src.getLocationMsgForError() : ""), e); + } + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FloorFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FloorFunction.java new file mode 100644 index 0000000..1b1ea1c --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FloorFunction.java @@ -0,0 +1,122 @@ + +/* + * @(#)FloorFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the floor function. It takes one double + * operand, chooses the largest integer less than or equal to that + * value, and returns that integer (as a double). If the operand + * is indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class FloorFunction extends FunctionBase +{ + + /** + * Standard identifier for the floor function. + */ + public static final String NAME_FLOOR = FUNCTION_NS + "floor"; + + /** + * Creates a new FloorFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public FloorFunction(String functionName) { + super(NAME_FLOOR, 0, DoubleAttribute.identifier, false, 1, + DoubleAttribute.identifier, false); + + if (! functionName.equals(NAME_FLOOR)) { + throw new IllegalArgumentException("unknown floor function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_FLOOR); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have real values, perform the floor operation + double arg = ((DoubleAttribute) argValues[0]).getValue(); + + return new EvaluationResult(new DoubleAttribute(Math.floor(arg))); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Function.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Function.java new file mode 100644 index 0000000..cdcfc40 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/Function.java @@ -0,0 +1,169 @@ + +/* + * @(#)Function.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.debug.IndirectLocatable; +import com.sun.xacml.debug.RuntimeInfo; + +import java.net.URI; + +import java.util.List; + + +/** + * Interface that all functions in the system must implement. + * + * @since 1.0 + * @author Seth Proctor + */ +public interface Function extends Expression, IndirectLocatable +{ + + /** + * Evaluates the Function using the given inputs. + * The List contains Evaluatables which are all + * of the correct type if the Function has been created as + * part of an Apply or TargetMatch, but which + * may otherwise be invalid. Each parameter should be evaluated by the + * Function, unless the Function + * doesn't need to evaluate all inputs to determine a result (as in the + * case of the or function). The order of the List is + * significant, so a Function should have a very good reason + * if it wants to evaluate the inputs in a different order. + *

    + * Note that if this is a higher-order function, like any-of, then + * some argument (typically the first) in the List will + * actually be a Function object representing the function to apply to + * some bag. A function needs to know if it's a higher-order function, + * and therefore whether or not to look for this case. Also, a + * higher-order function is responsible for checking that the inputs + * that it will pass to the Function provided as the first + * parameter are valid, ie. it must do a checkInputs on + * its sub-function when checkInputs is called on the + * higher-order function. + * + * @param inputs the List of inputs for the function + * @param context the representation of the request + * + * @return a result containing the AttributeValue computed + * when evaluating the function, or Status + * specifying some error condition + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context); + + /** + * Returns the identifier of this function as known by the factories. + * In the case of the standard XACML functions, this will be one of the + * URIs defined in the standard namespace. This function must always + * return the complete namespace and identifier of this function. + * + * @return the function's identifier + */ + public URI getIdentifier(); + + /** + * Provides the type of AttributeValue that this function + * returns from evaluate in a successful evaluation. + * + * @return the type returned by this function + */ + public URI getReturnType(); + + /** + * Tells whether this function will return a bag of values or just a + * single value. + * + * @return true if evaluation will return a bag, false otherwise + */ + public boolean returnsBag(); + + /** + * Checks that the given inputs are of the right types, in the right + * order, and are the right number for this function to evaluate. If + * the function cannot accept the inputs for evaluation, an + * IllegalArgumentException is thrown. + * + * @param inputs a List of Evaluatables, with + * the first argument being a Function if + * this is a higher-order function + * + * @throws IllegalArgumentException if the inputs do match what the + * function accepts for evaluation + */ + public void checkInputs(List inputs) throws IllegalArgumentException; + + /** + * Checks that the given inputs are of the right types, in the right + * order, and are the right number for this function to evaluate. If + * the function cannot accept the inputs for evaluation, an + * IllegalArgumentException is thrown. + * + * @param inputs a List of Evaluatables, with + * the first argument being a Function if + * this is a higher-order function + * + * @throws IllegalArgumentException if the inputs do match what the + * function accepts for evaluation + */ + public void checkInputs(List inputs, RuntimeInfo src) throws IllegalArgumentException; + + /** + * Checks that the given inputs are of the right types, in the right + * order, and are the right number for this function to evaluate. If + * the function cannot accept the inputs for evaluation, an + * IllegalArgumentException is thrown. Unlike the other + * checkInput method in this interface, this assumes that + * the parameters will never provide bags of values. This is useful if + * you're considering a target function which has a designator or + * selector in its input list, but which passes the values from the + * derived bags one at a time to the function, so the function doesn't + * have to deal with the bags that the selector or designator + * generates. + * + * @param inputs a List of Evaluatables, with + * the first argument being a Function if + * this is a higher-order function + * + * @throws IllegalArgumentException if the inputs do match what the + * function accepts for evaluation + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException; + + + public void checkInputsNoBag(List inputs, RuntimeInfo src) throws IllegalArgumentException; +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionBase.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionBase.java new file mode 100644 index 0000000..3afecfb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionBase.java @@ -0,0 +1,763 @@ + +/* + * @(#)FunctionBase.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; + +import com.sun.xacml.attr.AttributeValue; + +import com.sun.xacml.ctx.Status; +import com.sun.xacml.debug.RuntimeInfo; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; + +import org.apache.log4j.Logger; + + + +/** + * An abstract utility superclass for functions. Supplies several useful + * methods, making it easier to implement a Function. You can + * extend this class or implement Function directly, depending + * on your needs. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public abstract class FunctionBase implements Function +{ + + /** + * The standard namespace where all XACML 1.0 spec-defined functions live + */ + public static final String FUNCTION_NS = + "urn:oasis:names:tc:xacml:1.0:function:"; + + /** + * The standard namespace where all XACML 2.0 spec-defined functions live + */ + public static final String FUNCTION_NS_2 = + "urn:oasis:names:tc:xacml:2.0:function:"; + + // A List used by makeProcessingError() to save some steps. + private static List processingErrList = null; + + // the name of this function + private String functionName; + + // the id used by this function + private int functionId; + + // the return type of this function, and whether it's a bag + private String returnType; + private boolean returnsBag; + + // flag that tells us which of the two constructors was used + private boolean singleType; + + // parameter data if we're only using a single type + private String paramType; + private boolean paramIsBag; + private int numParams; + private int minParams; + + // paramater data if we're using different types + private List paramTypes; + private List paramsAreBags; + + private Logger logger = Logger.getLogger(FunctionBase.class); + + //private RuntimeInfo src; + private Stack src; + + /** + * Constructor that sets up the function as having some number of + * parameters all of the same given type. If numParams is + * -1, then the length is variable + * + * @param functionName the name of this function as used by the factory + * and any XACML policies + * @param functionId an optional identifier that can be used by your + * code for convenience + * @param paramType the type of all parameters to this function, as used + * by the factory and any XACML documents + * @param paramIsBag whether or not every parameter is actually a bag + * of values + * @param numParams the number of parameters required by this function, + * or -1 if any number are allowed + * @param returnType the type returned by this function, as used by + * the factory and any XACML documents + * @param returnsBag whether or not this function returns a bag of values + */ + public FunctionBase(String functionName, int functionId, String paramType, + boolean paramIsBag, int numParams, + String returnType, boolean returnsBag) { + this(functionName, functionId, returnType, returnsBag); + + this.singleType = true; + + this.paramType = paramType; + this.paramIsBag = paramIsBag; + this.numParams = numParams; + this.minParams = 0; + } + + /** + * Constructor that sets up the function as having some number of + * parameters all of the same given type. If numParams is + * -1, then the length is variable, and then minParams may + * be used to specify a minimum number of parameters. If + * numParams is not -1, then minParams is + * ignored. + * + * @param functionName the name of this function as used by the factory + * and any XACML policies + * @param functionId an optional identifier that can be used by your + * code for convenience + * @param paramType the type of all parameters to this function, as used + * by the factory and any XACML documents + * @param paramIsBag whether or not every parameter is actually a bag + * of values + * @param numParams the number of parameters required by this function, + * or -1 if any number are allowed + * @param minParams the minimum number of parameters required if + * numParams is -1 + * @param returnType the type returned by this function, as used by + * the factory and any XACML documents + * @param returnsBag whether or not this function returns a bag of values + */ + public FunctionBase(String functionName, int functionId, String paramType, + boolean paramIsBag, int numParams, int minParams, + String returnType, boolean returnsBag) { + this(functionName, functionId, returnType, returnsBag); + + this.singleType = true; + + this.paramType = paramType; + this.paramIsBag = paramIsBag; + this.numParams = numParams; + this.minParams = minParams; + } + + + /** + * Constructor that sets up the function as having different types for + * each given parameter. + * + * @param functionName the name of this function as used by the factory + * and any XACML policies + * @param functionId an optional identifier that can be used by your + * code for convenience + * @param paramTypes the type of each parameter, in order, required by + * this function, as used by the factory and any XACML + * documents + * @param paramIsBag whether or not each parameter is actually a bag + * of values + * @param returnType the type returned by this function, as used by + * the factory and any XACML documents + * @param returnsBag whether or not this function returns a bag of values + */ + public FunctionBase(String functionName, int functionId, + String [] paramTypes, boolean [] paramIsBag, + String returnType, boolean returnsBag) { + this(functionName, functionId, returnType, returnsBag); + + this.singleType = false; + + this.paramTypes = Arrays.asList(paramTypes); + this.paramsAreBags = new ArrayList(); + for (int i=0; i < paramIsBag.length; i++) { + this.paramsAreBags.add(Boolean.valueOf(paramIsBag[i])); + } + } + + /** + * Constructor that sets up some basic values for functions that will + * take care of parameter checking on their own. If you use this + * constructor for your function class, then you must override the + * two check methods to make sure that parameters are correct. + * + * @param functionName the name of this function as used by the factory + * and any XACML policies + * @param functionId an optional identifier that can be used by your + * code for convenience + * @param returnType the type returned by this function, as used by + * the factory and any XACML documents + * @param returnsBag whether or not this function returns a bag of values + */ + public FunctionBase(String functionName, int functionId, + String returnType, boolean returnsBag) { + this.functionName = functionName; + this.functionId = functionId; + this.returnType = returnType; + this.returnsBag = returnsBag; + } + + /** + * Returns the full identifier of this function, as known by the factories. + * + * @return the function's identifier + * + * @throws IllegalArgumentException if the identifier isn't a valid URI + */ + public URI getIdentifier() { + // this is to get around the exception handling problems, but may + // change if this code changes to include exceptions from the + // constructors + try { + return new URI(this.functionName); + } catch (URISyntaxException use) { + throw new IllegalArgumentException("invalid URI: " + this.functionName); + } + } + + /** + * Returns the name of the function to be handled by this particular + * object. + * + * @return the function name + */ + public String getFunctionName() { + return this.functionName; + } + + /** + * Returns the Identifier of the function to be handled by this + * particular object. + * + * @return the function Id + */ + public int getFunctionId() { + return this.functionId; + } + + /** + * Returns the same value as getReturnType. This is here + * to support the Expression interface. + * + * @return the return type + */ + public URI getType() { + return getReturnType(); + } + + /** + * Get the attribute type returned by this function. + * + * @return a URI indicating the attribute type + * returned by this function + */ + public URI getReturnType() { + try { + return new URI(this.returnType); + } catch (Exception e) { + return null; + } + } + + /** + * @return A Boolean determining + * wether the parameter(s) is bag(s) or not. Null if this is + * not a single type function. + */ + + public boolean getParamIsBag() { + return this.paramIsBag; + } + + /** + * Returns true if this function returns a bag of values. + * + * @return true if the function returns a bag, false otherwise + */ + public boolean returnsBag() { + return this.returnsBag; + } + + /** + * Returns the return type for this particular object. + * + * @return the return type + */ + public String getReturnTypeAsString() { + return this.returnType; + } + + /** + * Create an EvaluationResult that indicates a + * processing error with the specified message. This method + * may be useful to subclasses. + * + * @param message a description of the error + * (null if none) + * @return the desired EvaluationResult + */ + protected static EvaluationResult makeProcessingError(String message) { + // Build up the processing error Status. + if (processingErrList == null) { + String [] errStrings = { Status.STATUS_PROCESSING_ERROR }; + processingErrList = Arrays.asList(errStrings); + } + Status errStatus = new Status(processingErrList, message); + EvaluationResult processingError = new EvaluationResult(errStatus); + + return processingError; + } + + /** + * Evaluates each of the parameters, in order, filling in the argument + * array with the resulting values. If any error occurs, this method + * returns the error, otherwise null is returned, signalling that + * evaluation was successful for all inputs, and the resulting argument + * list can be used. + * + * @param params a List of Evaluatable + * objects representing the parameters to evaluate + * @param context the representation of the request + * @param args an array as long as the params List that + * will, on return, contain the AttributeValues + * generated from evaluating all parameters + * + * @return null if no errors were encountered, otherwise + * an EvaluationResult representing the error + */ + protected EvaluationResult evalArgs(List params, EvaluationCtx context, + AttributeValue [] args) { + Iterator it = params.iterator(); + int index = 0; + + while (it.hasNext()) { + // get and evaluate the next parameter + Evaluatable eval = (Evaluatable)(it.next()); + EvaluationResult result = eval.evaluate(context); + + // If there was an error, pass it back... + if (result.indeterminate()) { + return result; + } + // ...otherwise save it and keep going + args[index++] = result.getAttributeValue(); + } + + // if no error occurred then we got here, so we return no errors + return null; + } + + /** + * Default handling of input checking. This does some simple checking + * based on the type of constructor used. If you need anything more + * complex, or if you used the simple constructor, then you must + * override this method. + * + * @param inputs a List> of Evaluatables + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputs(List inputs) throws IllegalArgumentException { + checkInputs(inputs, null); + } + + /** + * Default handling of input checking. This does some simple checking + * based on the type of constructor used. If you need anything more + * complex, or if you used the simple constructor, then you must + * override this method. + * + * @param inputs a List> of Evaluatables + * @param src provides information about the source of the checked function, + * e.g., providing information in with file and which line number the error is located + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputs(List inputs, RuntimeInfo src) throws IllegalArgumentException { + // first off, see what kind of function we are + if (this.singleType) { + // first, check the length of the inputs, if appropriate + if (this.numParams != -1) { + if (inputs.size() != this.numParams) { + throw new IllegalArgumentException("wrong number of args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + } else { + if (inputs.size() < this.minParams) { + throw new IllegalArgumentException("not enough args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + } + + + // now, make sure everything is of the same, correct type + Iterator it = inputs.iterator(); + while (it.hasNext()) { + Evaluatable eval = (Evaluatable)(it.next()); + + if ( ! eval.getType().toString().equals(this.paramType)) { + throw new IllegalArgumentException("illegal parameter for function " + + this.getFunctionName() + ": expected " + this.paramType + + ", but got " + eval.getType() + + (src != null ? src.getLocationMsgForError() : "")); + } + + if ( eval.returnsBag() != this.paramIsBag) { + if ( this.paramIsBag ) { + throw new IllegalArgumentException("illegal parameter for function " + + this.getFunctionName() + ": required a bag, but got none" + + (src != null ? src.getLocationMsgForError() : "")); + } else { + throw new IllegalArgumentException("illegal parameter for function " + + this.getFunctionName() + ": no bag supported, but got one" + + (src != null ? src.getLocationMsgForError() : "")); + } + } + } + } else { + // first, check the length of the inputs + if (this.paramTypes.size() != inputs.size()) { + throw new IllegalArgumentException("wrong number of args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + + // now, make sure everything is of the same, correct type + Iterator it = inputs.iterator(); + int i = 0; + while (it.hasNext()) { + Evaluatable eval = (Evaluatable)(it.next()); + + if ( ! eval.getType().toString().equals(this.paramTypes.get(i))) { + throw new IllegalArgumentException("illegal parameter (" + i + + ") for function" + this.getFunctionName() + ": expected " + + this.paramTypes.get(i) + ", but received " + + eval.getType().toString() + + (src != null ? src.getLocationMsgForError() : "")); + } + + if ( eval.returnsBag() != ((Boolean)this.paramsAreBags.get(i)).booleanValue() ) { + if ( eval.returnsBag() ) { + throw new IllegalArgumentException("illegal parameter for function " + + this.getFunctionName() + ": no bag supported, but got one" + + (src != null ? src.getLocationMsgForError() : "")); + } else { + throw new IllegalArgumentException("illegal parameter for function " + + this.getFunctionName() + ": required a bag, but got none" + + (src != null ? src.getLocationMsgForError() : "")); + } + } + + + +// if ((! eval.getType().toString().equals( +// this.paramTypes.get(i))) +// || (eval.returnsBag() +// != ((Boolean)this.paramsAreBags +// .get(i)) +// .booleanValue())) { +// throw new IllegalArgumentException("illegal parameter"); +// } + i++; + } + } + } + + /** + * Default handling of input checking. This does some simple checking + * based on the type of constructor used. If you need anything more + * complex, or if you used the simple constructor, then you must + * override this method. + * + * @param inputs a List> of Evaluatables + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException { + checkInputsNoBag(inputs, null); + } + + /** + * Default handling of input checking. This does some simple checking + * based on the type of constructor used. If you need anything more + * complex, or if you used the simple constructor, then you must + * override this method. + * + * @param inputs a List> of Evaluatables + * @param src provides information about the source of the checked function, + * e.g., providing information in with file and which line number the error is located + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputsNoBag(List inputs, RuntimeInfo src) throws IllegalArgumentException { + // first off, see what kind of function we are + if (this.singleType) { + // first check to see if we need bags + if (this.paramIsBag) { + throw new IllegalArgumentException(this.functionName + "needs" + + "bags on input" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // now check on the length + if (this.numParams != -1) { + if (inputs.size() != this.numParams) { + throw new IllegalArgumentException("wrong number of args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + } else { + if (inputs.size() < this.minParams) { + throw new IllegalArgumentException("not enough args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + } + + // finally check param list + Iterator it = inputs.iterator(); + while (it.hasNext()) { + Evaluatable eval = it.next(); + + if (! eval.getType().toString().equals(this.paramType)) { + throw new IllegalArgumentException("illegal parameter (" + + eval.getType().toString() + " <> " + this.paramType + ")" + + (src != null ? src.getLocationMsgForError() : "")); + } + } + } else { + // first, check the length of the inputs + if (this.paramTypes.size() != inputs.size()) { + throw new IllegalArgumentException("wrong number of args" + + " to " + this.functionName + + (src != null ? src.getLocationMsgForError() : "")); + } + + // now, make sure everything is of the same, correct type + Iterator it = inputs.iterator(); + int i = 0; + while (it.hasNext()) { + Evaluatable eval = it.next(); + + if ((! eval.getType().toString().equals( + this.paramTypes.get(i))) + || ((Boolean)( + this.paramsAreBags.get(i))).booleanValue()) { + throw new IllegalArgumentException("illegal parameter" + + (src != null ? src.getLocationMsgForError() : "")); + } + i++; + } + } + } + + /** + * A utility method for the getters. + * + * @return True if the function has only one dataType of parameters. + */ + public boolean isSingleType() { + return this.singleType; + } + + /** + * @return The number of parameters for this function. + */ + public int getNumberOfParameters() { + if (this.singleType) { + return this.numParams; + } + return this.paramTypes.size(); + } + + /** + * @return The minimum number of parameters. + */ + public int getMinimumParameters() { + if (this.singleType) { + return this.minParams; + } + return this.paramTypes.size(); + } + + /** + * @return The parameter type for single parameter functions + * or null if this is not a single parameter function. + */ + public String getParamType() { + if (this.singleType) { + return this.paramType; + } + return null; + } + + /** + * @return The List of parameter types for multi parameter + * functions or null if this is a single parameter function. + */ + public List getParamTypes() { + if (this.singleType) { + return null; + } + return Collections.unmodifiableList(this.paramTypes); + } + + /** + * @return A List of Booleans determining + * wether the parameters are bags or not. Null if this is + * a single type function. + */ + public List getParamsAreBag() { + if (this.singleType) { + return null; + } + return Collections.unmodifiableList(this.paramsAreBags); + } + + /** + * Implements the IndirectLocatable interface + */ + public void setRuntimeInfo(RuntimeInfo src) { + if ( this.src == null ) { + this.src = new Stack(); + } + this.src.push(src); + //System.out.println("// set " + src.getLocationMsgRuntime() + " on stack position " + this.src.size()); + /* + + if ( this.src != null ) { + logger.warn("Overwriting SourceLocator! This indicates that " + + "serveral threads are used to query the enginge which " + + "should NOT be the case when the source locator feature " + + "is enabled (overwrite" + + ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + + ( src == null ? "null" : src.getLocationMsgForError())); + } + this.src = src; + + */ + } + + /** + * Implements the IndirectLocatable interface + */ + public void unsetRuntimeInfo(RuntimeInfo src) { + if ( this.src != null ) { + RuntimeInfo src_pop = this.src.pop(); + if ( src_pop != src ) { + logger.warn("Unset Source Locator Object which did not match the current " + + "element on the stack"); + this.src.removeAllElements(); + } + } + /* + + if ( src != this.src ) { + logger.warn("Unset Source Locator Object which is currently unvalid! (from " + + ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + + ( src == null ? "null" : src.getLocationMsgForError())); + } + this.src = null; + + */ + } + + public RuntimeInfo getRuntimeInfo() { + if ( this.src != null && this.src.size() > 0 ) { + return this.src.get(this.src.size()-1); + } else { + return null; + } + //return this.src; + } + + /** + * Encodes this FunctionBase into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this FunctionBase into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + out.println(indenter.makeString() + ""); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactory.java new file mode 100644 index 0000000..3695ba0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactory.java @@ -0,0 +1,566 @@ + +/* + * @(#)FunctionFactory.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; + +import java.net.URI; + +import java.util.HashMap; +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * Factory used to create all functions. There are three kinds of factories: + * general, condition, and target. These provide functions that can be used + * anywhere, only in a condition's root and only in a target (respectively). + *

    + * Note that all functions, except for abstract functions, are singletons, so + * any instance that is added to a factory will be the same one returned + * from the create methods. This is done because most functions don't have + * state, so there is no need to have more than one, or to spend the time + * creating multiple instances that all do the same thing. + * + * @since 1.0 + * @author Marco Barreno + * @author Seth Proctor + */ +public abstract class FunctionFactory +{ + + // the proxies used to get the default factorys + private static FunctionFactoryProxy defaultFactoryProxy; + + // the map of registered factories + private static HashMap registeredFactories; + + /** + * static intialiazer that sets up the default factory proxies and + * registers the standard namespaces + */ + static { + FunctionFactoryProxy proxy = new FunctionFactoryProxy() { + public FunctionFactory getTargetFactory() { + return StandardFunctionFactory.getTargetFactory(); + } + public FunctionFactory getConditionFactory() { + return StandardFunctionFactory.getConditionFactory(); + } + public FunctionFactory getGeneralFactory() { + return StandardFunctionFactory.getGeneralFactory(); + } + }; + registeredFactories = new HashMap(); + registeredFactories.put(Constants.XACML_1_0_IDENTIFIER, proxy); + registeredFactories.put(Constants.XACML_2_0_IDENTIFIER, proxy); + registeredFactories.put(Constants.XACML_3_0_IDENTIFIER, proxy); + defaultFactoryProxy = proxy; + } + + /** + * Default constructor. Used only by subclasses. + */ + protected FunctionFactory() { + //used only by subclasses + } + + /** + * Returns the default FunctionFactory that will only provide those + * functions that are usable in Target matching. + * + * @return a FunctionFactory for target functions + */ + public static final FunctionFactory getTargetInstance() { + return defaultFactoryProxy.getTargetFactory(); + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0 and 2.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return a FunctionFactory that supports Target functions + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final FunctionFactory getTargetInstance(String identifier) + throws UnknownIdentifierException + { + return getRegisteredProxy(identifier).getTargetFactory(); + } + + /** + * Returns the default FuntionFactory that will only provide those + * functions that are usable in the root of the Condition. These Functions + * are a superset of the Target functions. + * + * @return a FunctionFactory for condition functions + */ + public static final FunctionFactory getConditionInstance() { + return defaultFactoryProxy.getConditionFactory(); + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0 and 2.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return a FunctionFactory that supports Condition functions + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final FunctionFactory getConditionInstance(String identifier) + throws UnknownIdentifierException + { + return getRegisteredProxy(identifier).getConditionFactory(); + } + + /** + * Returns the default FunctionFactory that provides access to all the + * functions. These Functions are a superset of the Condition functions. + * + * @return a FunctionFactory for all functions + */ + public static final FunctionFactory getGeneralInstance() { + return defaultFactoryProxy.getGeneralFactory(); + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0 and 2.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return a FunctionFactory that supports General functions + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final FunctionFactory getGeneralInstance(String identifier) + throws UnknownIdentifierException + { + return getRegisteredProxy(identifier).getGeneralFactory(); + } + + /** + * Returns the default FunctionFactoryProxy that provides access to all + * the functions. + * + * @return a FunctionFactoryProxy for all functions + */ + public static final FunctionFactoryProxy getInstance() { + return defaultFactoryProxy; + } + + /** + * Returns a factory based on the given identifier. You may register + * as many factories as you like, and then retrieve them through this + * interface, but a factory may only be registered once using a given + * identifier. By default, the standard XACML 1.0 and 2.0 identifiers + * are regsietered to provide the standard factory. + * + * @param identifier the identifier for a factory + * + * @return a FunctionFactoryProxy + * + * @throws UnknownIdentifierException if the given identifier isn't + * registered + */ + public static final FunctionFactoryProxy getInstance(String identifier) + throws UnknownIdentifierException + { + return getRegisteredProxy(identifier); + } + + /** + * Private helper that resolves the proxy for the given identifier, or + * throws an exception if no proxy is registered for that identifier. + */ + private static FunctionFactoryProxy getRegisteredProxy(String identifier) + throws UnknownIdentifierException + { + FunctionFactoryProxy proxy = + (FunctionFactoryProxy)(registeredFactories.get(identifier)); + + if (proxy == null) { + throw new UnknownIdentifierException("Uknown FunctionFactory " + + "identifier: " + identifier); + } + return proxy; + } + + /** + * Sets the default factory. This does not register the factory proxy as + * an identifiable factory. + * + * @param proxy the FunctionFactoryProxy to set as the new + * default factory proxy + */ + public static final void setDefaultFactory(FunctionFactoryProxy proxy) { + defaultFactoryProxy = proxy; + } + + /** + * Registers the given factory proxy with the given identifier. If the + * identifier is already used, then this throws an exception. If the + * identifier is not already used, then it will always be bound to the + * given proxy. + * + * @param identifier the identifier for the proxy + * @param proxy the FunctionFactoryProxy to register with + * the given identifier + * + * @throws IllegalArgumentException if the identifier is already used + */ + public static final void registerFactory(String identifier, + FunctionFactoryProxy proxy) + throws IllegalArgumentException + { + synchronized (registeredFactories) { + if (registeredFactories.containsKey(identifier)) { + throw new IllegalArgumentException("Identifier is already " + + "registered as " + + "FunctionFactory: " + + identifier); + } + registeredFactories.put(identifier, proxy); + } + } + + /** + * Adds the function to the factory. Most functions have no state, so + * the singleton model used here is typically desireable. The factory will + * not enforce the requirement that a Target or Condition matching function + * must be boolean. If a function is already contained in the factory, an + * error will be thrown. + * + * @param function the Function to add to the factory + * + * @throws IllegalArgumentException if the function's identifier is already + * used + */ + public abstract void addFunction(Function function); + + + /** + * Adds the function to the factory. Most functions have no state, so + * the singleton model used here is typically desireable. The factory will + * not enforce the requirement that a Target or Condition matching function + * must be boolean. + * + * Allows to define if an already existing function should be overwritten + * or not. + * + * @param function the Function to add to the factory + * + * @throws IllegalArgumentException if the function's identifier is already + * used + */ + public abstract void addFunction(Function function, boolean overwrite); + + /** + * Adds the abstract function proxy to the factory. This is used for + * those functions which have state, or change behavior (for instance + * the standard map function, which changes its return type based on + * how it is used). + * + * @param proxy the FunctionProxy to add to the factory + * @param identity the function's identifier + * + * @throws IllegalArgumentException if the function's identifier is already + * used + */ + public abstract void addAbstractFunction(FunctionProxy proxy, + URI identity); + + /** + * Adds a target function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addFunction(Function)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param function the function to add + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addTargetFunction(Function function) { + getTargetInstance().addFunction(function); + } + + /** + * Adds an abstract target function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addAbstractFunction(FunctionProxy,URI)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param proxy the function proxy to add + * @param identity the name of the function + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addAbstractTargetFunction(FunctionProxy proxy, + URI identity) { + getTargetInstance().addAbstractFunction(proxy, identity); + } + + /** + * Adds a condition function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addFunction(Function)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param function the function to add + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addConditionFunction(Function function) { + getConditionInstance().addFunction(function); + } + + /** + * Adds an abstract condition function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addAbstractFunction(FunctionProxy,URI)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param proxy the function proxy to add + * @param identity the name of the function + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addAbstractConditionFunction(FunctionProxy proxy, + URI identity) { + getConditionInstance().addAbstractFunction(proxy, identity); + } + + /** + * Adds a general function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addFunction(Function)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param function the function to add + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addGeneralFunction(Function function) { + getGeneralInstance().addFunction(function); + } + + /** + * Adds an abstract general function. + * + * @deprecated As of version 1.2, replaced by + * {@link #addAbstractFunction(FunctionProxy,URI)}. + * The new factory system requires you to get a factory + * instance and then call the non-static methods on that + * factory. The static versions of these methods have been + * left in for now, but are slower and will be removed in + * a future version. + * + * @param proxy the function proxy to add + * @param identity the name of the function + * + * @throws IllegalArgumentException if the name is already in use + */ + public static void addAbstractGeneralFunction(FunctionProxy proxy, + URI identity) { + getGeneralInstance().addAbstractFunction(proxy, identity); + } + + /** + * Returns the function identifiers supported by this factory. + * + * @return a Set of Strings + */ + public abstract Set getSupportedFunctions(); + + /** + * Tries to get an instance of the specified function. + * + * @param identity the name of the function + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to an + * abstract function, and should therefore + * be created through createAbstractFunction + */ + public abstract Function createFunction(URI identity) + throws UnknownIdentifierException, FunctionTypeException; + + /** + * Tries to get an instance of the specified function. + * + * @param identity the name of the function + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to an + * abstract function, and should therefore + * be created through createAbstractFunction + */ + public abstract Function createFunction(String identity) + throws UnknownIdentifierException, FunctionTypeException; + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public abstract Function createAbstractFunction(URI identity, Node root) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException; + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * @param xpathVersion the version specified in the contianing policy, or + * null if no version was specified + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public abstract Function createAbstractFunction(URI identity, Node root, + String xpathVersion) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException; + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public abstract Function createAbstractFunction(String identity, Node root) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException; + + /** + * Tries to get an instance of the specified abstract function. + * + * @param identity the name of the function + * @param root the DOM root containing info used to create the function + * @param xpathVersion the version specified in the contianing policy, or + * null if no version was specified + * + * @return the function that was created. + * + * @throws UnknownIdentifierException if the name isn't known + * @throws FunctionTypeException if the name is known to map to a + * concrete function, and should therefore + * be created through createFunction + * @throws ParsingException if the function can't be created with the + * given inputs + */ + public abstract Function createAbstractFunction(String identity, Node root, + String xpathVersion) + throws UnknownIdentifierException, ParsingException, + FunctionTypeException; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactoryProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactoryProxy.java new file mode 100644 index 0000000..0070608 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionFactoryProxy.java @@ -0,0 +1,76 @@ + +/* + * @(#)FunctionFactoryProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + + +/** + * A simple proxy interface used to install new FunctionFactorys. + * The three kinds of factory (Target, Condition, and General) are tied + * together in this interface because implementors writing new factories + * should always implement all three types and provide them together. + * + * @since 1.2 + * @author Seth Proctor + */ +public interface FunctionFactoryProxy +{ + + /** + * Returns the Target version of an instance of the + * FunctionFactory for which this is a proxy. + * + * @return a FunctionFactory instance + */ + public FunctionFactory getTargetFactory(); + + /** + * Returns the Condition version of an instance of the + * FunctionFactory for which this is a proxy. + * + * @return a FunctionFactory instance + */ + public FunctionFactory getConditionFactory(); + + /** + * Returns the General version of an instance of the + * FunctionFactory for which this is a proxy. + * + * @return a FunctionFactory instance + */ + public FunctionFactory getGeneralFactory(); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionProxy.java new file mode 100644 index 0000000..5a5b5e3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionProxy.java @@ -0,0 +1,70 @@ + +/* + * @(#)FunctionProxy.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import org.w3c.dom.Node; + + +/** + * Used by abstract functions to define how new functions are created by + * the factory. Note that all functions using XPath are defined to be + * abstract functions, so they must be created using this interface. + * + * @since 1.0 + * @author Seth Proctor + */ +public interface FunctionProxy +{ + + /** + * Creates an instance of some abstract function. If the function + * being created is not using XPath, then the version parameter can be + * ignored, otherwise a value must be present and the version must + * be acceptable. + * + * @param root the DOM root of the apply statement containing the function + * @param xpathVersion the version specified in the contianing policy, or + * null if no version was specified + * + * @return the function + * + * @throws Exception if the underlying code experienced any error + */ + public Function getInstance(Node root, String xpathVersion) + throws Exception; + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionTypeException.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionTypeException.java new file mode 100644 index 0000000..0f79785 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/FunctionTypeException.java @@ -0,0 +1,107 @@ + +/* + * @(#)FunctionTypeException.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + + +/** + * Exception that gets thrown if one of the createFunction methods on the + * FunctionFactory was called, but the other method should have + * been called instead. + * + * @since 1.0 + * @author Seth Proctor + */ +public class FunctionTypeException extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new FunctionTypeException with no message + * or cause. + */ + public FunctionTypeException() { + // no message or cause + } + + /** + * Constructs a new FunctionTypeException with a message, + * but no cause. The message is saved for later retrieval by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} + * method. + * + * @param message the detail message (null if nonexistent + * or unknown) + */ + public FunctionTypeException(String message) { + super(message); + } + + /** + * Constructs a new FunctionTypeException with a cause, + * but no message. The cause is saved for later retrieval by the + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * method. + * + * @param cause the cause (null if nonexistent + * or unknown) + */ + public FunctionTypeException(Throwable cause) { + super(cause); + } + + /** + * Constructs a new FunctionTypeException with a message + * and a cause. The message and cause are saved for later retrieval + * by the + * {@link java.lang.Throwable#getMessage() Throwable.getMessage()} and + * {@link java.lang.Throwable#getCause() Throwable.getCause()} + * methods. + * + * @param message the detail message (null if nonexistent + * or unknown) + * @param cause the cause (null if nonexistent + * or unknown) + */ + public FunctionTypeException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralBagFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralBagFunction.java new file mode 100644 index 0000000..b5380ae --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralBagFunction.java @@ -0,0 +1,371 @@ + +/* + * @(#)GeneralBagFunction.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * Specific BagFunction class that supports all of the + * general-purpose bag functions: type-one-and-only, type-bag-size, and + * type-bag. + * + * @since 1.2 + * @author Seth Proctor + */ +public class GeneralBagFunction extends BagFunction +{ + + // private identifiers for the supported functions + private static final int ID_BASE_ONE_AND_ONLY = 0; + private static final int ID_BASE_BAG_SIZE = 1; + private static final int ID_BASE_BAG = 2; + + // mapping of function name to its associated parameters + private static HashMap paramMap; + private static Set supportedIds; + + /** + * Static initializer that sets up the parameter info for all the + * supported functions. + */ + static { + paramMap = new HashMap(); + + for (int i = 0; i < baseTypes.length; i++) { + String baseType = baseTypes[i]; + String functionBaseName = FUNCTION_NS + simpleTypes[i]; + + paramMap.put(functionBaseName + NAME_BASE_ONE_AND_ONLY, + new BagParameters(ID_BASE_ONE_AND_ONLY, baseType, + true, 1, baseType, false)); + + paramMap.put(functionBaseName + NAME_BASE_BAG_SIZE, + new BagParameters(ID_BASE_BAG_SIZE, baseType, true, + 1, IntegerAttribute.identifier, + false)); + + paramMap.put(functionBaseName + NAME_BASE_BAG, + new BagParameters(ID_BASE_BAG, baseType, false, -1, + baseType, true)); + } + + for (int i = 0; i < baseTypes2.length; i++) { + String baseType = baseTypes2[i]; + String functionBaseName = FUNCTION_NS_2 + simpleTypes2[i]; + + paramMap.put(functionBaseName + NAME_BASE_ONE_AND_ONLY, + new BagParameters(ID_BASE_ONE_AND_ONLY, baseType, + true, 1, baseType, false)); + + paramMap.put(functionBaseName + NAME_BASE_BAG_SIZE, + new BagParameters(ID_BASE_BAG_SIZE, baseType, true, + 1, IntegerAttribute.identifier, + false)); + + paramMap.put(functionBaseName + NAME_BASE_BAG, + new BagParameters(ID_BASE_BAG, baseType, false, -1, + baseType, true)); + } + + supportedIds = Collections. + unmodifiableSet(new HashSet(paramMap.keySet())); + + paramMap.put(NAME_BASE_ONE_AND_ONLY, + new BagParameters(ID_BASE_ONE_AND_ONLY, null, true, 1, + null, false)); + paramMap.put(NAME_BASE_BAG_SIZE, + new BagParameters(ID_BASE_BAG_SIZE, null, true, 1, + IntegerAttribute.identifier, false)); + paramMap.put(NAME_BASE_BAG, + new BagParameters(ID_BASE_BAG, null, false, -1, null, + true)); + + + } + + /** + * Constructor that is used to create one of the general-purpose standard + * bag functions. The name supplied must be one of the standard XACML + * functions supported by this class, including the full namespace, + * otherwise an exception is thrown. Look in BagFunction + * for details about the supported names. + * + * @param functionName the name of the function to create + * + * @throws IllegalArgumentException if the function is unknown + */ + public GeneralBagFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + getIsBag(functionName), getNumArgs(functionName), + getReturnType(functionName), getReturnsBag(functionName)); + } + + /** + * Constructor that is used to create instances of general-purpose bag + * functions for new (non-standard) datatypes. This is equivalent to + * using the getInstance methods in BagFunction + * and is generally only used by the run-time configuration code. + * + * @param functionName the name of the new function + * @param datatype the full identifier for the supported datatype + * @param functionType which kind of Bag function, based on the + * NAME_BASE_* fields + */ + public GeneralBagFunction(String functionName, String datatype, + String functionType) { + super(functionName, getId(functionType), datatype, + getIsBag(functionType), getNumArgs(functionType), + getCustomReturnType(functionType, datatype), + getReturnsBag(functionType)); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + BagParameters params = (BagParameters)(paramMap.get(functionName)); + + if (params == null) { + throw new IllegalArgumentException("unknown bag function: " + + functionName); + } + return params.id; + } + + /** + * Private helper that returns the argument type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + return ((BagParameters)(paramMap.get(functionName))).arg; + } + + /** + * Private helper that returns if the given standard function takes + * a bag. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static boolean getIsBag(String functionName) { + return ((BagParameters)(paramMap.get(functionName))).argIsBag; + } + + /** + * Private helper that returns the argument count for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static int getNumArgs(String functionName) { + return ((BagParameters)(paramMap.get(functionName))).params; + } + + /** + * Private helper that returns the return type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getReturnType(String functionName) { + return ((BagParameters)(paramMap.get(functionName))).returnType; + } + + /** + * Private helper that returns if the return type is a bag for the given + * standard function. Note that this doesn't check on the return value + * since the method always is called after getId, so we assume that the + * function is present. + */ + private static boolean getReturnsBag(String functionName) { + return ((BagParameters)(paramMap.get(functionName))).returnsBag; + } + + /** + * Private helper used by the custom datatype constructor to figure out + * what the return type is. Note that this doesn't check on the return + * value since the method always is called after getId, so we assume that + * the function is present. + */ + private static String getCustomReturnType(String functionType, + String datatype) { + String ret = ((BagParameters)(paramMap.get(functionType))).returnType; + + if (ret == null) { + return datatype; + } + return ret; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return supportedIds; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the requested operation. + AttributeValue attrResult = null; + + switch (getFunctionId()) { + + // *-one-and-only takes a single bag and returns a + // single value of baseType + case ID_BASE_ONE_AND_ONLY: { + BagAttribute bag = (BagAttribute)(argValues[0]); + + if (bag.size() != 1) { + //return new EvaluationResult(Status) + return makeProcessingError(getFunctionName() + " expects " + + "a bag that contains a single element," + + "got a bag with " + bag.size() + " elements"); + } + attrResult = (AttributeValue)(bag.iterator().next()); + break; + } + + // *-size takes a single bag and returns an integer + case ID_BASE_BAG_SIZE: { + BagAttribute bag = (BagAttribute)(argValues[0]); + + attrResult = new IntegerAttribute(bag.size()); + break; + } + + // *-bag takes any number of elements of baseType and + // returns a bag containing those elements + case ID_BASE_BAG: { + List argsList = Arrays.asList(argValues); + + attrResult = new BagAttribute(getReturnType(), argsList); + break; + } + } + + return new EvaluationResult(attrResult); + } + + /** + * Private class that is used for mapping each function to it set of + * parameters. + */ + private static class BagParameters { + /** + * + */ + public int id; + + /** + * + */ + public String arg; + + /** + * + */ + public boolean argIsBag; + + /** + * + */ + public int params; + + /** + * + */ + public String returnType; + + /** + * + */ + public boolean returnsBag; + + /** + * @param id + * @param arg + * @param argIsBag + * @param params + * @param returnType + * @param returnsBag + */ + public BagParameters(int id, String arg, boolean argIsBag, int params, + String returnType, boolean returnsBag) { + this.id = id; + this.arg = arg; + this.argIsBag = argIsBag; + this.params = params; + this.returnType = returnType; + this.returnsBag = returnsBag; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralSetFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralSetFunction.java new file mode 100644 index 0000000..a4dc397 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/GeneralSetFunction.java @@ -0,0 +1,245 @@ + +/* + * @(#)GeneralSetFunction.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * Specific SetFunction class that supports all of the + * general-purpose set functions: type-intersection and type-union. + * + * @since 1.2 + * @author Seth Proctor + */ +public class GeneralSetFunction extends SetFunction +{ + + // private identifiers for the supported functions + private static final int ID_BASE_INTERSECTION = 0; + private static final int ID_BASE_UNION = 1; + + // mapping of function name to its associated id and parameter type + private static HashMap idMap; + private static HashMap typeMap; + + /** + * Static initializer that sets up the parameter info for all the + * supported functions. + */ + static { + idMap = new HashMap(); + typeMap = new HashMap(); + + idMap.put(NAME_BASE_INTERSECTION, Integer.valueOf(ID_BASE_INTERSECTION)); + idMap.put(NAME_BASE_UNION, Integer.valueOf(ID_BASE_UNION)); + + for (int i = 0; i < baseTypes.length; i++) { + String baseName = FUNCTION_NS + simpleTypes[i]; + String baseType = baseTypes[i]; + + idMap.put(baseName + NAME_BASE_INTERSECTION, + Integer.valueOf(ID_BASE_INTERSECTION)); + idMap.put(baseName + NAME_BASE_UNION, + Integer.valueOf(ID_BASE_UNION)); + + typeMap.put(baseName + NAME_BASE_INTERSECTION, baseType); + typeMap.put(baseName + NAME_BASE_UNION, baseType); + } + + for (int i = 0; i < baseTypes2.length; i++) { + String baseName = FUNCTION_NS_2 + simpleTypes2[i]; + String baseType = baseTypes2[i]; + + idMap.put(baseName + NAME_BASE_INTERSECTION, + Integer.valueOf(ID_BASE_INTERSECTION)); + idMap.put(baseName + NAME_BASE_UNION, + Integer.valueOf(ID_BASE_UNION)); + + typeMap.put(baseName + NAME_BASE_INTERSECTION, baseType); + typeMap.put(baseName + NAME_BASE_UNION, baseType); + } + } + + /** + * Constructor that is used to create one of the general-purpose standard + * set functions. The name supplied must be one of the standard XACML + * functions supported by this class, including the full namespace, + * otherwise an exception is thrown. Look in SetFunction + * for details about the supported names. + * + * @param functionName the name of the function to create + * + * @throws IllegalArgumentException if the function is unknown + */ + public GeneralSetFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + getArgumentType(functionName), true); + } + + /** + * Constructor that is used to create instances of general-purpose set + * functions for new (non-standard) datatypes. This is equivalent to + * using the getInstance methods in SetFunction + * and is generally only used by the run-time configuration code. + * + * @param functionName the name of the new function + * @param datatype the full identifier for the supported datatype + * @param functionType which kind of Set function, based on the + * NAME_BASE_* fields + */ + public GeneralSetFunction(String functionName, String datatype, + String functionType) { + super(functionName, getId(functionType), datatype, datatype, true); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + Integer id = (Integer)(idMap.get(functionName)); + + if (id == null) { + throw new IllegalArgumentException("unknown set function " + + functionName); + } + return id.intValue(); + } + + /** + * Private helper that returns the argument type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + return (String)(typeMap.get(functionName)); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(idMap.keySet()); + } + + /** + * Evaluates the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult evalResult = evalArgs(inputs, context, argValues); + if (evalResult != null) { + return evalResult; + } + // setup the two bags we'll be using + BagAttribute [] bags = new BagAttribute[2]; + bags[0] = (BagAttribute)(argValues[0]); + bags[1] = (BagAttribute)(argValues[1]); + + AttributeValue result = null; + Set set = new HashSet(); + + if (getFunctionId() == ID_BASE_INTERSECTION) { + // *-intersection takes two bags of the same type and returns + // a bag of that type + + // create a bag with the common elements of both inputs, removing + // all duplicate values + Iterator it = bags[0].iterator(); + + // find all the things in bags[0] that are also in bags[1] + while (it.hasNext()) { + AttributeValue value = it.next(); + if (bags[1].contains(value)) { + // sets won't allow duplicates, so this addition is ok + set.add(value); + } + } + + result = new BagAttribute(bags[0].getType(), set); + + } else if (getFunctionId() == ID_BASE_UNION) { + // *-union takes two bags of the same type and returns a bag of + // that type + + // create a bag with all the elements from both inputs, removing + // all duplicate values + Iterator it0 = bags[0].iterator(); + while (it0.hasNext()) { + // first off, add all elements from the first bag...the set + // will ignore all duplicates + set.add(it0.next()); + } + + Iterator it1 = bags[1].iterator(); + while (it1.hasNext()) { + // now add all the elements from the second bag...again, all + // duplicates will be ignored by the set + set.add(it1.next()); + } + + result = new BagAttribute(bags[0].getType(), set); + } + + return new EvaluationResult(result); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/HigherOrderFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/HigherOrderFunction.java new file mode 100644 index 0000000..f1bf69e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/HigherOrderFunction.java @@ -0,0 +1,715 @@ + +/* + * @(#)HigherOrderFunction.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; + + +/** + * Represents all of the higher order bag functions, except map, which has + * its own class due to the issues with its return type. Unlike the other + * functions that are designed to work over any types (the type-* functions) + * these functions don't use specific names to describe what type they + * operate over, so you don't need to install new instances for any new + * datatypes you define. + * + * @since 1.0 + * @author Seth Proctor + */ +public class HigherOrderFunction implements Function +{ + + /** + * Standard identifier for the any-of function. + */ + public static final String NAME_ANY_OF = + FunctionBase.FUNCTION_NS + "any-of"; + + /** + * Standard identifier for the all-of function. + */ + public static final String NAME_ALL_OF = + FunctionBase.FUNCTION_NS + "all-of"; + + /** + * Standard identifier for the any-of-any function. + */ + public static final String NAME_ANY_OF_ANY = + FunctionBase.FUNCTION_NS + "any-of-any"; + + /** + * Standard identifier for the all-of-any function. + */ + public static final String NAME_ALL_OF_ANY = + FunctionBase.FUNCTION_NS + "all-of-any"; + + /** + * Standard identifier for the any-of-all function. + */ + public static final String NAME_ANY_OF_ALL = + FunctionBase.FUNCTION_NS + "any-of-all"; + + /** + * Standard identifier for the all-of-all function. + */ + public static final String NAME_ALL_OF_ALL = + FunctionBase.FUNCTION_NS + "all-of-all"; + + // internal identifiers for each of the supported functions + private static final int ID_ANY_OF = 0; + private static final int ID_ALL_OF = 1; + private static final int ID_ANY_OF_ANY = 2; + private static final int ID_ALL_OF_ANY = 3; + private static final int ID_ANY_OF_ALL = 4; + private static final int ID_ALL_OF_ALL = 5; + + // internal mapping of names to ids + private static HashMap idMap; + + // the internal identifier for each function + private int functionId; + + // the real identifier for each function + private URI identifier; + + // should the second argument (the first arg passed to the sub-function) + // be a bag + private boolean secondIsBag; + + // the stuff used to make sure that we have a valid return type or a + // known error, just like in the attribute classes + private static URI returnTypeURI; + private static RuntimeException earlyException; + + private static Logger logger = Logger.getLogger(HigherOrderFunction.class); + + private RuntimeInfo src; + + // try to create the return type URI, and also setup the id map + static { + try { + returnTypeURI = URI.create(BooleanAttribute.identifier); + } catch (IllegalArgumentException e) { + earlyException = e; + } + + idMap = new HashMap(); + + idMap.put(NAME_ANY_OF, Integer.valueOf(ID_ANY_OF)); + idMap.put(NAME_ALL_OF, Integer.valueOf(ID_ALL_OF)); + idMap.put(NAME_ANY_OF_ANY, Integer.valueOf(ID_ANY_OF_ANY)); + idMap.put(NAME_ALL_OF_ANY, Integer.valueOf(ID_ALL_OF_ANY)); + idMap.put(NAME_ANY_OF_ALL, Integer.valueOf(ID_ANY_OF_ALL)); + idMap.put(NAME_ALL_OF_ALL, Integer.valueOf(ID_ALL_OF_ALL)); + } + + /** + * Creates a new instance of the given function. + * + * @param functionName the function to create + * + * @throws IllegalArgumentException if the function is unknown + */ + public HigherOrderFunction(String functionName) { + // try to get the function's identifier + Integer i = (Integer)(idMap.get(functionName)); + if (i == null) { + throw new IllegalArgumentException("unknown function: " + + functionName); + } + this.functionId = i.intValue(); + + // setup the URI form of this function's idenitity + try { + this.identifier = new URI(functionName); + } catch (URISyntaxException use) { + throw new IllegalArgumentException("invalid URI"); + } + + // see if the second arg is a bag + if ((this.functionId != ID_ANY_OF) && (this.functionId != ID_ALL_OF)) { + this.secondIsBag = true; + } + else { + this.secondIsBag = false; + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + return Collections.unmodifiableSet(idMap.keySet()); + } + + /** + * Returns the full identifier of this function, as known by the factories. + * + * @return the function's identifier + */ + public URI getIdentifier() { + return this.identifier; + } + + /** + * Returns the same value as getReturnType. This is here + * to support the Expression interface. + * + * @return the return type + */ + public URI getType() { + return getReturnType(); + } + + /** + * Returns the type of attribute value that will be returned by + * this function. + * + * @return the return type + */ + public URI getReturnType() { + if (earlyException != null) { + throw earlyException; + } + + return returnTypeURI; + } + + /** + * Returns whether or not this function will actually return a bag + * of values. + * + * @return true if the function returns a bag of values, otherwise false + */ + public boolean returnsBag() { + return false; + } + + /** + * Evaluates the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + Iterator iterator = inputs.iterator(); + + // get the first arg, which is the function + Expression xpr = iterator.next(); + Function function = null; + + if (xpr instanceof Function) { + function = (Function)xpr; + } else { + function = (Function)(((VariableReference)xpr). + getReferencedDefinition().getExpression()); + } + + + // get the two inputs, and if anything is INDETERMINATE, then we + // stop right away + AttributeValue [] args = new AttributeValue[2]; + + Evaluatable eval = (Evaluatable)(iterator.next()); + EvaluationResult result = eval.evaluate(context); + if (result.indeterminate()) { + return result; + } + args[0] = (result.getAttributeValue()); + + eval = (Evaluatable)(iterator.next()); + result = eval.evaluate(context); + if (result.indeterminate()) { + return result; + } + args[1] = (result.getAttributeValue()); + + // now we're ready to do the evaluation + result = null; + + switch(this.functionId) { + + case ID_ANY_OF: { + + // param: boolean-function, single value, bag of same type + // return: boolean + // using the function, iterate through the bag, and if one + // of the bag elements matches the single value, return + // true, otherwise return false + + result = any(args[0], (BagAttribute)(args[1]), function, context, + false); + break; + } + + case ID_ALL_OF: { + + // param: boolean-function, single value, bag of same type + // return: boolean + // using the function, iterate through the bag, and if all + // of the bag elements match the single value, return + // true, otherwise return false + + result = all(args[0], (BagAttribute)(args[1]), function, context); + break; + } + + case ID_ANY_OF_ANY: { + + // param: boolean-function, bag, bag of same type + // return: boolean + // apply the function to every combination of a single value from + // the first bag and a single value from the second bag, and if + // any evaluation is true return true, otherwise return false + + result = new EvaluationResult(BooleanAttribute.getInstance(false)); + Iterator it = ((BagAttribute)args[0]).iterator(); + BagAttribute bag = (BagAttribute)(args[1]); + + while (it.hasNext()) { + AttributeValue value = it.next(); + result = any(value, bag, function, context, false); + + if (result.indeterminate()) { + return result; + } + + if (((BooleanAttribute)(result. + getAttributeValue())).getValue()) { + break; + } + } + break; + } + + case ID_ALL_OF_ANY: { + + // param: boolean-function, bag, bag of same type + // return: boolean + // iterate through the first bag, and if for each of those values + // one of the values in the second bag matches then return true, + // otherwise return false + + result = allOfAny((BagAttribute)(args[1]), (BagAttribute)(args[0]), + function, context); + break; + } + + case ID_ANY_OF_ALL: { + + // param: boolean-function, bag, bag of same type + // return: boolean + // iterate through the second bag, and if for each of those values + // one of the values in the first bag matches then return true, + // otherwise return false + + result = anyOfAll((BagAttribute)(args[0]), (BagAttribute)(args[1]), + function, context); + break; + } + + case ID_ALL_OF_ALL: { + + // param: boolean-function, bag, bag of same type + // return: boolean + // iterate through the first bag, and for each of those values + // if every value in the second bag matches using the given + // function, then return true, otherwise return false + + result = new EvaluationResult(BooleanAttribute.getInstance(true)); + Iterator it = ((BagAttribute)args[0]).iterator(); + BagAttribute bag = (BagAttribute)(args[1]); + + while (it.hasNext()) { + AttributeValue value = (AttributeValue)(it.next()); + result = all(value, bag, function, context); + + if (result.indeterminate()) { + return result; + } + + if (! ((BooleanAttribute)(result. + getAttributeValue())).getValue()) { + break; + } + } + break; + } + + } + + return result; + } + + /** + * Checks that the given inputs are valid for this function. + * + * @param inputs a List of Evaluatables + * + * @throws IllegalArgumentException if the inputs are invalid + */ + public void checkInputs(List inputs) throws IllegalArgumentException { + checkInputs(inputs, null); + } + + /** + * Checks that the given inputs are valid for this function. + * + * @param inputs a List of Evaluatables + * + * @throws IllegalArgumentException if the inputs are invalid + */ + public void checkInputs(List inputs, RuntimeInfo src) throws IllegalArgumentException { + Object [] list = inputs.toArray(); + + // first off, check that we got the right number of paramaters + if (list.length != 3) { + throw new IllegalArgumentException("requires three inputs" + + (src != null ? src.getLocationMsgForError() : "")); + } + // now, try to cast the first element into a function + Function function = null; + + if (list[0] instanceof Function) { + function = (Function)(list[0]); + } else if (list[0] instanceof VariableReference) { + Expression xpr = ((VariableReference)(list[0])). + getReferencedDefinition().getExpression(); + if (xpr instanceof Function) { + function = (Function)xpr; + } + } + + if (function == null) { + throw new IllegalArgumentException("first arg to higher-order " + + " function must be a function" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // check that the function returns a boolean + if (! function.getReturnType().toString(). + equals(BooleanAttribute.identifier)) { + throw new IllegalArgumentException("higher-order function must " + + "use a boolean function" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // get the two inputs + Evaluatable eval1 = (Evaluatable)(list[1]); + Evaluatable eval2 = (Evaluatable)(list[2]); + + // make sure the two args are of the same type + if (! eval1.getType().equals(eval2.getType())) { + throw new IllegalArgumentException("input types to the any/all " + + "functions must match" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // the first arg might be a bag + if (this.secondIsBag && (! eval1.returnsBag())) { + throw new IllegalArgumentException("first arg has to be a bag" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // the second arg must be a bag + if (! eval2.returnsBag()) { + throw new IllegalArgumentException("second arg has to be a bag" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // finally, we need to make sure that the given type will work on + // the given function + List args = new ArrayList(); + args.add(eval1); + args.add(eval2); + function.checkInputsNoBag(args); + } + /** + * Checks that the given inputs are valid for this function if all + * inputs are considered to not be bags. This always throws an + * exception, since this function by definition must work on bags. + * + * @param inputs a List of Evaluatables + * + * @throws IllegalArgumentException always + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException { + checkInputsNoBag(inputs, null); + } + + /** + * Checks that the given inputs are valid for this function if all + * inputs are considered to not be bags. This always throws an + * exception, since this function by definition must work on bags. + * + * @param inputs a List of Evaluatables + * + * @throws IllegalArgumentException always + */ + public void checkInputsNoBag(List inputs, RuntimeInfo src) throws IllegalArgumentException { + throw new IllegalArgumentException("higher-order functions require " + + "use of bags"); + } + + /** + * Private helper function that performs the any function, but lets you + * swap the argument order (so it can be used by any-of-all) + */ + private EvaluationResult any(AttributeValue value, BagAttribute bag, + Function function, EvaluationCtx context, + boolean argumentsAreSwapped) { + return anyAndAllHelper(value, bag, function, context, false, + argumentsAreSwapped); + } + + /** + * Private helper function that performs the all function + */ + private EvaluationResult all(AttributeValue value, BagAttribute bag, + Function function, EvaluationCtx context) { + return anyAndAllHelper(value, bag, function, context, true, false); + } + + /** + * Private helper for any & all functions + */ + private EvaluationResult anyAndAllHelper(AttributeValue value, + BagAttribute bag, + Function function, + EvaluationCtx context, + boolean allFunction, + boolean argumentsAreSwapped) { + BooleanAttribute attr = BooleanAttribute.getInstance(allFunction); + Iterator it = bag.iterator(); + + while (it.hasNext()) { + List params = new ArrayList(); + + if (argumentsAreSwapped) { + params.add((it.next())); + params.add(value); + } else { + params.add(value); + params.add((it.next())); + } + + //Do some event recoding for the function + context.newEvent(function); + + //set (context dependent) source locator for function + RuntimeInfo funcSrc = null; + if ( src != null ) { + funcSrc = src.getIndirectRuntimeInfo(function, ELEMENT_TYPE.FUNCTION); + function.setRuntimeInfo(funcSrc); + } + + EvaluationResult result = function.evaluate(params, context); + //unset source locator + if ( funcSrc != null ) { + function.unsetRuntimeInfo(funcSrc) ; + } + + //Record the result for the function + context.closeCurrentEvent(result); + + if (result.indeterminate()) { + return result; + } + + BooleanAttribute bool = + (BooleanAttribute)(result.getAttributeValue()); + if (bool.getValue() != allFunction) { + attr = bool; + break; + } + } + + return new EvaluationResult(attr); + } + + /** + * any-of-all + */ + private EvaluationResult anyOfAll(BagAttribute anyBag, BagAttribute allBag, + Function function, + EvaluationCtx context) { + return allAnyHelper(anyBag, allBag, function, context, true); + } + + /** + * all-of-any + */ + private EvaluationResult allOfAny(BagAttribute anyBag, BagAttribute allBag, + Function function, + EvaluationCtx context) { + return allAnyHelper(anyBag, allBag, function, context, false); + } + + /** + * Private helper for the all-of-any and any-of-all functions + */ + private EvaluationResult allAnyHelper(BagAttribute anyBag, + BagAttribute allBag, + Function function, + EvaluationCtx context, + boolean argumentsAreSwapped) { + Iterator it = allBag.iterator(); + + while (it.hasNext()) { + AttributeValue value = (AttributeValue)(it.next()); + EvaluationResult result = + any(value, anyBag, function, context, argumentsAreSwapped); + + if (result.indeterminate()) { + return result; + } + + if (! ((BooleanAttribute)(result. + getAttributeValue())).getValue()) { + return result; + } + } + + return new EvaluationResult(BooleanAttribute.getTrueInstance()); + } + + /** + * Encodes this HigherOrderFunction into its XML + * representation and writes this encoding to the given + * OutputStream with no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this HigherOrderFunction into its XML + * representation and writes this encoding to the given + * OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + out.println(indenter.makeString() + ""); + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + + public void setRuntimeInfo(RuntimeInfo src) { + if ( this.src != null ) { + logger.warn("Overwriting SourceLocator! This indicates that " + + "serveral threads are used to query the enginge which " + + "should NOT be the case when the source locator feature " + + "is enabled (overwrite" + + ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + + ( src == null ? "null" : src.getLocationMsgForError())); + } + this.src = src; +// if (logger.isDebugEnabled() ) { +// logger.debug("Set SourceLocator for Function " + this.getIdentifier() + " (" + (src != null ? src.getLocationMsgForError() : "no src") + ")"); +// } + } + + public void unsetRuntimeInfo(RuntimeInfo src) { + if ( src != this.src ) { + logger.warn("Unset Source Locator Object which is currently unvalid! (from " + + ( this.src == null ? "null" : this.src.getLocationMsgForError()) + " with " + + ( src == null ? "null" : src.getLocationMsgForError())); + } + this.src = null; +// if (logger.isDebugEnabled() ) { +// logger.debug("Unset SourceLocator for Function " + this.getIdentifier() + " (" + (src != null ? src.getLocationMsgForError() : "no src") + ")"); +// } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/LogicalFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/LogicalFunction.java new file mode 100644 index 0000000..dbd41ca --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/LogicalFunction.java @@ -0,0 +1,165 @@ + +/* + * @(#)LogicalFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the logical functions "or" and "and". + * These functions take any number of boolean arguments and evaluate + * them one at a time, starting with the first argument. As soon as + * the result of the function can be determined, evaluation stops and + * that result is returned. During this process, if any argument + * evaluates to indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class LogicalFunction extends FunctionBase +{ + + /** + * Standard identifier for the or function. + */ + public static final String NAME_OR = FUNCTION_NS + "or"; + + /** + * Standard identifier for the and function. + */ + public static final String NAME_AND = FUNCTION_NS + "and"; + + // internal identifiers for each of the supported functions + private static final int ID_OR = 0; + private static final int ID_AND = 1; + + /** + * Creates a new LogicalFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the functionName is unknown + */ + public LogicalFunction(String functionName) { + super(functionName, getId(functionName), BooleanAttribute.identifier, + false, -1, BooleanAttribute.identifier, false); + } + + /** + * Private helper that looks up the private id based on the function name. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_OR)) { + return ID_OR; + } else if (functionName.equals(NAME_AND)) { + return ID_AND; + } else { + throw new IllegalArgumentException("unknown logical function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_OR); + set.add(NAME_AND); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments one by one. As soon as we can + // return a result, do so. Return Indeterminate if any argument + // evaluated is indeterminate. + Iterator it = inputs.iterator(); + while (it.hasNext()) { + Evaluatable eval = (Evaluatable)(it.next()); + + // Evaluate the argument + EvaluationResult result = eval.evaluate(context); + if (result.indeterminate()) { + return result; + } + + AttributeValue value = result.getAttributeValue(); + boolean argBooleanValue = ((BooleanAttribute)value).getValue(); + + if (getFunctionId() == ID_OR) { + if (argBooleanValue) { + return EvaluationResult.getTrueInstance(); + } + } else if (getFunctionId() == ID_AND) { + if (!argBooleanValue) { + return EvaluationResult.getFalseInstance(); + } + } + } + + if (getFunctionId() == ID_OR) { + return EvaluationResult.getFalseInstance(); + } + return EvaluationResult.getTrueInstance(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunction.java new file mode 100644 index 0000000..d984b9b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunction.java @@ -0,0 +1,420 @@ + +/* + * @(#)MapFunction.java 1.4 01/30/03 + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.debug.RuntimeInfo; + +import java.net.URI; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the higher order bag function map. + * + * @since 1.0 + * @author Seth Proctor + */ +class MapFunction implements Function +{ + + /** + * The name of this function + */ + public static final String NAME_MAP = FunctionBase.FUNCTION_NS + "map"; + + // the return type for this instance + private URI returnType; + + // the stuff used to make sure that we have a valid identifier or a + // known error, just like in the attribute classes + private static URI identifier; + private static RuntimeException earlyException; + + private static Logger logger = Logger.getLogger(MapFunction.class); + + // try to initialize the identifier + static { + try { + identifier = URI.create(NAME_MAP); + } catch (IllegalArgumentException e) { + earlyException = e; + } + } + + /** + * Creates a new instance of a MapFunction. + * + * @param returnType the type returned by this function + */ + public MapFunction(URI returnType) { + this.returnType = returnType; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_MAP); + + return set; + } + + /** + * Creates a new instance of the map function using the data found in + * the DOM node provided. This is called by a proxy when the factory + * is asked to create one of these functions. + * + * @param root the DOM node of the apply tag containing this function + * + * @return a MapFunction instance + * + * @throws ParsingException if the DOM data was incorrect + */ + public static MapFunction getInstance(Node root) throws ParsingException { + URI returnType = null; + // check if this really is a Function (may be an Apply element too + if (root.getNodeType() != Node.ELEMENT_NODE) { + throw new ParsingException("Can't create a Function from a " + + root.getLocalName() + " element"); + } + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Function")) { + + String funcName = null; + if (node.getAttributes().getNamedItem("FunctionId") != null) { + funcName = node.getAttributes().getNamedItem("FunctionId") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute" + + " FunctionId not found in Function element"); + } + FunctionFactory factory = FunctionFactory.getGeneralInstance(); + try { + Function function = factory.createFunction(funcName); + returnType = function.getReturnType(); + break; + } catch (FunctionTypeException fte) { + // try to get this as an abstract function + try { + Function function = factory. + createAbstractFunction(funcName, root); + returnType = function.getReturnType(); + break; + } catch (Exception e) { + // any exception here is an error + throw new ParsingException("invalid abstract map", e); + } + } catch (Exception e) { + // any exception that's not function type is an error + throw new ParsingException("couldn't parse map body", e); + } + } + } + + // see if we found the return type + if (returnType == null) { + throw new ParsingException("couldn't find the return type"); + } + + return new MapFunction(returnType); + } + + /** + * Returns the full identifier of this function, as known by the factories. + * + * @return the function's identifier + */ + public URI getIdentifier() { + // strictly speaking, this should never happen + if (earlyException != null) { + throw earlyException; + } + + return identifier; + } + + /** + * Returns the same value as getReturnType. This is here + * to support the Expression interface. + * + * @return the return type + */ + public URI getType() { + return getReturnType(); + } + + /** + * Returns the attribute type returned by this function. + * + * @return the return type + */ + public URI getReturnType() { + return this.returnType; + } + + /** + * Returns true, since the map function always returns a bag + * + * @return true + */ + public boolean returnsBag() { + return true; + } + + /** + * Evaluates the function given the input data. Map expects a + * Function followed by a BagAttribute. + * + * @param inputs the input agrument list + * @param context the representation of the request + * + * @return the result of evaluation + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // get the inputs, which we expect to be correct + Iterator iterator = inputs.iterator(); + Function function = null; + + Expression xpr = (Expression)(iterator.next()); + if (xpr instanceof Function) { + function = (Function)xpr; + } else { + function = (Function)(((VariableReference)xpr). + getReferencedDefinition().getExpression()); + } + + Evaluatable eval = (Evaluatable)(iterator.next()); + EvaluationResult result = eval.evaluate(context); + + // in a higher-order case, if anything is INDETERMINATE, then + // we stop right away + if (result.indeterminate()) { + return result; + } + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + + // param: function, bag + // return: bag + // for each value in the bag evaluate the given function with + // the value and put the function result in a new bag that + // is ultimately returned + + Iterator it = bag.iterator(); + List outputs = new ArrayList(); + + while (it.hasNext()) { + List params = new ArrayList(); + params.add(it.next()); + result = function.evaluate(params, context); + + if (result.indeterminate()) { + return result; + } + + outputs.add(result.getAttributeValue()); + } + + return new EvaluationResult(new BagAttribute(this.returnType, + outputs)); + } + + /** + * Checks that the input list is valid for evaluation. + * + * @param inputs a List of inputs + * + * @throws IllegalArgumentException if the inputs cannot be evaluated + */ + public void checkInputs(List inputs) throws IllegalArgumentException { + checkInputs(inputs, null); + } + + /** + * Checks that the input list is valid for evaluation. + * + * @param inputs a List of inputs + * + * @throws IllegalArgumentException if the inputs cannot be evaluated + */ + public void checkInputs(List inputs, RuntimeInfo src) throws IllegalArgumentException { + Expression [] list = inputs.toArray(new Expression[inputs.size()]); + + // check that we've got the right number of arguments + if (list.length != 2) { + throw new IllegalArgumentException("map requires two inputs" + + (src != null ? src.getLocationMsgForError() : "")); + } + + // now check that we've got the right types for map + Function function = null; + + if (list[0] instanceof Function) { + function = (Function)(list[0]); + } else if (list[0] instanceof VariableReference) { + Expression xpr = ((VariableReference)(list[0])). + getReferencedDefinition().getExpression(); + if (xpr instanceof Function) { + function = (Function)xpr; + } + } + + if (function == null) { + throw new IllegalArgumentException("first argument to map must " + + "be a Function" + (src != null ? src.getLocationMsgForError() : "")); + } + Evaluatable eval = (Evaluatable)(list[1]); + if (! eval.returnsBag()) { + throw new IllegalArgumentException("second argument to map must " + + "be a bag" + (src != null ? src.getLocationMsgForError() : "")); + } + + // finally, check that the type in the bag is right for the function + List input = new ArrayList(); + input.add( (Evaluatable) list[1]); + function.checkInputsNoBag(input); + } + + /** + * Always throws IllegalArgumentException since map needs + * to work on a bag + * + * @param inputs a List of inputs + * + * @throws IllegalArgumentException always + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException { + checkInputsNoBag(inputs); + } + + /** + * Always throws IllegalArgumentException since map needs + * to work on a bag + * + * @param inputs a List of inputs + * + * @throws IllegalArgumentException always + */ + public void checkInputsNoBag(List inputs, RuntimeInfo src) throws IllegalArgumentException { + throw new IllegalArgumentException("map requires a bag"); + } + + /** + * Encodes this MapFunction into its XML representation and + * writes this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this MapFunction into its XML representation and + * writes this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + out.println(indenter.makeString() + ""); + } + + public RuntimeInfo getRuntimeInfo() { + logger.warn("SourceLocator feature currently not supported for Map Function"); + return null; + //throw new RuntimeException(); + } + + public void setRuntimeInfo(RuntimeInfo src) { + logger.warn("SourceLocator feature currently not supported for Map Function"); + } + + public void unsetRuntimeInfo(RuntimeInfo src) { + logger.warn("SourceLocator feature currently not supported for Map Function"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunctionProxy.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunctionProxy.java new file mode 100644 index 0000000..2d03883 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MapFunctionProxy.java @@ -0,0 +1,63 @@ + +/* + * @(#)MapFunctionProxy.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import org.w3c.dom.Node; + + +/** + * A basic proxy class that supports map, the only standard abstract function. + * This is useful if you're configuring the PDP at runtime. + * + * @since 1.2 + * @author Seth Proctor + */ +public class MapFunctionProxy implements FunctionProxy { + + /** + * Default constructor. + */ + public MapFunctionProxy() { + //default constructor + } + + public Function getInstance(Node root, String xpathVersion) + throws Exception { + return MapFunction.getInstance(root); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MatchFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MatchFunction.java new file mode 100644 index 0000000..59690fb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MatchFunction.java @@ -0,0 +1,441 @@ + +/* + * @(#)MatchFunction.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.DNSNameAttribute; +import com.sun.xacml.attr.IPAddressAttribute; +import com.sun.xacml.attr.RFC822NameAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.X500NameAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import java.util.regex.Pattern; + +import javax.security.auth.x500.X500Principal; + + +/** + * Implements the standard matching and regular expression functions. + * + * @since 1.0 + * @author Seth Proctor + * @author Yassir Elley + */ +public class MatchFunction extends FunctionBase +{ + + /** + * Standard identifier for the string-regexp-match function. + */ + public static final String NAME_REGEXP_STRING_MATCH = + FUNCTION_NS + "string-regexp-match"; + + /** + * Standard identifier for the x500Name-match function. + */ + public static final String NAME_X500NAME_MATCH = + FUNCTION_NS + "x500Name-match"; + + /** + * Standard identifier for the rfc822Name-match function. + */ + public static final String NAME_RFC822NAME_MATCH = + FUNCTION_NS + "rfc822Name-match"; + + /** + * Standard identifier for the string-regexp-match function. NOTE: this + * in the 1.0 namespace right now because of a bug in the XACML 2.0 + * specification, but this will be changed to the 2.0 namespace as soon + * as the errata is recognized. + */ + public static final String NAME_STRING_REGEXP_MATCH = + FUNCTION_NS + "string-regexp-match"; + + /** + * Standard identifier for the anyURI-regexp-match function. + */ + public static final String NAME_ANYURI_REGEXP_MATCH = + FUNCTION_NS_2 + "anyURI-regexp-match"; + + /** + * Standard identifier for the ipAddress-regexp-match function. + */ + public static final String NAME_IPADDRESS_REGEXP_MATCH = + FUNCTION_NS_2 + "ipAddress-regexp-match"; + + /** + * Standard identifier for the dnsName-regexp-match function. + */ + public static final String NAME_DNSNAME_REGEXP_MATCH = + FUNCTION_NS_2 + "dnsName-regexp-match"; + + /** + * Standard identifier for the rfc822Name-regexp-match function. + */ + public static final String NAME_RFC822NAME_REGEXP_MATCH = + FUNCTION_NS_2 + "rfc822Name-regexp-match"; + + /** + * Standard identifier for the x500Name-regexp-match function. + */ + public static final String NAME_X500NAME_REGEXP_MATCH = + FUNCTION_NS_2 + "x500Name-regexp-match"; + + // private identifiers for the supported functions + private static final int ID_REGEXP_STRING_MATCH = 0; + private static final int ID_X500NAME_MATCH = 1; + private static final int ID_RFC822NAME_MATCH = 2; + private static final int ID_STRING_REGEXP_MATCH = 3; + private static final int ID_ANYURI_REGEXP_MATCH = 4; + private static final int ID_IPADDRESS_REGEXP_MATCH = 5; + private static final int ID_DNSNAME_REGEXP_MATCH = 6; + private static final int ID_RFC822NAME_REGEXP_MATCH = 7; + private static final int ID_X500NAME_REGEXP_MATCH = 8; + + // private mappings for the input arguments + private static final String regexpParams [] = { + StringAttribute.identifier, + StringAttribute.identifier }; + private static final String x500Params [] = { + X500NameAttribute.identifier, + X500NameAttribute.identifier }; + private static final String rfc822Params [] = { + StringAttribute.identifier, + RFC822NameAttribute.identifier}; + private static final String stringRegexpParams [] = { + StringAttribute.identifier, + StringAttribute.identifier}; + private static final String anyURIRegexpParams [] = { + StringAttribute.identifier, + AnyURIAttribute.identifier}; + private static final String ipAddressRegexpParams [] = { + StringAttribute.identifier, + IPAddressAttribute.identifier}; + private static final String dnsNameRegexpParams [] = { + StringAttribute.identifier, + DNSNameAttribute.identifier}; + private static final String rfc822NameRegexpParams [] = { + StringAttribute.identifier, + RFC822NameAttribute.identifier}; + private static final String x500NameRegexpParams [] = { + StringAttribute.identifier, + X500NameAttribute.identifier}; + + // private mapping for bag input options + private static final boolean bagParams [] = { false, false }; + + /** + * Creates a new MatchFunction based on the given name. + * + * @param functionName the name of the standard match function, including + * the complete namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public MatchFunction(String functionName) { + super(functionName, getId(functionName), + getArgumentTypes(functionName), bagParams, + BooleanAttribute.identifier, false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_REGEXP_STRING_MATCH)) { + return ID_REGEXP_STRING_MATCH; + } else if (functionName.equals(NAME_X500NAME_MATCH)) { + return ID_X500NAME_MATCH; + } else if (functionName.equals(NAME_RFC822NAME_MATCH)) { + return ID_RFC822NAME_MATCH; + } else if (functionName.equals(NAME_STRING_REGEXP_MATCH)) { + return ID_STRING_REGEXP_MATCH; + } else if (functionName.equals(NAME_ANYURI_REGEXP_MATCH)) { + return ID_ANYURI_REGEXP_MATCH; + } else if (functionName.equals(NAME_IPADDRESS_REGEXP_MATCH)) { + return ID_IPADDRESS_REGEXP_MATCH; + } else if (functionName.equals(NAME_DNSNAME_REGEXP_MATCH)) { + return ID_DNSNAME_REGEXP_MATCH; + } else if (functionName.equals(NAME_RFC822NAME_REGEXP_MATCH)) { + return ID_RFC822NAME_REGEXP_MATCH; + } else if (functionName.equals(NAME_X500NAME_REGEXP_MATCH)) { + return ID_X500NAME_REGEXP_MATCH; + } + throw new IllegalArgumentException("unknown match function: " + + functionName); + } + + /** + * Private helper that returns the types used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String [] getArgumentTypes(String functionName) { + if (functionName.equals(NAME_REGEXP_STRING_MATCH)) { + return regexpParams; + } else if (functionName.equals(NAME_X500NAME_MATCH)) { + return x500Params; + } else if (functionName.equals(NAME_RFC822NAME_MATCH)) { + return rfc822Params; + } else if (functionName.equals(NAME_STRING_REGEXP_MATCH)) { + return stringRegexpParams; + } else if (functionName.equals(NAME_ANYURI_REGEXP_MATCH)) { + return anyURIRegexpParams; + } else if (functionName.equals(NAME_IPADDRESS_REGEXP_MATCH)) { + return ipAddressRegexpParams; + } else if (functionName.equals(NAME_DNSNAME_REGEXP_MATCH)) { + return dnsNameRegexpParams; + } else if (functionName.equals(NAME_RFC822NAME_REGEXP_MATCH)) { + return rfc822NameRegexpParams; + } else if (functionName.equals(NAME_X500NAME_REGEXP_MATCH)) { + return x500NameRegexpParams; + } + return null; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_REGEXP_STRING_MATCH); + set.add(NAME_X500NAME_MATCH); + set.add(NAME_RFC822NAME_MATCH); + set.add(NAME_STRING_REGEXP_MATCH); + set.add(NAME_ANYURI_REGEXP_MATCH); + set.add(NAME_IPADDRESS_REGEXP_MATCH); + set.add(NAME_DNSNAME_REGEXP_MATCH); + set.add(NAME_RFC822NAME_REGEXP_MATCH); + set.add(NAME_X500NAME_REGEXP_MATCH); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + + // make sure we didn't get an error in processing the args + if (result != null) { + return result; + } + // now that we're setup, we can do the matching operations + + boolean boolResult = false; + + switch (getFunctionId()) { + + case ID_REGEXP_STRING_MATCH: + case ID_STRING_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((StringAttribute)(argValues[1])).getValue(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + case ID_X500NAME_MATCH: { + X500Principal arg0 = + ((X500NameAttribute)(argValues[0])).getValue(); + X500Principal arg1 = + ((X500NameAttribute)(argValues[1])).getValue(); + + boolResult = arg1.getName(X500Principal.CANONICAL). + endsWith(arg0.getName(X500Principal.CANONICAL)); + + break; + } + + case ID_RFC822NAME_MATCH: { + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((RFC822NameAttribute)(argValues[1])).getValue(); + + if (arg0.indexOf('@') != -1) { + // this is case #1 : a whole address + String normalized = (new RFC822NameAttribute(arg0)).getValue(); + boolResult = normalized.equals(arg1); + } else if (arg0.charAt(0) == '.') { + // this is case #3 : a sub-domain + boolResult = arg1.endsWith(arg0.toLowerCase()); + } else { + // this is case #2 : any mailbox at a specific domain + String mailDomain = arg1.substring(arg1.indexOf('@') + 1); + boolResult = arg0.toLowerCase().equals(mailDomain); + } + + break; + } + + case ID_ANYURI_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((AnyURIAttribute)(argValues[1])).encode(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + case ID_IPADDRESS_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((IPAddressAttribute)(argValues[1])).encode(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + case ID_DNSNAME_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((DNSNameAttribute)(argValues[1])).encode(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + case ID_RFC822NAME_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((RFC822NameAttribute)(argValues[1])).encode(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + case ID_X500NAME_REGEXP_MATCH: { + // arg0 is a regular expression; arg1 is a general string + String arg0 = ((StringAttribute)(argValues[0])).getValue(); + String arg1 = ((X500NameAttribute)(argValues[1])).encode(); + + boolResult = regexpHelper(arg0, arg1); + + break; + } + + } + + // Return the result as a BooleanAttribute. + return EvaluationResult.getInstance(boolResult); + } + + /** + * + */ + private boolean regexpHelper(String xpr, String str) { + // the regular expression syntax required by XACML differs + // from the syntax supported by java.util.regex.Pattern + // in several ways; the next several code blocks transform + // the XACML syntax into a semantically equivalent Pattern syntax + + StringBuffer buf = new StringBuffer(xpr); + + // in order to handle the requirement that the string is + // considered to match the pattern if any substring matches + // the pattern, we prepend ".*" and append ".*" to the reg exp, + // but only if there isn't an anchor (^ or $) in place + + if (xpr.charAt(0) != '^') { + buf = buf.insert(0, ".*"); + } + if (xpr.charAt(xpr.length() - 1) != '$') { + buf = buf.insert(buf.length(), ".*"); + } + // in order to handle Unicode blocks, we replace all + // instances of "\p{Is" with "\p{In" in the reg exp + + int idx = -1; + idx = buf.indexOf("\\p{Is", 0); + while (idx != -1){ + buf = buf.replace(idx, idx+5, "\\p{In"); + idx = buf.indexOf("\\p{Is", idx); + } + + // in order to handle Unicode blocks, we replace all instances + // of "\P{Is" with "\P{In" in the reg exp + + idx = -1; + idx = buf.indexOf("\\P{Is", 0); + while (idx != -1){ + buf = buf.replace(idx, idx+5, "\\P{In"); + idx = buf.indexOf("\\P{Is", idx); + } + + // in order to handle character class subtraction, we + // replace all instances of "-[" with "&&[^" in the reg exp + + idx = -1; + idx = buf.indexOf("-[", 0); + while (idx != -1){ + buf = buf.replace(idx, idx+2, "&&[^"); + idx = buf.indexOf("-[", idx); + } + + return Pattern.matches(buf.toString(), str); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ModFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ModFunction.java new file mode 100644 index 0000000..ab68282 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/ModFunction.java @@ -0,0 +1,122 @@ + +/* + * @(#)ModFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the integer-mod function. It takes two + * integer operands and returns the remainder. If either of the + * operands is indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class ModFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-mod function. + */ + public static final String NAME_INTEGER_MOD = FUNCTION_NS + "integer-mod"; + + /** + * Creates a new ModFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public ModFunction(String functionName) { + super(NAME_INTEGER_MOD, 0, IntegerAttribute.identifier, false, + 2, IntegerAttribute.identifier, false); + + if (! functionName.equals(NAME_INTEGER_MOD)) { + throw new IllegalArgumentException("unknown mod function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_MOD); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have real values, perform the mod operation + long arg0 = ((IntegerAttribute) argValues[0]).getValue(); + long arg1 = ((IntegerAttribute) argValues[1]).getValue(); + + return new EvaluationResult(new IntegerAttribute(arg0 % arg1)); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MultiplyFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MultiplyFunction.java new file mode 100644 index 0000000..ff1e755 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/MultiplyFunction.java @@ -0,0 +1,170 @@ + +/* + * @(#)MultiplyFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-multiply functions. It takes two + * operands of the appropriate type and returns the product of the + * operands. If either of the operands is indeterminate, an indeterminate + * result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class MultiplyFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-multiply function. + */ + public static final String NAME_INTEGER_MULTIPLY = + FUNCTION_NS + "integer-multiply"; + + /** + * Standard identifier for the double-multiply function. + */ + public static final String NAME_DOUBLE_MULTIPLY = + FUNCTION_NS + "double-multiply"; + + // inernal identifiers for each of the supported functions + private static final int ID_INTEGER_MULTIPLY = 0; + private static final int ID_DOUBLE_MULTIPLY = 1; + + /** + * Creates a new MultiplyFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public MultiplyFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 2, getArgumentType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_INTEGER_MULTIPLY)) { + return ID_INTEGER_MULTIPLY; + } else if (functionName.equals(NAME_DOUBLE_MULTIPLY)) { + return ID_DOUBLE_MULTIPLY; + } else { + throw new IllegalArgumentException("unknown multiply function " + + functionName); + } + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_INTEGER_MULTIPLY)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_MULTIPLY); + set.add(NAME_DOUBLE_MULTIPLY); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the multiply operation + // in the manner appropriate for the type of the arguments. + if (getFunctionId() == ID_INTEGER_MULTIPLY) { + long arg0 = ((IntegerAttribute) argValues[0]).getValue(); + long arg1 = ((IntegerAttribute) argValues[1]).getValue(); + long product = arg0 * arg1; + result = new EvaluationResult(new IntegerAttribute(product)); + } else if (getFunctionId() == ID_DOUBLE_MULTIPLY) { + double arg0 = ((DoubleAttribute) argValues[0]).getValue(); + double arg1 = ((DoubleAttribute) argValues[1]).getValue(); + double product = arg0 * arg1; + result = new EvaluationResult(new DoubleAttribute(product)); + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NOfFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NOfFunction.java new file mode 100644 index 0000000..671620c --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NOfFunction.java @@ -0,0 +1,229 @@ + +/* + * @(#)NOfFunction.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the n-of function. It requires + * at least one argument. The first argument must be an integer + * and the rest of the arguments must be booleans. If the number of + * boolean arguments that evaluate to true is at least the value of the + * first argument, the function returns true. Otherwise, it returns false + * (or indeterminate, as described in the next paragraph. + *

    + * This function evaluates the arguments one at a time, starting with + * the first one. As soon as the result of the function can be determined, + * evaluation stops and that result is returned. During this process, if + * any argument evaluates to indeterminate, an indeterminate result is + * returned. + * + * @since 1.0 + * @author Steve Hanne + * @author Seth Proctor + */ +public class NOfFunction extends FunctionBase +{ + + /** + * Standard identifier for the n-of function. + */ + public static final String NAME_N_OF = FUNCTION_NS + "n-of"; + + /** + * Creates a new NOfFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public NOfFunction(String functionName) { + super(NAME_N_OF, 0, BooleanAttribute.identifier, false); + + if (! functionName.equals(NAME_N_OF)) { + throw new IllegalArgumentException("unknown nOf function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_N_OF); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments one by one. As soon as we can return + // a result, do so. Return Indeterminate if any argument + // evaluated is indeterminate. + Iterator it = inputs.iterator(); + Evaluatable eval = (Evaluatable)(it.next()); + + // Evaluate the first argument + EvaluationResult result = eval.evaluate(context); + if (result.indeterminate()) { + return result; + } + // if there were no problems, we know 'n' + long n = ((IntegerAttribute)(result.getAttributeValue())).getValue(); + + // If the number of trues needed is less than zero, report an error. + if (n < 0) { + return makeProcessingError("First argument to " + getFunctionName() + + " cannot be negative."); + } + // If the number of trues needed is zero, return true. + if (n == 0) { + return EvaluationResult.getTrueInstance(); + } + // make sure it's possible to find n true values + long remainingArgs = inputs.size() - 1; + if (n > remainingArgs) { + return makeProcessingError("not enough arguments to n-of to " + + "find " + n + " true values"); + } + // loop through the inputs, trying to find at least n trues + while (remainingArgs >= n) { + eval = (Evaluatable)(it.next()); + + // evaluate the next argument + result = eval.evaluate(context); + if (result.indeterminate()) { + return result; + } + // get the next value, and see if it's true + if (((BooleanAttribute)(result.getAttributeValue())).getValue()) { + // we're one closer to our goal...see if we met it + if (--n == 0) { + return EvaluationResult.getTrueInstance(); + } + } + + // we're still looking, but we've got one fewer arguments + remainingArgs--; + } + + // if we got here then we didn't meet our quota + return EvaluationResult.getFalseInstance(); + } + + /** + * @param inputs The inputs for this function. + * + * @throws IllegalArgumentException + * + */ + public void checkInputs(List inputs) throws IllegalArgumentException { + // check that none of the inputs is a bag + Evaluatable [] list = inputs.toArray(new Evaluatable[inputs.size()]); + for (int i = 0; i < list.length; i++) { + if ( list[i].returnsBag()) { + throw new IllegalArgumentException("n-of can't use bags"); + } + } + // if we got here then there were no bags, so ask the other check + // method to finish the checking + //List copy = new ArrayList(inputs); + + List copy = new ArrayList(inputs.size()); + for (int i = 0; i < inputs.size(); ++i ) { + copy.add( list[i]); + } + + checkInputsNoBag(copy); + } + + /**:-( + * @param inputs The inputs for this function. + * + * @throws IllegalArgumentException + * + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException { + Object [] list = inputs.toArray(); + + // check that there is at least one arg + if (list.length == 0) { + throw new IllegalArgumentException("n-of requires an argument"); + } + // check that the first element is an Integer + Evaluatable eval = (Evaluatable)(list[0]); + if (! eval.getType().toString().equals(IntegerAttribute.identifier)) { + throw new IllegalArgumentException("first argument to n-of must" + + " be an integer"); + } + // now check that the rest of the args are booleans + for (int i = 1; i < list.length; i++) { + if (! ((Evaluatable)(list[i])).getType().toString(). + equals(BooleanAttribute.identifier)) { + throw new IllegalArgumentException("invalid parameter in n-of" + + ": expected boolean"); + } + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NotFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NotFunction.java new file mode 100644 index 0000000..d7ed6e5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NotFunction.java @@ -0,0 +1,121 @@ + +/* + * @(#)NotFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the not function. This function takes + * one boolean argument and returns the logical negation of that + * value. If the argument evaluates to indeterminate, an + * indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class NotFunction extends FunctionBase +{ + + /** + * Standard identifier for the not function. + */ + public static final String NAME_NOT = FUNCTION_NS + "not"; + + /** + * Creates a new NotFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public NotFunction(String functionName) { + super(NAME_NOT, 0, BooleanAttribute.identifier, false, 1, + BooleanAttribute.identifier, false); + + if (! functionName.equals(NAME_NOT)) { + throw new IllegalArgumentException("unknown not function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_NOT); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have a real value, perform the not operation. + boolean arg = ((BooleanAttribute) argValues[0]).getValue(); + return EvaluationResult.getInstance(!arg); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NumericConvertFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NumericConvertFunction.java new file mode 100644 index 0000000..e6629d0 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/NumericConvertFunction.java @@ -0,0 +1,182 @@ + +/* + * @(#)NumericConvertFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the numeric type conversion functions + * (double-to-integer and integer-to-double). It takes one argument + * of the appropriate type, converts that argument to the other type, + * and returns the result. If the argument is indeterminate, an + * indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class NumericConvertFunction extends FunctionBase +{ + + /** + * Standard identifier for the double-to-integer function. + */ + public static final String NAME_DOUBLE_TO_INTEGER = + FUNCTION_NS + "double-to-integer"; + + /** + * Standard identifier for the integer-to-double function. + */ + public static final String NAME_INTEGER_TO_DOUBLE = + FUNCTION_NS + "integer-to-double"; + + // private identifiers for the supported functions + private static final int ID_DOUBLE_TO_INTEGER = 0; + private static final int ID_INTEGER_TO_DOUBLE = 1; + + /** + * Creates a new NumericConvertFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknwon + */ + public NumericConvertFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 1, getReturnType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_DOUBLE_TO_INTEGER)) { + return ID_DOUBLE_TO_INTEGER; + } else if (functionName.equals(NAME_INTEGER_TO_DOUBLE)) { + return ID_INTEGER_TO_DOUBLE; + } else { + throw new IllegalArgumentException("unknown convert function " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_DOUBLE_TO_INTEGER); + set.add(NAME_INTEGER_TO_DOUBLE); + + return set; + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_DOUBLE_TO_INTEGER)) { + return DoubleAttribute.identifier; + } + return IntegerAttribute.identifier; + } + + /** + * Private helper that returns the return type for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getReturnType(String functionName) { + if (functionName.equals(NAME_DOUBLE_TO_INTEGER)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the numeric conversion + // operation in the manner appropriate for this function. + if (getFunctionId() == ID_DOUBLE_TO_INTEGER) { + double arg0 = ((DoubleAttribute) argValues[0]).getValue(); + long longValue = (long) arg0; + result = new EvaluationResult(new IntegerAttribute(longValue)); + } else if (getFunctionId() == ID_INTEGER_TO_DOUBLE) { + long arg0 = ((IntegerAttribute) argValues[0]).getValue(); + double doubleValue = arg0; + result = new EvaluationResult(new DoubleAttribute(doubleValue)); + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/RoundFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/RoundFunction.java new file mode 100644 index 0000000..de46ad1 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/RoundFunction.java @@ -0,0 +1,136 @@ + +/* + * @(#)RoundFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements the round function. It takes one double + * operand, rounds that value to an integer and returns that integer. + * If the operand is indeterminate, an indeterminate result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class RoundFunction extends FunctionBase +{ + + /** + * Standard identifier for the round function. + */ + public static final String NAME_ROUND = FUNCTION_NS + "round"; + + /** + * Creates a new RoundFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public RoundFunction(String functionName) { + super(NAME_ROUND, 0, DoubleAttribute.identifier, false, 1, + DoubleAttribute.identifier, false); + + if (! functionName.equals(NAME_ROUND)) { + throw new IllegalArgumentException("unknown round function: " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_ROUND); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // Now that we have real values, perform the round operation + double arg = ((DoubleAttribute) argValues[0]).getValue(); + double roundValue = Math.round(arg); + + // Make it round half even, not round nearest + double lower = Math.floor(arg); + double higher = lower + 1; + + //Equality test for floating point numbers that is + //resilient against errors. + if (Math.abs((arg - lower) - (higher - arg)) < .0000001 ) { + if ((lower % 2) == 0) { + roundValue = lower; + } else { + roundValue = higher; + } + } + + return new EvaluationResult(new DoubleAttribute(roundValue)); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SetFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SetFunction.java new file mode 100644 index 0000000..c8be7af --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SetFunction.java @@ -0,0 +1,291 @@ + +/* + * @(#)SetFunction.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.Base64BinaryAttribute; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.DayTimeDurationAttribute; +import com.sun.xacml.attr.DNSNameAttribute; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.HexBinaryAttribute; +import com.sun.xacml.attr.IntegerAttribute; +import com.sun.xacml.attr.IPAddressAttribute; +import com.sun.xacml.attr.RFC822NameAttribute; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TimeAttribute; +import com.sun.xacml.attr.X500NameAttribute; +import com.sun.xacml.attr.YearMonthDurationAttribute; + +import java.util.HashSet; +import java.util.Set; + + +/** + * Represents all of the Set functions, though the actual implementations + * are in two sub-classes specific to the condition and general set + * functions. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class SetFunction extends FunctionBase +{ + + /** + * Base name for the type-intersection funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_INTERSECTION. + */ + public static final String NAME_BASE_INTERSECTION = + "-intersection"; + + /** + * Base name for the type-at-least-one-member-of funtions. To get the + * standard identifier for a given type, use + * FunctionBase.FUNCTION_NS + the datatype's base name + * (e.g., string) + + * NAME_BASE_AT_LEAST_ONE_MEMBER_OF. + */ + public static final String NAME_BASE_AT_LEAST_ONE_MEMBER_OF = + "-at-least-one-member-of"; + + /** + * Base name for the type-union funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_UNION. + */ + public static final String NAME_BASE_UNION = + "-union"; + + /** + * Base name for the type-subset funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_SUBSET. + */ + public static final String NAME_BASE_SUBSET = + "-subset"; + + /** + * Base name for the type-set-equals funtions. To get the standard + * identifier for a given type, use FunctionBase.FUNCTION_NS + * + the datatype's base name (e.g., string) + + * NAME_BASE_SET_EQUALS. + */ + public static final String NAME_BASE_SET_EQUALS = + "-set-equals"; + + /** + * A complete list of all the XACML datatypes supported by the Set + * functions in XACML 1.x + */ + protected final static String baseTypes [] = { + StringAttribute.identifier, + BooleanAttribute.identifier, + IntegerAttribute.identifier, + DoubleAttribute.identifier, + DateAttribute.identifier, + DateTimeAttribute.identifier, + TimeAttribute.identifier, + AnyURIAttribute.identifier, + HexBinaryAttribute.identifier, + Base64BinaryAttribute.identifier, + DayTimeDurationAttribute.identifier, + YearMonthDurationAttribute.identifier, + X500NameAttribute.identifier, + RFC822NameAttribute.identifier + }; + + /** + * A complete list of all the XACML datatypes newly supported by the Set + * functions in XACML 2.0 + */ + protected final static String baseTypes2 [] = { + IPAddressAttribute.identifier, + DNSNameAttribute.identifier + }; + + /** + * A complete list of all the XACML datatypes supported by the Set + * functions in XACML 1.x, using the "simple" form of the names (eg, + * string instead of http://www.w3.org/2001/XMLSchema#string) + */ + protected static final String simpleTypes [] = { + "string", "boolean", "integer", "double", "date", "dateTime", + "time", "anyURI", "hexBinary", "base64Binary", "dayTimeDuration", + "yearMonthDuration", "x500Name", "rfc822Name" + }; + + /** + * A complete list of all the XACML datatypes newly supported by the Set + * functions in XACML 2.0, using the "simple" form of the names (eg, + * string instead of http://www.w3.org/2001/XMLSchema#string) + */ + protected static final String simpleTypes2 [] = { + "ipAddress", "dnsName" + }; + + /** + * Creates a new instance of the intersection set function. + * This should be used to create support for any new attribute types + * and then the new SetFunction object should be added + * to the factory (all set functions for the base types are already + * installed in the factory). + * + * @param functionName the name of the function + * @param argumentType the attribute type this function will work with + * + * @return a new SetFunction for the given type + */ + public static SetFunction getIntersectionInstance(String functionName, + String argumentType) { + return new GeneralSetFunction(functionName, argumentType, + NAME_BASE_INTERSECTION); + } + + /** + * Creates a new instance of the at-least-one-member-of set function. + * This should be used to create support for any new attribute types + * and then the new SetFunction object should be added + * to the factory (all set functions for the base types are already + * installed in the factory). + * + * @param functionName the name of the function + * @param argumentType the attribute type this function will work with + * + * @return a new SetFunction for the given type + */ + public static SetFunction getAtLeastOneInstance(String functionName, + String argumentType) { + return new ConditionSetFunction(functionName, argumentType, + NAME_BASE_AT_LEAST_ONE_MEMBER_OF); + } + + /** + * Creates a new instance of the union set function. + * This should be used to create support for any new attribute types + * and then the new SetFunction object should be added + * to the factory (all set functions for the base types are already + * installed in the factory). + * + * @param functionName the name of the function + * @param argumentType the attribute type this function will work with + * + * @return a new SetFunction for the given type + */ + public static SetFunction getUnionInstance(String functionName, + String argumentType) { + return new GeneralSetFunction(functionName, argumentType, + NAME_BASE_UNION); + } + + /** + * Creates a new instance of the subset set function. + * This should be used to create support for any new attribute types + * and then the new SetFunction object should be added + * to the factory (all set functions for the base types are already + * installed in the factory). + * + * @param functionName the name of the function + * @param argumentType the attribute type this function will work with + * + * @return a new SetFunction for the given type + */ + public static SetFunction getSubsetInstance(String functionName, + String argumentType) { + return new ConditionSetFunction(functionName, argumentType, + NAME_BASE_SUBSET); + } + + /** + * Creates a new instance of the equals set function. + * This should be used to create support for any new attribute types + * and then the new SetFunction object should be added + * to the factory (all set functions for the base types are already + * installed in the factory). + * + * @param functionName the name of the function + * @param argumentType the attribute type this function will work with + * + * @return a new SetFunction for the given type + */ + public static SetFunction getSetEqualsInstance(String functionName, + String argumentType) { + return new ConditionSetFunction(functionName, argumentType, + NAME_BASE_SET_EQUALS); + } + + /** + * Protected constuctor used by the general and condition subclasses. + * If you need to create a new SetFunction instance you + * should either use one of the getInstance methods or + * construct one of the sub-classes directly. + * + * @param functionName the identitifer for the function + * @param functionId an optional, internal numeric identifier + * @param argumentType the datatype this function accepts + * @param returnType the datatype this function returns + * @param returnsBag whether this function returns bags + */ + protected SetFunction(String functionName, int functionId, + String argumentType, String returnType, + boolean returnsBag) { + super(functionName, functionId, argumentType, true, 2, returnType, + returnsBag); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.addAll(ConditionSetFunction.getSupportedIdentifiers()); + set.addAll(GeneralSetFunction.getSupportedIdentifiers()); + + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StandardFunctionFactory.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StandardFunctionFactory.java new file mode 100644 index 0000000..73d8327 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StandardFunctionFactory.java @@ -0,0 +1,424 @@ + +/* + * @(#)StandardFunctionFactory.java + * + * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.cond.cluster.AbsFunctionCluster; +import com.sun.xacml.cond.cluster.AddFunctionCluster; +import com.sun.xacml.cond.cluster.ComparisonFunctionCluster; +import com.sun.xacml.cond.cluster.ConditionBagFunctionCluster; +import com.sun.xacml.cond.cluster.ConditionSetFunctionCluster; +import com.sun.xacml.cond.cluster.DateMathFunctionCluster; +import com.sun.xacml.cond.cluster.DivideFunctionCluster; +import com.sun.xacml.cond.cluster.EqualFunctionCluster; +import com.sun.xacml.cond.cluster.FloorFunctionCluster; +import com.sun.xacml.cond.cluster.GeneralBagFunctionCluster; +import com.sun.xacml.cond.cluster.GeneralSetFunctionCluster; +import com.sun.xacml.cond.cluster.HigherOrderFunctionCluster; +import com.sun.xacml.cond.cluster.LogicalFunctionCluster; +import com.sun.xacml.cond.cluster.MatchFunctionCluster; +import com.sun.xacml.cond.cluster.ModFunctionCluster; +import com.sun.xacml.cond.cluster.MultiplyFunctionCluster; +import com.sun.xacml.cond.cluster.NOfFunctionCluster; +import com.sun.xacml.cond.cluster.NotFunctionCluster; +import com.sun.xacml.cond.cluster.NumericConvertFunctionCluster; +import com.sun.xacml.cond.cluster.RoundFunctionCluster; +import com.sun.xacml.cond.cluster.StringFunctionCluster; +import com.sun.xacml.cond.cluster.StringNormalizeFunctionCluster; +import com.sun.xacml.cond.cluster.SubtractFunctionCluster; + +//import foo.xacml.cond.cluster.EmergencyLevelFunctionCluster; + +import java.net.URI; + +import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Logger; + + +/** + * This factory supports the standard set of functions specified in XACML + * 1.x and 2.0. It is the default factory used by the system, and imposes + * a singleton pattern insuring that there is only ever one instance of + * this class. + *

    + * Note that because this supports only the standard functions, this + * factory does not allow the addition of any other functions. If you call + * addFunction on an instance of this class, an exception + * will be thrown. If you need a standard factory that is modifiable, + * you can either create a new BaseFunctionFactory (or some + * other implementation of FunctionFactory) populated with + * the standard functions from getStandardFunctions or + * you can use getNewFactoryProxy to get a proxy containing + * a new, modifiable set of factories. + * + * @since 1.2 + * @author Seth Proctor + */ +public class StandardFunctionFactory extends BaseFunctionFactory +{ + + // the three singleton instances + private static StandardFunctionFactory targetFactory = null; + private static StandardFunctionFactory conditionFactory = null; + private static StandardFunctionFactory generalFactory = null; + + // the three function sets/maps that we use internally + private static Set targetFunctions = null; + private static Set conditionFunctions = null; + private static Set generalFunctions = null; + + private static Map targetAbstractFunctions = null; + private static Map conditionAbstractFunctions = null; + private static Map generalAbstractFunctions = null; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(StandardFunctionFactory.class.getName()); + + /** + * Creates a new StandardFunctionFactory, making sure that the default + * maps are initialized correctly. Standard factories can't be modified, + * so there is no notion of supersetting since that's only used for + * correctly propagating new functions. + */ + private StandardFunctionFactory(Set supportedFunctions, + Map supportedAbstractFunctions) { + super(supportedFunctions, supportedAbstractFunctions); + } + + /** + * Private initializer for the target functions. This is only ever + * called once. + */ + private static void initTargetFunctions() { + logger.debug("Initializing standard Target functions"); + + targetFunctions = new HashSet(); + + // add EqualFunction + targetFunctions.addAll((new EqualFunctionCluster()). + getSupportedFunctions()); + // add LogicalFunction + targetFunctions.addAll((new LogicalFunctionCluster()). + getSupportedFunctions()); + // add NOfFunction + targetFunctions.addAll((new NOfFunctionCluster()). + getSupportedFunctions()); + // add NotFunction + targetFunctions.addAll((new NotFunctionCluster()). + getSupportedFunctions()); + // add ComparisonFunction + targetFunctions.addAll((new ComparisonFunctionCluster()). + getSupportedFunctions()); + // add MatchFunction + targetFunctions.addAll((new MatchFunctionCluster()). + getSupportedFunctions()); + +// targetFunctions.addAll((new EmergencyLevelFunctionCluster()). +// getSupportedFunctions()); + + targetAbstractFunctions = new HashMap(); + } + + /** + * Private initializer for the condition functions. This is only ever + * called once. + */ + private static void initConditionFunctions() { + logger.debug("Initializing standard Condition functions"); + + if (targetFunctions == null) { + initTargetFunctions(); + } + + conditionFunctions = new HashSet(targetFunctions); + + // add condition functions from BagFunction + conditionFunctions.addAll((new ConditionBagFunctionCluster()). + getSupportedFunctions()); + // add condition functions from SetFunction + conditionFunctions.addAll((new ConditionSetFunctionCluster()). + getSupportedFunctions()); + // add condition functions from HigherOrderFunction + conditionFunctions.addAll((new HigherOrderFunctionCluster()). + getSupportedFunctions()); + + conditionAbstractFunctions = new HashMap(targetAbstractFunctions); + } + + /** + * Private initializer for the general functions. This is only ever + * called once. + */ + private static void initGeneralFunctions() { + logger.debug("Initializing standard General functions"); + + if (conditionFunctions == null) { + initConditionFunctions(); + } + + generalFunctions = new HashSet(conditionFunctions); + + // add AddFunction + generalFunctions.addAll((new AddFunctionCluster()). + getSupportedFunctions()); + // add SubtractFunction + generalFunctions.addAll((new SubtractFunctionCluster()). + getSupportedFunctions()); + // add MultiplyFunction + generalFunctions.addAll((new MultiplyFunctionCluster()). + getSupportedFunctions()); + // add DivideFunction + generalFunctions.addAll((new DivideFunctionCluster()). + getSupportedFunctions()); + // add ModFunction + generalFunctions.addAll((new ModFunctionCluster()). + getSupportedFunctions()); + // add AbsFunction + generalFunctions.addAll((new AbsFunctionCluster()). + getSupportedFunctions()); + // add RoundFunction + generalFunctions.addAll((new RoundFunctionCluster()). + getSupportedFunctions()); + // add FloorFunction + generalFunctions.addAll((new FloorFunctionCluster()). + getSupportedFunctions()); + // add DateMathFunction + generalFunctions.addAll((new DateMathFunctionCluster()). + getSupportedFunctions()); + // add general functions from BagFunction + generalFunctions.addAll((new GeneralBagFunctionCluster()). + getSupportedFunctions()); + // add NumericConvertFunction + generalFunctions.addAll((new NumericConvertFunctionCluster()). + getSupportedFunctions()); + // add StringNormalizeFunction + generalFunctions.addAll((new StringNormalizeFunctionCluster()). + getSupportedFunctions()); + // add general functions from SetFunction + generalFunctions.addAll((new GeneralSetFunctionCluster()). + getSupportedFunctions()); + // add the XACML 2.0 string functions + generalFunctions.addAll((new StringFunctionCluster()). + getSupportedFunctions()); + + + generalAbstractFunctions = new HashMap(conditionAbstractFunctions); + + // add the map function's proxy + + generalAbstractFunctions.put(URI.create(MapFunction.NAME_MAP), + new MapFunctionProxy()); + + } + + /** + * Returns a FunctionFactory that will only provide those functions that + * are usable in Target matching. This method enforces a singleton + * model, meaning that this always returns the same instance, creating + * the factory if it hasn't been requested before. This is the default + * model used by the FunctionFactory, ensuring quick + * access to this factory. + * + * @return a FunctionFactory for target functions + */ + public static synchronized StandardFunctionFactory getTargetFactory() { + if (targetFactory == null) { + if (targetFunctions == null) { + initTargetFunctions(); + } + if (targetFactory == null) { + targetFactory = + new StandardFunctionFactory(targetFunctions, + targetAbstractFunctions); + } + } + + return targetFactory; + } + + /** + * Returns a FuntionFactory that will only provide those functions that + * are usable in the root of the Condition. These Functions are a + * superset of the Target functions. This method enforces a singleton + * model, meaning that this always returns the same instance, creating + * the factory if it hasn't been requested before. This is the default + * model used by the FunctionFactory, ensuring quick + * access to this factory. + * + * @return a FunctionFactory for condition functions + */ + public static synchronized StandardFunctionFactory getConditionFactory() { + if (conditionFactory == null) { + if (conditionFunctions == null) { + initConditionFunctions(); + } + if (conditionFactory == null) { + conditionFactory = + new StandardFunctionFactory(conditionFunctions, + conditionAbstractFunctions); + } + } + + return conditionFactory; + } + + /** + * Returns a FunctionFactory that provides access to all the functions. + * These Functions are a superset of the Condition functions. This method + * enforces a singleton model, meaning that this always returns the same + * instance, creating the factory if it hasn't been requested before. + * This is the default model used by the FunctionFactory, + * ensuring quick access to this factory. + * + * @return a FunctionFactory for all functions + */ + public static StandardFunctionFactory getGeneralFactory() { + if (generalFactory == null) { + synchronized (StandardFunctionFactory.class) { + if (generalFunctions == null) { + initGeneralFunctions(); + generalFactory = + new StandardFunctionFactory(generalFunctions, + generalAbstractFunctions); + } + } + } + + return generalFactory; + } + + /** + * Returns the identifiers supported for the given version of XACML. + * Because this factory supports identifiers from all versions of theStandardFunctionFactory - Initializing standard Target functions + + * XACML specifications, this method is useful for getting a list of + * which specific identifiers are supported by a given version of XACML. + * + * @param xacmlVersion a standard XACML identifier string, as provided + * in PolicyMetaData + * + * @return a Set of identifiers + */ + public static Set getStandardFunctions(String xacmlVersion) { + // FIXME: collecting the identifiers needs to be implemented.. + throw new RuntimeException("This method isn't implemented yet."); + } + + + /** + * Returns the set of abstract functions that this standard factory + * supports as a mapping of identifier to proxy. + * + * @param xacmlVersion The XACML version number. + * + * @return a Map mapping URIs to + * FunctionProxys + */ + public static Map getStandardAbstractFunctions(String xacmlVersion) { + // FIXME: collecting the identifiers needs to be implemented.. + throw new RuntimeException("This method isn't implemented yet."); + } + + /** + * A convenience method that returns a proxy containing newly created + * instances of BaseFunctionFactorys that are correctly + * supersetted and contain the standard functions and abstract functions. + * These factories allow adding support for new functions. + * + * @return a new proxy containing new factories supporting the standard + * functions + */ + public static FunctionFactoryProxy getNewFactoryProxy() { + // first off, make sure everything's been initialized + getGeneralFactory(); + + // now create the new instances + FunctionFactory newGeneral = + new BaseFunctionFactory(generalFunctions, + generalAbstractFunctions); + + FunctionFactory newCondition = + new BaseFunctionFactory(newGeneral, conditionFunctions, + conditionAbstractFunctions); + + FunctionFactory newTarget = + new BaseFunctionFactory(newCondition, targetFunctions, + targetAbstractFunctions); + + return new BasicFunctionFactoryProxy(newTarget, newCondition, + newGeneral); + } + + /** + * Always throws an exception, since support for new functions may not be + * added to a standard factory. + * + * @param function the Function to add to the factory + * + * @throws IllegalArgumentException + * @throws UnsupportedOperationException always + */ + public void addFunction(Function function) + throws IllegalArgumentException + { + throw new UnsupportedOperationException("a standard factory cannot " + + "support new functions"); + } + + /** + * Always throws an exception, since support for new functions may not be + * added to a standard factory. + * + * @param proxy the FunctionProxy to add to the factory + * @param identity the function's identifier + * + * @throws IllegalArgumentException + * @throws UnsupportedOperationException always + */ + public void addAbstractFunction(FunctionProxy proxy, + URI identity) + throws IllegalArgumentException + { + throw new UnsupportedOperationException("a standard factory cannot " + + "support new functions"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringFunction.java new file mode 100644 index 0000000..e6cc981 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringFunction.java @@ -0,0 +1,123 @@ + +/* + * @(#)StringFunction.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StringAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * This class implements the string-concatenate function from XACML 2.0. + * + * @since 2.0 + * @author Seth Proctor + */ +public class StringFunction extends FunctionBase +{ + + /** + * Standard identifier for the string-concatenate function. + */ + public static final String NAME_STRING_CONCATENATE = + FUNCTION_NS_2 + "string-concatenate"; + + // private identifiers for the supported functions + private static final int ID_STRING_CONCATENATE = 0; + + /** + * Creates a new StringFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public StringFunction(String functionName) { + super(functionName, ID_STRING_CONCATENATE, StringAttribute.identifier, + false, -1, 2, StringAttribute.identifier, false); + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_STRING_CONCATENATE); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + if (getFunctionId() == ID_STRING_CONCATENATE) { + String str = ((StringAttribute)argValues[0]).getValue(); + for (int i = 1; i < argValues.length; i++) { + str += ((StringAttribute)(argValues[i])).getValue(); + } + result = new EvaluationResult(new StringAttribute(str)); + } + + return result; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringNormalizeFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringNormalizeFunction.java new file mode 100644 index 0000000..52631fd --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/StringNormalizeFunction.java @@ -0,0 +1,166 @@ + +/* + * @(#)StringNormalizeFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StringAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the string conversion functions + * (string-normalize-space and string-normalize-to-lower-case). + * It takes string argument, normalizes that value, and returns + * the result. If the argument is indeterminate, an indeterminate + * result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class StringNormalizeFunction extends FunctionBase +{ + + /** + * Standard identifier for the string-normalize-space function. + */ + public static final String NAME_STRING_NORMALIZE_SPACE = + FUNCTION_NS + "string-normalize-space"; + + /** + * Standard identifier for the string-normalize-to-lower-case function. + */ + public static final String NAME_STRING_NORMALIZE_TO_LOWER_CASE = + FUNCTION_NS + "string-normalize-to-lower-case"; + + // private identifiers for the supported functions + private static final int ID_STRING_NORMALIZE_SPACE = 0; + private static final int ID_STRING_NORMALIZE_TO_LOWER_CASE = 1; + + /** + * Creates a new StringNormalizeFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public StringNormalizeFunction(String functionName) { + super(functionName, getId(functionName), StringAttribute.identifier, + false, 1, StringAttribute.identifier, false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_STRING_NORMALIZE_SPACE)) { + return ID_STRING_NORMALIZE_SPACE; + } else if (functionName.equals(NAME_STRING_NORMALIZE_TO_LOWER_CASE)) { + return ID_STRING_NORMALIZE_TO_LOWER_CASE; + } else { + throw new IllegalArgumentException("unknown normalize function " + + functionName); + } + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_STRING_NORMALIZE_SPACE); + set.add(NAME_STRING_NORMALIZE_TO_LOWER_CASE); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the numeric conversion + // operation in the manner appropriate for this function. + if (getFunctionId() == ID_STRING_NORMALIZE_SPACE) { + String str = ((StringAttribute) argValues[0]).getValue(); + // Trim whitespace from start and end of string + int startIndex = 0; + int endIndex = str.length() - 1; + while ((startIndex <= endIndex) && + Character.isWhitespace(str.charAt(startIndex))) { + startIndex++; + } + while ((startIndex <= endIndex) && + Character.isWhitespace(str.charAt(endIndex))) { + endIndex--; + } + String strResult = str.substring(startIndex, endIndex+1); + result = new EvaluationResult(new StringAttribute(strResult)); + } else if (getFunctionId() == ID_STRING_NORMALIZE_TO_LOWER_CASE) { + String str = ((StringAttribute) argValues[0]).getValue(); + // Convert string to lower case + String strResult = str.toLowerCase(); + result = new EvaluationResult(new StringAttribute(strResult)); + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SubtractFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SubtractFunction.java new file mode 100644 index 0000000..9718e1a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/SubtractFunction.java @@ -0,0 +1,170 @@ + +/* + * @(#)SubtractFunction.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.DoubleAttribute; +import com.sun.xacml.attr.IntegerAttribute; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + + +/** + * A class that implements all the *-subtract functions. It takes two + * operands of the appropriate type and returns the difference of the + * operands. If either of the operands is indeterminate, an indeterminate + * result is returned. + * + * @since 1.0 + * @author Steve Hanna + * @author Seth Proctor + */ +public class SubtractFunction extends FunctionBase +{ + + /** + * Standard identifier for the integer-subtract function. + */ + public static final String NAME_INTEGER_SUBTRACT = + FUNCTION_NS + "integer-subtract"; + + /** + * Standard identifier for the integer-subtract function. + */ + public static final String NAME_DOUBLE_SUBTRACT = + FUNCTION_NS + "double-subtract"; + + // inernal identifiers for each of the supported functions + private static final int ID_INTEGER_SUBTRACT = 0; + private static final int ID_DOUBLE_SUBTRACT = 1; + + /** + * Creates a new SubtractFunction object. + * + * @param functionName the standard XACML name of the function to be + * handled by this object, including the full namespace + * + * @throws IllegalArgumentException if the function is unknown + */ + public SubtractFunction(String functionName) { + super(functionName, getId(functionName), getArgumentType(functionName), + false, 2, getArgumentType(functionName), false); + } + + /** + * Private helper that returns the internal identifier used for the + * given standard function. + */ + private static int getId(String functionName) { + if (functionName.equals(NAME_INTEGER_SUBTRACT)) { + return ID_INTEGER_SUBTRACT; + } else if (functionName.equals(NAME_DOUBLE_SUBTRACT)) { + return ID_DOUBLE_SUBTRACT; + } else { + throw new IllegalArgumentException("unknown subtract function " + + functionName); + } + } + + /** + * Private helper that returns the type used for the given standard + * function. Note that this doesn't check on the return value since the + * method always is called after getId, so we assume that the function + * is present. + */ + private static String getArgumentType(String functionName) { + if (functionName.equals(NAME_INTEGER_SUBTRACT)) { + return IntegerAttribute.identifier; + } + return DoubleAttribute.identifier; + } + + /** + * Returns a Set containing all the function identifiers + * supported by this class. + * + * @return a Set of Strings + */ + public static Set getSupportedIdentifiers() { + Set set = new HashSet(); + + set.add(NAME_INTEGER_SUBTRACT); + set.add(NAME_DOUBLE_SUBTRACT); + + return set; + } + + /** + * Evaluate the function, using the specified parameters. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context an EvaluationCtx so that the + * Evaluatable objects can be evaluated + * @return an EvaluationResult representing the + * function's result + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + + // Now that we have real values, perform the subtract operation + // in the manner appropriate for the type of the arguments. + if (getFunctionId() == ID_INTEGER_SUBTRACT) { + long arg0 = ((IntegerAttribute) argValues[0]).getValue(); + long arg1 = ((IntegerAttribute) argValues[1]).getValue(); + long difference = arg0 - arg1; + result = new EvaluationResult(new IntegerAttribute(difference)); + } else if (getFunctionId() == ID_DOUBLE_SUBTRACT) { + double arg0 = ((DoubleAttribute) argValues[0]).getValue(); + double arg1 = ((DoubleAttribute) argValues[1]).getValue(); + double difference = arg0 - arg1; + result = new EvaluationResult(new DoubleAttribute(difference)); + } + + return result; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/TimeInRangeFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/TimeInRangeFunction.java new file mode 100644 index 0000000..9938cf3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/TimeInRangeFunction.java @@ -0,0 +1,203 @@ + +/* + * @(#)TimeInRangeFunction.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BooleanAttribute; +import com.sun.xacml.attr.TimeAttribute; + +import java.util.List; + + +/** + * This class implements the time-in-range function, which takes + * three time values and returns true if the first value falls between the + * second and the third value. This function was introduced in XACML 2.0. + *

    + * Note that this function allows any time ranges less than 24 hours. In + * other words, it is not bound by normal day boundries (midnight GMT), but + * by the minimum time in the range. This means that ranges like 9am-5pm + * are supported, as are ranges like 5pm-9am. + * + * @since 2.0 + * @author seth proctor + */ +public class TimeInRangeFunction extends FunctionBase +{ + + /** + * The identifier for this function + */ + public static final String NAME = FUNCTION_NS_2 + "time-in-range"; + + /** + * The number of milliseconds in a minute + */ + public static final long MILLIS_PER_MINUTE = 1000 * 60; + + /** + * The number of milliseconds in a day + */ + public static final long MILLIS_PER_DAY = MILLIS_PER_MINUTE * 60 * 24; + + /** + * Default constructor. + */ + public TimeInRangeFunction() { + super(NAME, 0, TimeAttribute.identifier, false, 3, + BooleanAttribute.identifier, false); + } + + /** + * Evaluates the time-in-range function, which takes three + * TimeAttribute values. This function return true + * if the first value falls between the second and third values + * (ie., on or after the second time and on or before the third + * time). If no time zone is specified for the second and/or third + * time value, then the timezone from the first time value is + * used. This lets you say time-in-range(current-time, 9am, 5pm) + * and always have the evaluation happen in your current-time + * timezone. + * + * @param inputs a List of Evaluatable + * objects representing the arguments passed to the function + * @param context the respresentation of the request + * + * @return an EvaluationResult containing true or false + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + + // check if any errors occured while resolving the inputs + if (result != null) { + return result; + } + // get the three time values + TimeAttribute attr = (TimeAttribute)(argValues[0]); + long middleTime = attr.getMilliseconds(); + long minTime = resolveTime(attr, (TimeAttribute)(argValues[1])); + long maxTime = resolveTime(attr, (TimeAttribute)(argValues[2])); + + // first off, if the min and max are the same, then this can only + // be true is the middle is also the same value + if (minTime == maxTime) { + return EvaluationResult.getInstance(middleTime == minTime); + } + // shift the minTime to 00:00:00 so we can do a normal comparison, + // taking care to shift in the correct direction (left if the + // maxTime is bigger, otherwise right), and making sure that we + // handle any wrapping values for the middle time (the maxTime will + // never wrap around 00:00:00 GMT as long as we're dealing with + // windows of less than 24 hours) + + // the amount we're shifting + long shiftSpan; + + // figure out the right direction and get the shift amount + if (minTime < maxTime) { + shiftSpan = -minTime; + } else { + shiftSpan = MILLIS_PER_DAY - minTime; + } + // shift the maxTime and the middleTime + maxTime = maxTime + shiftSpan; + middleTime = handleWrap(middleTime + shiftSpan); + + // we're in the range if the middle is now between 0 and maxTime + return EvaluationResult. + getInstance((middleTime >= 0) && (middleTime <= maxTime)); + } + + /** + * Private helper method that is used to resolve the correct values for + * min and max. If an explicit timezone is provided for either, then + * that value gets used. Otherwise we need to pick the timezone the + * middle time is using, and move the other time into that timezone. + */ + private long resolveTime(TimeAttribute middleTime, + TimeAttribute otherTime) { + long time = otherTime.getMilliseconds(); + int tz = otherTime.getTimeZone(); + + // if there's no explicit timezone, then the otherTime needs to + // be shifted to the middleTime's timezone + if (tz == TimeAttribute.TZ_UNSPECIFIED) { + // the other time didn't specify a timezone, so we use the + // timezone specified in the middle time... + int middleTz = middleTime.getTimeZone(); + + // ...and we get the default timezone from the otherTime + tz = otherTime.getDefaultedTimeZone(); + + // if there was no specified timezone for the middleTime, use + // the default timezone for that too + if (middleTz == TimeAttribute.TZ_UNSPECIFIED) { + middleTz = middleTime.getDefaultedTimeZone(); + } + // use the timezone to offset the time value, if the two aren't + // already in the same timezone + if (middleTz != tz) { + time -= ((middleTz - tz) * MILLIS_PER_MINUTE); + time = handleWrap(time); + } + } + + return time; + } + + /** + * Private helper method that handles when a time value wraps no more + * than 24 hours either above 23:59:59 or below 00:00:00. + */ + private long handleWrap(long time) { + if (time < 0) { + // if it's negative, add one day + return time + MILLIS_PER_DAY; + } + + if (time > MILLIS_PER_DAY) { + // if it's more than 24 hours, subtract one day + return time - MILLIS_PER_DAY; + } + + return time; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/URIStringCatFunction.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/URIStringCatFunction.java new file mode 100644 index 0000000..bc2e246 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/URIStringCatFunction.java @@ -0,0 +1,171 @@ + +/* + * @(#)URIStringCatFunction.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StringAttribute; + +import com.sun.xacml.ctx.Status; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +/** + * Represents the XACML 2.0 uri-string-concatenate function. + * + * @since 2.0 + * @author Seth Proctor + */ +public class URIStringCatFunction extends FunctionBase +{ + + /** + * Standard identifier for the url-string-concatenate function. + */ + public static final String NAME_URI_STRING_CONCATENATE = + FUNCTION_NS_2 + "uri-string-concatenate"; + + /** + * Creates an instance of this function. + */ + public URIStringCatFunction() { + super(NAME_URI_STRING_CONCATENATE, 0, AnyURIAttribute.identifier, + false); + } + + /** + * Checks the inputs of this function. + * + * @param inputs a List> of Evaluatables + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputs(List inputs) throws IllegalArgumentException { + // scan the list to make sure nothing returns a bag + Iterator it = inputs.iterator(); + while (it.hasNext()) { + if (it.next().returnsBag() ) { + throw new IllegalArgumentException(NAME_URI_STRING_CONCATENATE + + " doesn't accept bags"); + } + } + + List copy = new ArrayList(inputs.size()); + for (int i = 0; i < inputs.size(); ++i ) { + copy.add( (Evaluatable)inputs.get(i)); + } + + // nothing is a bag, so check using the no-bag method + checkInputsNoBag(copy); + } + + /** + * Checks the inputs of this function assuming no parameters are bags. + * + * @param inputs a List> of Evaluatables + * + * @throws IllegalArgumentException if the inputs won't work + */ + public void checkInputsNoBag(List inputs) throws IllegalArgumentException { + // make sure it's long enough + if (inputs.size() < 2) { + throw new IllegalArgumentException("not enough args to " + + NAME_URI_STRING_CONCATENATE); + } + // check that the parameters are of the correct types... + Iterator it = inputs.iterator(); + + // ...the first argument must be a URI... + if (! it.next().getType().toString().equals(AnyURIAttribute.identifier)) { + throw new IllegalArgumentException("illegal parameter"); + } + // ...and all following arguments must be strings + while (it.hasNext()) { + if (! ((Expression)(it.next())).getType().toString(). + equals(StringAttribute.identifier)) { + throw new IllegalArgumentException("illegal parameter"); + } + } + } + + /** + * Evaluates the function given the input data. This function expects + * an AnyURIAttribute followed by one or more + * StringAttributes, and returns an + * AnyURIAttribute. + * + * @param inputs the input agrument list + * @param context the representation of the request + * + * @return the result of evaluation + */ + public EvaluationResult evaluate(List inputs, EvaluationCtx context) { + // Evaluate the arguments + AttributeValue [] argValues = new AttributeValue[inputs.size()]; + EvaluationResult result = evalArgs(inputs, context, argValues); + if (result != null) { + return result; + } + // the first argument is always a URI + String str = ((AnyURIAttribute)(argValues[0])).getValue().toString(); + + // the remaining arguments are strings + for (int i = 1; i < argValues.length; i++) { + str += ((StringAttribute)(argValues[i])).getValue(); + } + // finally, try to convert the string back to a URI + try { + return new EvaluationResult(new AnyURIAttribute(new URI(str))); + } catch (URISyntaxException use) { + List code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + String message = NAME_URI_STRING_CONCATENATE + " didn't produce" + + " a valid URI: " + str; + + return new EvaluationResult(new Status(code, message)); + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableDefinition.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableDefinition.java new file mode 100644 index 0000000..f2bd162 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableDefinition.java @@ -0,0 +1,213 @@ + +/* + * @(#)VariableDefinition.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.debug.Locatable; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.Set; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * This class supports the VariableDefinitionType type introuced in XACML + * 2.0. It allows a Policy to pre-define any number of expression blocks for + * general use. Note that it's legal (though not usually useful) to define + * expressions that don't get referenced within the Policy. It is illegal to + * have more than one definition with the same identifier within a Policy. + * + * @since 2.0 + * @author Seth Proctor + */ +public class VariableDefinition implements Locatable +{ + + // the identitifer for this definition + private String variableId; + + // the actual expression defined here + private Expression expression; + + public static final Set EMPTY_SET = Collections.emptySet(); + + private RuntimeInfo src; + + /** + * Creates a new VariableDefinition with the given + * identifier and expression. + * + * @param variableId the identifier for this definition + * @param expression the expression defined here + */ + public VariableDefinition(String variableId, Expression expression) { + this.variableId = variableId; + this.expression = expression; + } + + /** + * Returns a new instance of the VariableDefinition class + * based on a DOM node. The node must be the root of an XML + * VariableDefinitionType. + * + * @param root the DOM root of a VariableDefinitionType XML type + * @param metaData the meta-data associated with the containing policy + * @param manager VariableManager used to connect references + * to this definition + * + * @return The instance of this variable definition. + * + * @throws ParsingException if the VariableDefinitionType is invalid + */ + public static VariableDefinition getInstance(Node root, + PolicyMetaData metaData, VariableManager manager) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.VARIABLE_DEFINITION); + // check if this really is a VariableDefinition + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("VariableDefinition")) { + throw new ParsingException("Can't create a VariableDefinition " + + "from a " + root.getLocalName() + " element"); + } + + String variableId = null; + if (root.getAttributes().getNamedItem("VariableId") != null) { + variableId = root.getAttributes().getNamedItem("VariableId") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute VariableId" + + " missing"); + } + + // get the first element, which is the expression node + NodeList nodes = root.getChildNodes(); + Node xprNode = nodes.item(0); + if (xprNode == null) { + throw new ParsingException("First expression node not found"); + } + int i = 1; + while (xprNode.getNodeType() != Node.ELEMENT_NODE) { + xprNode = nodes.item(i++); + } + // use that node to get the expression + Expression xpr = ExpressionHandler. + parseExpression(xprNode, metaData, manager); + + VariableDefinition varDef = new VariableDefinition(variableId, xpr); + varDef.src = src; + return varDef; + } + + /** + * Returns the identifier for this definition. + * + * @return the definition's identifier + */ + public String getVariableId() { + return this.variableId; + } + + /** + * Returns the expression provided by this definition. + * + * @return the definition's expression + */ + public Expression getExpression() { + return this.expression; + } + + /** + * Encodes this class into its XML representation and writes this + * encoding to the given OutputStream with no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this class into its XML representation and writes this + * encoding to the given OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + indenter.in(); + + this.expression.encode(output, charsetName, indenter); + + out.println(""); + indenter.out(); + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableManager.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableManager.java new file mode 100644 index 0000000..fdd87f9 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableManager.java @@ -0,0 +1,373 @@ + +/* + * @(#)VariableManager.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.ProcessingException; + +import java.net.URI; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * This class is used by the parsing routines to handle the relationships + * between variable references and definitions. Specifically, it takes care + * of the fact that definitions can be placed after their first reference, + * and can use references to create circular or recursive relationships. It + * keeps track of what's in the process of being parsed and will pre-parse + * elements as needed. + *

    + * Note that you should never have to use this class directly. It is really + * meant only as a utility for the internal parsing routines. Also, note that + * the operations on this class are not thread-safe. Typically this doesn't + * matter, since the code doesn't support using more than one thread to + * parse a single Policy. + * + * @since 2.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class VariableManager +{ + + // the map from identifiers to internal data + private Map idMap; + + // the meta-data for the containing policy + private PolicyMetaData metaData; + + /** + * Creates a manager with a fixed set of supported identifiers. For + * each of these identifiers, the map supplies a cooresponding DOM node + * used to parse the definition. This is used if, in the course of + * parsing one definition, a reference requires that you have information + * about another definition available. All parsed definitions are cached + * so that each is only parsed once. If a node is not provided, then the + * parsing code may throw an exception if out-of-order or circular + * refereces are used. + *

    + * Note that the use of a DOM node may change to an arbitrary interface, + * so that you could use your own mechanism, but this is still being + * hashed out. This interface will be forzed before a 2.0 release. + * + * @param variableIds a Map from an identifier to the + * Node that is the root of the + * cooresponding variable definition, or null + * @param metaData the meta-data associated with the containing policy + */ + public VariableManager(Map variableIds, PolicyMetaData metaData) { + this.idMap = new HashMap(); + + Iterator> it = variableIds.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + Object key = entry.getKey(); + Node node = entry.getValue(); + this.idMap.put(key, new VariableState(null, node, null, + false, false)); + } + + this.metaData = metaData; + } + + /** + * Returns the definition with the given identifier. If the definition + * is not available, then this method will try to get the definition + * based on the DOM node given for this identifier. If parsing the + * definition requires loading another definition (because of a reference) + * then this method will be recursively invoked. This may make it slow + * to call this method once, but all retrieved definitions are cached, + * and once this manager has started parsing a definition it will never + * try parsing that definition again. If the definition cannot be + * retrieved, then an exception is thrown. + * + * @param variableId the definition's identifier + * + * @return the identified definition + * + * @throws ProcessingException if the definition cannot be resolved + */ + public VariableDefinition getDefinition(String variableId) { + VariableState state = (VariableState)(this.idMap.get(variableId)); + + // make sure this is an identifier we handle + if (state == null) { + throw new ProcessingException("variable is unsupported: " + + variableId); + } + + // if we've resolved the definition before, then we're done + if (state.definition != null) { + return state.definition; + } + + // we don't have the definition, so get the DOM node + Node node = state.rootNode; + + // we can't keep going unless we have a node to work with + if (node != null) { + // if we've already started parsing this node before, then + // don't start again + if (state.handled) { + throw new ProcessingException("processing in progress"); + } + + // keep track of the fact that we're parsing this node, and + // also get the type (if it's an Apply node) + state.handled = true; + discoverApplyType(node, state); + + try { + // now actually try parsing the definition...remember that + // if its expression has a reference, we could end up + // calling this manager method again + state.definition = + VariableDefinition.getInstance(state.rootNode, + this.metaData, this); + + return state.definition; + } catch (ParsingException pe) { + // we failed to parse the definition for some reason + throw new ProcessingException("failed to parse the definition", + pe); + } + } + + // we couldn't figure out how to resolve the definition + throw new ProcessingException("couldn't retrieve definition: " + + variableId); + } + + /** + * Private helper method to get the type of an expression, but only if + * that expression is an Apply. Basically, if there is a circular + * reference, then we'll need to know the types before we're done + * parsing one of the definitions. But, a circular reference that + * requires type-checking can only happen if the definition's expression + * is an Apply. So, we look here, and if it's an Apply, we get the + * type information and store that for later use, just in case. + *

    + * Note that we could wait until later to try this, or we could check + * first to see if there will be a circular reference. Comparatively, + * however, this isn't too expensive, and it makes the system much + * simpler. Still, it's worth re-examining this to see if there's a + * way that makes more sense. + */ + private void discoverApplyType(Node root, VariableState state) { + // get the first element, which is the expression node + NodeList nodes = root.getChildNodes(); + Node xprNode = nodes.item(0); + int i = 1; + while (xprNode.getNodeType() != Node.ELEMENT_NODE) { + xprNode = nodes.item(i++); + } + // now see if the node is an Apply + if (xprNode.getLocalName().equals("Apply")) { + try { + // get the function in the Apply... + Function function = ExpressionHandler. + getFunction(xprNode, this.metaData, + FunctionFactory.getGeneralInstance()); + + // ...and store the type information in the variable state + state.type = function.getReturnType(); + state.returnsBag = function.returnsBag(); + } catch (ParsingException pe) { + // we can just ignore this...if there really is an error, + // then it will come up during parsing in a code path that + // can handle the error cleanly + } + } + } + + /** + * Returns the datatype that the identified definition's expression + * resolves to on evaluation. Note that this method makes every attempt + * to discover this value, including parsing dependent definitions if + * needed and possible. + * + * @param variableId the identifier for the definition + * + * @return the datatype that the identified definition's expression + * evaluates to + * + * @throws ProcessingException if the identifier is not supported or if + * the result cannot be resolved + */ + public URI getVariableType(String variableId) { + VariableState state = (VariableState)(this.idMap.get(variableId)); + + // make sure the variable is supported + if (state == null) { + throw new ProcessingException("variable not supported: " + + variableId); + } + // if we've previously figured out the type, then return that + if (state.type != null) { + return state.type; + } + + // we haven't figured out the type already, so see if we have or + // can resolve the definition + VariableDefinition definition = state.definition; + if (definition == null) { + definition = getDefinition(variableId); + } + + // if we could get the definition, then ask it for the type + if (definition != null) { + return definition.getExpression().getType(); + } + + // we exhausted all our ways to get the right answer + throw new ProcessingException("we couldn't establish the type: " + + variableId); + } + + /** + * Returns true if the identified definition's expression resolves to + * a bag on evaluation. Note that this method makes every attempt to + * discover this value, including parsing dependent definitions if + * needed and possible. + * + * @param variableId the identifier for the definition + * + * @return true if the identified definition's expression evaluates + * to a bag + * + * @throws ProcessingException if the identifier is not supported or if + * the result cannot be resolved + */ + public boolean returnsBag(String variableId) { + VariableState state = (VariableState)(this.idMap.get(variableId)); + + // make sure the variable is supported + if (state == null) { + throw new ProcessingException("variable not supported: " + + variableId); + } + + // the flag is only valid if a type has also been determined + if (state.type != null) { + return state.returnsBag; + } + + // we haven't figured out the type already, so see if we have or + // can resolve the definition + VariableDefinition definition = state.definition; + if (definition == null) { + definition = getDefinition(variableId); + } + + // if we could get the definition, then ask it for the bag return + if (definition != null) { + return definition.getExpression().returnsBag(); + } + + // we exhausted all our ways to get the right answer + throw new ProcessingException("couldn't establish bag return for " + + variableId); + } + + /** + * Inner class that is used simply to manage fields associated with a + * given identifier. + */ + static class VariableState { + + /** + * the resolved definition for the identifier + */ + public VariableDefinition definition; + + /** + * the DOM node used to parse the definition + */ + public Node rootNode; + + /** + * the datatype returned when evaluating the definition + */ + public URI type; + + /** + * whether the definition's root evaluates to a Bag + */ + public boolean returnsBag; + + /** + * whether the definition is being parsed and constructed + */ + public boolean handled; + + /** + * + */ + public VariableState() { + this.definition = null; + this.rootNode = null; + this.type = null; + this.returnsBag = false; + this.handled = false; + } + + /** + * @param definition + * @param rootNode + * @param type + * @param returnsBag + * @param handled + */ + public VariableState(VariableDefinition definition, Node rootNode, + URI type, boolean returnsBag, + boolean handled) { + this.definition = definition; + this.rootNode = rootNode; + this.type = type; + this.returnsBag = returnsBag; + this.handled = handled; + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableReference.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableReference.java new file mode 100644 index 0000000..edefefc --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/VariableReference.java @@ -0,0 +1,351 @@ + +/* + * @(#)VariableReference.java + * + * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.ProcessingException; +import com.sun.xacml.debug.RuntimeInfo; +import com.sun.xacml.debug.RuntimeInfo.ELEMENT_TYPE; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; + +import java.util.List; + +import org.w3c.dom.Node; + + +/** + * This class supports the VariableReferenceType type introuced in XACML + * 2.0. It allows an expression to reference a variable definition. If there + * is no such definition then the Policy is invalid. A reference can be + * included anywwhere in an expression where the referenced expression would + * be valid. + * + * @since 2.0 + * @author Seth Proctor + */ +public class VariableReference implements Evaluatable +{ + + // the identifier used to resolve the reference + private String variableId; + + // the actual definition we refernce, if it's known + private VariableDefinition definition = null; + + // a manager for resolving references, if it's been provided + private VariableManager manager = null; + + private RuntimeInfo src; + + /** + * Simple constructor that takes only the identifier. This is provided + * for tools that want to build policies only for the sake of encoding + * or displaying them. This constructor will not create a reference + * that can be followed to its associated definition, so it cannot be + * used in evaluation. + * + * @param variableId the reference identifier + */ + public VariableReference(String variableId) { + this.variableId = variableId; + } + + /** + * Constructor that takes the definition referenced by this class. If + * you're building policies programatically, this is typically the form + * you use. It does make the connection from reference to definition, + * so this will result in an evaluatable reference. + * + * @param definition the definition this class references + */ + public VariableReference(VariableDefinition definition) { + this.variableId = definition.getVariableId(); + this.definition = definition; + } + + /** + * Constructor that takes the reference identifier and a manager. This + * is typically only used by parsing code, since the manager is used + * to handle out-of-order definitions and circular references. + * + * @param variableId the reference identifier + * @param manager a VariableManager used to handle the + * dependencies between references and definitions during + * parsing + */ + public VariableReference(String variableId, VariableManager manager) { + this.variableId = variableId; + this.manager = manager; + } + + /** + * Returns a new instance of the VariableReference class + * based on a DOM node. The node must be the root of an XML + * VariableReferenceType. + * + * @param root the DOM root of a VariableReferenceType XML type + * @param metaData the meta-data associated with the containing policy + * @param manager the VariableManager used to connect this + * reference to its definition + * + * @return The instance of the variable reference. + */ + public static VariableReference getInstance(Node root, + PolicyMetaData metaData, VariableManager manager) + throws ParsingException { + RuntimeInfo src = RuntimeInfo.getRuntimeInfo(root, ELEMENT_TYPE.VARIABLE_REFERENCE); + // check if this really is a VariableReference + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("VariableReference")) { + throw new ParsingException("Can't create a VariableReference from " + + "a " + root.getLocalName() + " element"); + } + // pretty easy, since there's just an attribute... + String variableId = null; + if (root.getAttributes().getNamedItem("VariableId") != null) { + variableId = root.getAttributes().getNamedItem("VariableId") + .getNodeValue(); + } else { + throw new ParsingException("Required xml-attribute VariableId" + + " missing"); + } + + // ...but we keep the manager since after this we'll probably get + // asked for our type, etc., and the manager will also be used to + // resolve the actual definition + VariableReference variableReference = new VariableReference(variableId, manager); + if ( src != null ) { + variableReference.src = src; + src.setXACMLObject(variableReference); + } + return variableReference; + } + + /** + * Returns the reference identifier. + * + * @return the reference's identifier + */ + public String getVariableId() { + return this.variableId; + } + + /** + * Returns the VariableDefinition referenced by this class, + * or null if the definition cannot be resolved. + * + * @return the referenced definition or null + */ + public VariableDefinition getReferencedDefinition() { + // if this was created with a concrete definition, then that's what + // we return, otherwise we query the manager (if we have one) + if (this.definition != null) { + return this.definition; + } else if (this.manager != null) { + return this.manager.getDefinition(this.variableId); + } + + // if the simple constructor was used, then we have nothing + return null; + } + + /** + * Evaluates the referenced expression using the given context, and either + * returns an error or a resulting value. If this doesn't reference an + * evaluatable expression (eg, a single Function) then this will throw + * an exception. + * + * @param context the representation of the request + * + * @return the result of evaluation + * + * @throws ProcessingException if the expression isn't evaluatable + */ + public EvaluationResult evaluate(EvaluationCtx context) { + Expression xpr = getReferencedDefinition().getExpression(); + + // Note that it's technically possible for this expression to + // be something like a Function, which isn't Evaluatable. It + // wouldn't make sense to have this, but it is possible. Because + // it makes no sense, however, it's unlcear exactly what the + // error should be, so raising the ClassCastException here seems + // as good an approach as any for now... + return ((Evaluatable)xpr).evaluate(context); + } + + /** + * Returns the type of the referenced expression. + * + * @return the attribute return type of the referenced expression + * + * @throws ProcessingException if the type couldn't be resolved + */ + public URI getType() { + // if we have a concrete definition, then ask it for the type, + // otherwise query the manager using the getVariableType method, + // since this handles type-checking for definitions that haven't + // been parsed yet + if (this.definition != null) { + return this.definition.getExpression().getType(); + } + if (this.manager != null) { + return this.manager.getVariableType(this.variableId); + } + + throw new ProcessingException("couldn't resolve the type"); + } + + /** + * Tells whether evaluation will return a bag or a single value. + * + * @return true if evaluation will return a bag, false otherwise + * + * @throws ProcessingException if the return type couldn't be resolved + */ + public boolean returnsToBag() { + // see comment in getType() + if (this.definition != null) { + return getReferencedDefinition().getExpression().returnsBag(); + } + + if (this.manager != null) { + return this.manager.returnsBag(this.variableId); + } + + throw new ProcessingException("couldn't resolve the return type"); + } + + /** + * Tells whether evaluation will return a bag or a single value. + * + * @return true if evaluation will return a bag, false otherwise + * + * @throws ProcessingException if the return type couldn't be resolved + */ + public boolean returnsBag() { + // see comment in getType() + if (this.definition != null) { + return getReferencedDefinition().getExpression().returnsBag(); + } + if (this.manager != null) { + return this.manager.returnsBag(this.variableId); + } + + throw new ProcessingException("couldn't resolve the return type"); + } + + /** + * Tells whether evaluation will return a bag or a single value. + * + * @return true if evaluation will return a bag, false otherwise + * + * @deprecated As of 2.0, you should use the returnsBag + * method from the super-interface Expression. + * + * @throws ProcessingException if the return type couldn't be resolved + */ + public boolean evaluatesToBag() { + return returnsBag(); + } + + /** + * Always returns an empty list since references never have children in + * the policy tree. Note that the referenced definition may still have + * children, so tools may want to treat these as children of this + * reference, but must take care since circular references could create + * a tree of infinite depth. + * + * @return an empty List + */ + public List getChildren() { + return Expression.EMPTY_LIST; + } + + /** + * Encodes this class into its XML representation and writes this + * encoding to the given OutputStream with no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this class into its XML representation and writes this + * encoding to the given OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + } + + public RuntimeInfo getRuntimeInfo() { + return this.src; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AbsFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AbsFunctionCluster.java new file mode 100644 index 0000000..4634cad --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AbsFunctionCluster.java @@ -0,0 +1,67 @@ + +/* + * @(#)AbsFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.AbsFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by AbsFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class AbsFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = AbsFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new AbsFunction(it.next())); + } + + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AddFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AddFunctionCluster.java new file mode 100644 index 0000000..770d53a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/AddFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)AddFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.AddFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by AddFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class AddFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = AddFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new AddFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ComparisonFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ComparisonFunctionCluster.java new file mode 100644 index 0000000..8c539a8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ComparisonFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)ComparisonFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.ComparisonFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by ComparisonFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ComparisonFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = ComparisonFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new ComparisonFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionBagFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionBagFunctionCluster.java new file mode 100644 index 0000000..4efa778 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionBagFunctionCluster.java @@ -0,0 +1,67 @@ + +/* + * @(#)ConditionBagFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.ConditionBagFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by ConditionBagFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ConditionBagFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = ConditionBagFunction.getSupportedIdentifiers(). + iterator(); + + while (it.hasNext()) { + set.add(new ConditionBagFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionSetFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionSetFunctionCluster.java new file mode 100644 index 0000000..7f192eb --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ConditionSetFunctionCluster.java @@ -0,0 +1,67 @@ + +/* + * @(#)ConditionSetFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.ConditionSetFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by ConditionSetFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ConditionSetFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = ConditionSetFunction.getSupportedIdentifiers(). + iterator(); + + while (it.hasNext()) { + set.add(new ConditionSetFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DateMathFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DateMathFunctionCluster.java new file mode 100644 index 0000000..81a3235 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DateMathFunctionCluster.java @@ -0,0 +1,68 @@ + +/* + * @(#)DateMathFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.DateMathFunction; +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.TimeInRangeFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by DateMathFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DateMathFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = DateMathFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new DateMathFunction(it.next())); + } + set.add(new TimeInRangeFunction()); + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DivideFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DivideFunctionCluster.java new file mode 100644 index 0000000..71e61a7 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/DivideFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)DivideFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.DivideFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by DivideFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class DivideFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = DivideFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new DivideFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/EqualFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/EqualFunctionCluster.java new file mode 100644 index 0000000..0115227 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/EqualFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)EqualFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.EqualFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by EqualFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class EqualFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = EqualFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new EqualFunction( it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FloorFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FloorFunctionCluster.java new file mode 100644 index 0000000..cfc755e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FloorFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)FloorFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.FloorFunction; +import com.sun.xacml.cond.Function; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by FloorFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class FloorFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = FloorFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new FloorFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FunctionCluster.java new file mode 100644 index 0000000..c8c5fbe --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/FunctionCluster.java @@ -0,0 +1,72 @@ + +/* + * @(#)FunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import java.util.Set; + +import com.sun.xacml.cond.Function; + + +/** + * Interface used by classes that support more than one function. It's a + * common design model to have a single class support more than one XACML + * function. In those cases, you should provide a proxy that implements + * FunctionCluster in addition to the Function. + * This is particularly important for the run-time configuration system, + * which uses this interface to create "clusters" of functions and therefore + * can use a smaller configuration file. + * + * @since 1.2 + * @author Seth Proctor + */ +public interface FunctionCluster +{ + + /** + * Returns a single instance of each of the functions supported by + * some class. The Set must contain instances of + * Function, and it must be both non-null and non-empty. + * It may contain only a single Function. + *

    + * Note that this is only used to return concrete Functions. + * It may not be used to report abstract functions. + * + * @return the functions supported by this class + */ + public Set getSupportedFunctions(); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralBagFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralBagFunctionCluster.java new file mode 100644 index 0000000..a1cf2ff --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralBagFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)GeneralBagFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.GeneralBagFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by GeneralBagFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class GeneralBagFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = GeneralBagFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new GeneralBagFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralSetFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralSetFunctionCluster.java new file mode 100644 index 0000000..d0d6e5f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/GeneralSetFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)GeneralSetFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.GeneralSetFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by GeneralSetFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class GeneralSetFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = GeneralSetFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new GeneralSetFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/HigherOrderFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/HigherOrderFunctionCluster.java new file mode 100644 index 0000000..c8a762e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/HigherOrderFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)HigherOrderFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.HigherOrderFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by HigherOrderFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class HigherOrderFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = HigherOrderFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new HigherOrderFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/LogicalFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/LogicalFunctionCluster.java new file mode 100644 index 0000000..d1b3c50 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/LogicalFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)LogicalFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.LogicalFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by LogicalFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class LogicalFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = LogicalFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new LogicalFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MatchFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MatchFunctionCluster.java new file mode 100644 index 0000000..8ea05ff --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MatchFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)MatchFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.MatchFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by MatchFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class MatchFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = MatchFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new MatchFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ModFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ModFunctionCluster.java new file mode 100644 index 0000000..6c02480 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/ModFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)ModFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.ModFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by ModFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class ModFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = ModFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new ModFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MultiplyFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MultiplyFunctionCluster.java new file mode 100644 index 0000000..cbad28a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/MultiplyFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)MultiplyFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.MultiplyFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by MultiplyFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class MultiplyFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = MultiplyFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new MultiplyFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NOfFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NOfFunctionCluster.java new file mode 100644 index 0000000..df0b5ec --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NOfFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)NOfFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.NOfFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by NOfFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class NOfFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = NOfFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new NOfFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NotFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NotFunctionCluster.java new file mode 100644 index 0000000..6fbf587 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NotFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)NotFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.NotFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by NotFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class NotFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = NotFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new NotFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NumericConvertFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NumericConvertFunctionCluster.java new file mode 100644 index 0000000..edb2ec3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/NumericConvertFunctionCluster.java @@ -0,0 +1,67 @@ + +/* + * @(#)NumericConvertFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.NumericConvertFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by NumericConvertFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class NumericConvertFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = NumericConvertFunction.getSupportedIdentifiers(). + iterator(); + + while (it.hasNext()) { + set.add(new NumericConvertFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/RoundFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/RoundFunctionCluster.java new file mode 100644 index 0000000..1acc6c3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/RoundFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)RoundFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.RoundFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by RoundFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class RoundFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = RoundFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new RoundFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringFunctionCluster.java new file mode 100644 index 0000000..86c33b2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringFunctionCluster.java @@ -0,0 +1,71 @@ + +/* + * @(#)StringFunctionCluster.java + * + * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.StringFunction; +import com.sun.xacml.cond.URIStringCatFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by StringFunction + * and URIStringCatFunction. + * + * @since 2.0 + * @author Seth Proctor + */ +public class StringFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = StringFunction.getSupportedIdentifiers(). + iterator(); + + while (it.hasNext()) { + set.add(new StringFunction(it.next())); + } + set.add(new URIStringCatFunction()); + + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringNormalizeFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringNormalizeFunctionCluster.java new file mode 100644 index 0000000..18102d2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/StringNormalizeFunctionCluster.java @@ -0,0 +1,67 @@ + +/* + * @(#)StringNormalizeFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.StringNormalizeFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by + * StringNormalizeFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class StringNormalizeFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = StringNormalizeFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new StringNormalizeFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/SubtractFunctionCluster.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/SubtractFunctionCluster.java new file mode 100644 index 0000000..200264d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/SubtractFunctionCluster.java @@ -0,0 +1,66 @@ + +/* + * @(#)SubtractFunctionCluster.java + * + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.cond.cluster; + +import com.sun.xacml.cond.Function; +import com.sun.xacml.cond.SubtractFunction; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + + +/** + * Clusters all the functions supported by SubtractFunction. + * + * @since 1.2 + * @author Seth Proctor + */ +public class SubtractFunctionCluster implements FunctionCluster +{ + + public Set getSupportedFunctions() { + Set set = new HashSet(); + Iterator it = SubtractFunction.getSupportedIdentifiers().iterator(); + + while (it.hasNext()) { + set.add(new SubtractFunction(it.next())); + } + return set; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/package.html new file mode 100644 index 0000000..b1ff3fa --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/cluster/package.html @@ -0,0 +1,7 @@ + + This package defines the FunctionCluster interface that + is used to define a cluster of functions that are all implemented by + some common class. Also included in this package, as a convenience, + are cluster classes for all the standard functions. These are used by + the standard factory and by the run-time configuration system. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/package.html new file mode 100644 index 0000000..314a93e --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/cond/package.html @@ -0,0 +1,19 @@ + + Support for Conditions is in this package. This contains all of the + function code, including base types, implementations of all of the + standard functions, and a factory for getting functions and adding new + ones to the system. There is also support for the Condition and Apply + XML types. +

    + Note that prior to the 1.2 release, most of the function + implementations in this package were package private, mostly because + there is no reason to interact with these classes directly. With the + 1.2 release all classes were exposed, in part to make all the standard + identifier strings easily available. If you need a function instance, + however, you should still use the factory interface. You should not + ever need to instantiate one of the standard function classes + directly. Note also that in the next major release some of the + function impementations may change their interfaces, which is another + reason to interact with the standard functions only through the + factory interface. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Attribute.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Attribute.java new file mode 100644 index 0000000..016805b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Attribute.java @@ -0,0 +1,449 @@ + +/* + * @(#)Attribute.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.Indenter; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; +import com.sun.xacml.PolicyMetaData; + +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StandardAttributeFactory; + +import java.io.PrintStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the AttributeType XML type found in the context schema. + * + * @since 1.0 + * @author Seth Proctor + */ +public class Attribute implements Cloneable +{ + + /** + * The required attribute id, + */ + protected URI id; + + // optional issuer attribute + private String issuer = null; + + // the single value associated with this attribute + private AttributeValue value; + + // the XACML version of this attribute + private int xacmlVersion = Constants.XACML_DEFAULT_VERSION; + + // a switch indicatig whether to include this attribute in the + // result status. + private boolean includeInResult = false; + + /** + * Creates a new Attribute of the type specified in the + * given AttributeValue. + * + * @param id the id of the attribute + * @param issuer the attribute's issuer or null if there is none + * @param value the actual value associated with the attribute meta-data, + * ` must not be null. + */ + public Attribute(URI id, String issuer, AttributeValue value) { + this(id, issuer, value, Constants.XACML_DEFAULT_VERSION, false); + } + + /** + * Creates a new Attribute of the type specified in the + * given AttributeValue. + * + * @param id the id of the attribute + * @param issuer the attribute's issuer or null if there is none + * @param value the actual value associated with the attribute meta-data, + * must not be null. + * @param xacmlVersion The XACML version number for compatibility code. + */ + public Attribute(URI id, String issuer, + AttributeValue value, int xacmlVersion) { + this(id, issuer, value, xacmlVersion, false); + } + + /** + * Creates a new Attribute of the type specified in the + * given AttributeValue. + * + * @param id the id of the attribute + * @param issuer the attribute's issuer or null if there is none + * @param value the actual value associated with the attribute meta-data, + * must not be null. + * @param xacmlVersion The XACML version number for compatibility code. + * @param includeInResult A switch indicating that this attribute + * should be included in the result. + */ + public Attribute(URI id, String issuer, + AttributeValue value, int xacmlVersion, + boolean includeInResult) { + this.id = id; + this.issuer = issuer; + this.value = value; + this.xacmlVersion = xacmlVersion; + this.includeInResult = includeInResult; + } + + /** + * The clone method. + * + * @return a copy if this object. + */ + public Object clone() { + try { + Attribute clone = (Attribute)super.clone(); + clone.id = this.id; + clone.issuer = this.issuer; + + StandardAttributeFactory fac + = StandardAttributeFactory.getFactory(); + try { + clone.value = fac.createValue(this.value.getType(), + this.value.encode()); + } catch (UnknownIdentifierException e) { + throw new RuntimeException("Impossible exception"); + } catch (ParsingException e) { + throw new RuntimeException("Impossible exception"); + } + + clone.xacmlVersion = this.xacmlVersion; + clone.includeInResult = this.includeInResult; + return clone; + } catch (CloneNotSupportedException e1) {//this should never happen + throw new RuntimeException("Couldn't clone Attribute"); + } + } + + /** + * Creates an instances of Attributes based on the root DOM + * node of the XML data. This method returns a list of attributes since + * the XACML syntax allows multi valued attributes in a single + * AttributeType XML type. + * + * @param root the DOM root of the AttributeType XML type + * + * @return a list of attributes + * + *@throws ParsingException if the data is invalid + */ + public static List getInstances(Node root) + throws ParsingException { + // check if this really is an attribute + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("Attribute")) { + throw new ParsingException("Can't create an Attribute from a " + + root.getLocalName() + " element"); + } + URI id = null; + URI type = null; + String issuer = null; + boolean includeInResult = false; + List result = new LinkedList(); + + AttributeFactory attrFactory = AttributeFactory.getInstance(); + + // Now get the xacml version + PolicyMetaData metaData = new PolicyMetaData(root.getNamespaceURI(), + Constants.XPATH_1_0_IDENTIFIER); + + NamedNodeMap attrs = root.getAttributes(); + + try { + id = new URI(attrs.getNamedItem("AttributeId").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error parsing required attribute " + + "AttributeId in AttributeType", e); + } + + if (metaData.getXACMLVersion() < Constants.XACML_VERSION_3_0) { + try { + type = new URI(attrs.getNamedItem("DataType").getNodeValue()); + } catch (Exception e) { + throw new ParsingException("Error parsing required attribute " + + "DataType in AttributeType", e); + } + } + + try { + Node issuerNode = attrs.getNamedItem("Issuer"); + if (issuerNode != null) { + issuer = issuerNode.getNodeValue(); + } + } catch (Exception e) { + // shouldn't happen, but just in case... + throw new ParsingException("Error parsing optional AttributeType" + + " attribute", e); + } + + Node includeNode = attrs.getNamedItem("includeInResult"); + if (includeNode != null) { + if (includeNode.getNodeValue().equals("true")) { + includeInResult = true; + } else if (includeNode.getNodeValue().equals("false")){ + includeInResult = false; + } else { + throw new ParsingException("Error parsing boolean value" + + " includeInResult: " + + includeNode.getNodeValue()); + } + } + + // now we get the attribute value + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("AttributeValue")) { + // get the type + if (metaData.getXACMLVersion() > + Constants.XACML_VERSION_2_0) { + Node typeNode = node.getAttributes() + .getNamedItem("DataType"); + if (typeNode == null) { + throw new ParsingException("No DataType xml-attribute " + + "found in AttributeValue"); + } + String typeStr = typeNode.getNodeValue(); + try { + type = new URI(typeStr); + } catch (Exception e) { + throw new ParsingException("Error parsing required " + + "attribute DataType in AttributeValue", e); + } + } + + // now get the value + try { + AttributeValue value = attrFactory.createValue(node, type); + Attribute attr = new Attribute(id, issuer, value, + metaData.getXACMLVersion(), includeInResult); + result.add(attr); + } catch (UnknownIdentifierException uie) { + throw new ParsingException("Unknown DataType", uie); + } + } + } + if(result.isEmpty()) + throw new ParsingException("Attribute must contain a value"); + + return result; + } + + /** + * Returns the id of this attribute + * + * @return the attribute id + */ + public URI getId() { + return this.id; + } + + /** + * Returns the issuer of this attribute, or null if no issuer was named + * + * @return the issuer or null + */ + public String getIssuer() { + return this.issuer; + } + + /** + * The value of this attribute, or null if no value was included + * + * @return the attribute's value or null + */ + public AttributeValue getValue() { + return this.value; + } + + /** + * Returns the xacml version number for this attribute. + * + * @return The xacml version number as defined in + * PolicyMetaData. + */ + public int getVersion() { + return this.xacmlVersion; + } + + /** + * @return True if this attribute should be included in the result. + */ + public boolean includeInResult() { + return this.includeInResult; + } + + /** + * Encodes this attribute into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this attribute into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + // setup the formatting & outstream stuff + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + + // write out the encoded form + out.println(encode(indenter)); + } + + /** + * Encoding method that returns the text-encoded version of + * this attribute with formatting. + * + * @return the text-encoded XML + */ + public String encode(Indenter indenter) { + String indent = indenter.makeString(); + indenter.in(); + String innerIndent = indenter.makeString(); + indenter.out(); + String encoded = indent + + "= Constants.XACML_VERSION_3_0 + && this.includeInResult == true) { + encoded += " includeInResult=\"true\""; + } + encoded += ">" + Constants.nl; + + if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { + encoded += innerIndent + + this.value.encodeWithTags(false) + Constants.nl + + indent + ""; + + } else { + encoded += innerIndent + + this.value.encodeWithTags(true) + Constants.nl + + indent + ""; + } + + return encoded; + } + + + /** + * Simple encoding method that returns the text-encoded version of + * this attribute with no formatting. + * + * @return the text-encoded XML + */ + public String encode() { + String encoded = "= Constants.XACML_VERSION_3_0 + && this.includeInResult == true) { + encoded += " includeInResult=\"true\""; + } + encoded += ">"; + + if (this.xacmlVersion < Constants.XACML_VERSION_3_0) { + encoded += this.value.encodeWithTags(false) + ""; + } else { + encoded += this.value.encodeWithTags(true) + ""; + } + + return encoded; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/InputParser.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/InputParser.java new file mode 100644 index 0000000..a6f1a3d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/InputParser.java @@ -0,0 +1,212 @@ + +/* + * @(#)InputParser.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.ParsingException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.log4j.Logger; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + + +/** + * A package-private helper that provides a single static routine for + * parsing input based on the context schema. + * + * @since 1.0 + * @author Seth Proctor + */ +class InputParser implements ErrorHandler +{ + + // the schema file, if provided + private File schemaFile; + + // the single reference, which is null unless a schema file is provided + private static InputParser ipReference = null; + + // the property string to set to turn on validation + private static final String CONTEXT_SCHEMA_PROPERTY = + "com.sun.xacml.ContextSchema"; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(InputParser.class.getName()); + + // standard strings for setting validation + + private static final String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + private static final String W3C_XML_SCHEMA = + "http://www.w3.org/2001/XMLSchema"; + + private static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + /** + * Look for the property that names the schema, and if it exists get + * the file name and create a single InputParser instance + */ + static { + String schemaName = System.getProperty(CONTEXT_SCHEMA_PROPERTY); + + if (schemaName != null) { + ipReference = new InputParser(new File(schemaName)); + } + } + + /** + * Constructor that takes the schema file. + */ + private InputParser(File schemaFile) { + this.schemaFile = schemaFile; + } + + /** + * Tries to Parse the given output as a Context document. + * + * @param input the stream to parse + * @param rootTag either "Request" or "Response" + * + * @return the root node of the request/response + * + * @throws ParsingException if a problem occurred parsing the document + */ + static Node parseInput(InputStream input, String rootTag) + throws ParsingException + { + NodeList nodes = null; + + try { + DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + factory.setIgnoringComments(true); + + DocumentBuilder builder = null; + + // as of 1.2, we always are namespace aware + factory.setNamespaceAware(true); + + if (ipReference == null) { + // we're not validating + factory.setValidating(false); + + builder = factory.newDocumentBuilder(); + } else { + // we are validating + factory.setValidating(true); + + factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); + factory.setAttribute(JAXP_SCHEMA_SOURCE, + ipReference.schemaFile); + + builder = factory.newDocumentBuilder(); + builder.setErrorHandler(ipReference); + } + + Document doc = builder.parse(input); + nodes = doc.getElementsByTagName(rootTag); + } catch (ParserConfigurationException e) { + throw new ParsingException("Error tring to parse " + rootTag + + "Type", e); + } catch (SAXException e) { + throw new ParsingException("Error tring to parse " + rootTag + + "Type", e); + } catch (IOException e) { + throw new ParsingException("Error tring to parse " + rootTag + + "Type", e); + } + + if (nodes.getLength() != 1) { + throw new ParsingException("Only one " + rootTag + "Type allowed " + + "at the root of a Context doc"); + } + return nodes.item(0); + } + + /** + * Standard handler routine for the XML parsing. + * + * @param exception information on what caused the problem + */ + public void warning(SAXParseException exception) { + logger.warn("Warning on line " + exception.getLineNumber() + + ": " + exception.getMessage()); + } + + /** + * Standard handler routine for the XML parsing. + * + * @param exception information on what caused the problem + * + * @throws SAXException always to halt parsing on errors + */ + public void error(SAXParseException exception) throws SAXException { + logger.warn("Error on line " + exception.getLineNumber() + + ": " + exception.getMessage()); + throw new SAXException("invalid context document"); + } + + /** + * Standard handler routine for the XML parsing. + * + * @param exception information on what caused the problem + * + * @throws SAXException always to halt parsing on errors + */ + public void fatalError(SAXParseException exception) throws SAXException { + logger.warn("FatalError on line " + exception.getLineNumber() + + ": " + exception.getMessage()); + throw new SAXException("invalid context document"); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/PolicyIssuer.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/PolicyIssuer.java new file mode 100644 index 0000000..02f9680 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/PolicyIssuer.java @@ -0,0 +1,118 @@ +/* + * @(#)PolicyIssuer.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import java.net.URI; +import java.util.Date; +import java.util.Set; + + +/** + * Represents a policy issuer in the list of indirect delegates of an administrative + * request made to the PDP. This is the class contains a set of attributes for the + * policy issuer and an issue date, that specifies when the policy was issued. + * The date is used for request evaluation in a historic attribute model. + * + * @since 3.0 + * @author Ludwig Seitz + */ +public class PolicyIssuer extends RequestElement { + + /** + * the issue instant member variable, can be null + */ + private Date issueDate = null; + + /** + * Constructor. Creates a policy issuer out of the components. + * + * @param attributes must be a Sets of + * Attributes + */ + public PolicyIssuer(Set attributes) { + super(URI.create("PolicyIssuer"), attributes); + this.issueDate = null; + } + + /** + * Constructor. Creates a policy issuer out of it's attributes and the + * policy issue date + * + * @param attributes must be a set of Attribute objects + * @param issueDate the issue date of the policy. May be null. + */ + public PolicyIssuer(Set attributes, Date issueDate) { + super(URI.create("PolicyIssuer"), attributes); + if (issueDate != null) { + this.issueDate = (Date)issueDate.clone(); + } + } + + /** + * The clone method. + * + * @return a copy of this object. + */ + public Object clone() { + PolicyIssuer clone = (PolicyIssuer)super.clone(); + if (this.issueDate != null) { + this.issueDate = (Date)this.issueDate.clone(); + } + return clone; + } + + /** + * Get the issue date as a Date object + * of this indirect delegate. + * + * @return the issue date, may be null + */ + public Date getIssueDate() { + if (this.issueDate != null) { + return (Date)this.issueDate.clone(); + } + return null; + } + + /** + * Set the issueDate from a Date object. + * @param issueDate the issueDate to be set + */ + public void setDate(Date issueDate) { + this.issueDate = (Date)issueDate.clone(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestCtx.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestCtx.java new file mode 100644 index 0000000..741cbb3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestCtx.java @@ -0,0 +1,412 @@ +/* + * @(#)RequestCtx.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.Constants; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents a request made to the PDP. This is the class that contains all + * the data used to start a policy evaluation. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + * @author Ludwig Seitz + */ +public class RequestCtx +{ + + /** + * This contains the requestElements. + */ + private Set requestElements = null; + + /** + * Hold onto the root of the document for XPath searches + */ + private Node documentRoot = null; + + /** + * The XACML version. + */ + private int xacmlVersion = Constants.XACML_DEFAULT_VERSION; + + /** + * Constructor that creates a RequestCtx from + * RequestElements. + * + * @param requestElements the elements of the request. E.g. subject, + * resource, action. A Set of + * RequestElements. + * Must not be null, or empty. + * @param documentRoot the root node of the DOM tree for this request. + * Can be null. + * + * @throws IllegalArgumentException if the inputs are not well formed + */ + public RequestCtx(Set requestElements, Node documentRoot, + Node content) throws IllegalArgumentException { + this(requestElements, documentRoot, Constants.XACML_DEFAULT_VERSION); + } + + /** + * Constructor that creates a RequestCtx from + * RequestElements. + * + * @param requestElements the elements of the request. E.g. subject, + * resource, action. A Set of + * RequestElements. + * Must not be null, or empty. + * @param documentRoot the root node of the DOM tree for this request. + * Can be null. + * @param xacmlVersion The version number of the XACML used (see + * PolicyMetaData for details). + * + * @throws IllegalArgumentException if the inputs are not well formed + */ + public RequestCtx(Set requestElements, Node documentRoot, + int xacmlVersion) throws IllegalArgumentException { + + //Control type of the requestElements + Iterator elements = requestElements.iterator(); + while (elements.hasNext()){ + Object element = elements.next(); + if (!(element instanceof RequestElement)) { + throw new IllegalArgumentException("First parameter in request" + + " must be a Set of RequestElement objects"); + } + } + this.requestElements = new HashSet(requestElements); + + // save document root node for AttributeSelectors. + this.documentRoot = documentRoot; + + this.xacmlVersion = xacmlVersion; + } + + /** + * Create a new RequestCtx by parsing a node. This + * node should be created by schema-verified parsing of an + * XML document. + * + * @param root the node to parse for the RequestCtx + * + * @return a new RequestCtx constructed by parsing + * + * @throws ParsingException if the DOM node is invalid + */ + public static RequestCtx getInstance(Node root) throws ParsingException { + Set newRequestElements = new HashSet(); + // get XACML version + PolicyMetaData metaData = new PolicyMetaData( + root.getNamespaceURI(), Constants.XPATH_1_0_IDENTIFIER); + int xacmlVersion = metaData.getXACMLVersion(); + + // First check to be sure the node passed is indeed a Request node. + String tagName = root.getLocalName(); + if (root.getNodeType() != Node.ELEMENT_NODE + || ! tagName.equals("Request")) { + throw new ParsingException("Request cannot be constructed using " + + "type: " + root.getLocalName()); + } + + // Now go through its child nodes, finding the Attributes in the + // different categories. This may reset the XACML version if the + // namespace had it wrong. + NodeList children = root.getChildNodes(); + + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + String name = node.getLocalName(); + if (name.equals("Attributes")) { + xacmlVersion = Constants.XACML_VERSION_3_0; + RequestElement re + = RequestElement.getInstance((Element)node, metaData); + if (re != null) { + newRequestElements.add(re); + } + } else if (name.equals("Subject") || + name.equals("Resource") || + name.equals("Action") || + name.equals("Environment")) { + //compatibility code for XACML 2.0 + xacmlVersion = Constants.XACML_VERSION_2_0; + RequestElement re + = RequestElement.getInstance((Element)node, metaData); + if (re != null) { + newRequestElements.add(re); + } + } else { + throw new ParsingException("Illegal element: " + + name + " where only Attributes and Content elements" + + " expected"); + } + } + } + + // Now create and return the RequestCtx from the information + // gathered + return new RequestCtx(newRequestElements, root, xacmlVersion); + } + + /** + * Creates a new RequestCtx by parsing XML from an + * input stream. Note that this a convenience method, and it will + * not do schema validation by default. You should be parsing the data + * yourself, and then providing the root node to the other + * getInstance method. If you use this convenience + * method, you probably want to turn on validation by setting the + * context schema file (see the programmer guide for more information + * on this). + * + * @param input a stream providing the XML data + * + * @return a new RequestCtx + * + * @throws ParsingException if there is an error parsing the input + */ + public static RequestCtx getInstance(InputStream input) + throws ParsingException + { + return getInstance(InputParser.parseInput(input, "Request")); + } + + /** + * Returns a Set containing the RequestElements. + * + * @return the request's RequestElements + */ + public Set getRequestElements() { + return Collections.unmodifiableSet(this.requestElements); + } + + /** + * @return The xacml version of this request + */ + public int getXACMLVersion() { + return this.xacmlVersion; + } + + /** + * Returns the root DOM node of the document used to create this + * object, or null if this object was created by hand (ie, not through + * the getInstance method) or if the root node was not + * provided to the constructor. + * + * @return the root DOM node or null + */ + public Node getDocumentRoot() { + return this.documentRoot; + } + + /** + * Encodes this context into its XML representation and writes this + * encoding to the given OutputStream. No + * indentation is used. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this context into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + + // Make a PrintStream for a nicer printing interface + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + + // Prepare the indentation string + String topIndent = indenter.makeString(); + out.print(topIndent + ""); + + HashSet subjects = new HashSet(); + HashSet resources = new HashSet(); + RequestElement action = null; + Iterator iter = this.requestElements.iterator(); + while (iter.hasNext()) { + RequestElement rE = iter.next(); + if (rE.getCategory().equals(Constants.RESOURCE_CAT)) { + resources.add(rE); + } else if (rE.getCategory().equals(Constants.ACTION_CAT)) { + action = rE; + } else { + //For backwards compatibility we cast all other categories + //to subject categories. + subjects.add(rE); + } + } + + //encode subjects + Iterator subjectIter = subjects.iterator(); + while(subjectIter.hasNext()) { + RequestElement subject = subjectIter.next(); + subject.encode(output, charsetName, indenter); + } + + //encode resources + Iterator resourceIter = resources.iterator(); + while(resourceIter.hasNext()) { + RequestElement resource = resourceIter.next(); + resource.encode(output, charsetName, indenter); + } + + //encode action + if (action != null) { + action.encode(output, charsetName, indenter); + } + break; + case Constants.XACML_VERSION_2_0: + out.println(Constants.XACML_2_0_CTX_ID + "\">"); + + subjects = new HashSet(); + resources = new HashSet(); + action = null; + RequestElement environment = null; + iter = this.requestElements.iterator(); + while (iter.hasNext()) { + RequestElement rE = (RequestElement)iter.next(); + if (rE.getCategory().equals(Constants.RESOURCE_CAT)) { + resources.add(rE); + } else if (rE.getCategory().equals(Constants.ACTION_CAT)) { + action = rE; + } else if (rE.getCategory().equals( + Constants.ENVIRONMENT_CAT)) { + environment = rE; + } else { + //For backwards compatibility we cast all other categories + //to subject categories. + subjects.add(rE); + } + } + + //encode subjects + subjectIter = subjects.iterator(); + while(subjectIter.hasNext()) { + RequestElement subject = (RequestElement)subjectIter.next(); + subject.encode(output, charsetName, indenter); + } + + //encode resources + resourceIter = resources.iterator(); + while(resourceIter.hasNext()) { + RequestElement resource = (RequestElement)resourceIter.next(); + resource.encode(output, charsetName, indenter); + } + + //encode action + if (action != null) { + action.encode(output, charsetName, indenter); + } + + //encode environment + if (environment != null) { + environment.encode(output, charsetName, indenter); + } + + break; + case Constants.XACML_VERSION_3_0: + /* falls through */ + default: + out.println(Constants.XACML_3_0_IDENTIFIER + "\">"); + + Iterator elements = this.requestElements.iterator(); + while (elements.hasNext()) { + RequestElement rEl = (RequestElement)elements.next(); + rEl.encode(output, charsetName, indenter); + } + break; + } + + indenter.out(); + + out.println(topIndent + ""); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestElement.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestElement.java new file mode 100644 index 0000000..755663f --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/RequestElement.java @@ -0,0 +1,626 @@ +/* + * @(#)RequestElement.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.OutputKeys; + +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.sun.xacml.Constants; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +/** + * Represents an element of a request made to the PDP. This is the class contains + * for example the subject, resource, action, delegate and one of the indirect + * delegate objects. Its purpose is to serve as an extension point for generic + * request elements. + * + * @since 3.0 + * @author Ludwig Seitz + */ +public class RequestElement implements Cloneable { + + /** + * The map of attributes characterizing this request element + * keyed by attribute-id. Maps to Sets of + * Attributes with the same id. + */ + private Map> attributes = null; + + /** + * The set of attributes with the includeInResult flag. + */ + private Set includeAttributes = null; + + /** + * This holds the optional Content/ResourceContent element, + * or null if there is no content. + */ + private Node content = null; + + /** + * The category of the request element + */ + private URI category = null; + + /** + * The XACML version. + */ + private int xacmlVersion = Constants.XACML_DEFAULT_VERSION; + + /** + * Remember if this was a pre 3.0 request with the SubjectCategory + * attribute (for encoding). + */ + private boolean withSubjectCategory = false; + + + public static final Set EMPTY_SET = Collections.emptySet(); + + /** + * Creates a request element out of it's category and attributes + * + * @param category the cateogry, must not be null + * @param attributes must be a Set containing + * Attribute objects. + * Must not be null or empty. + */ + public RequestElement(URI category, Set attributes) { + this(category, attributes, null, + Constants.XACML_DEFAULT_VERSION, false); + } + + /** + * Creates a request element without content. + * + * @param category the cateogry, must not be null + * @param attributes must be a Set containing + * Attribute objects. + * Must not be null or empty. + * @param xacmlVersion The version number of the XACML used (see + * PolicyMetaData for details). + * @param withSubjectCategory Remember if this was a pre 3.0 + * request with attribute category. + */ + public RequestElement(URI category, Set attributes, int xacmlVersion, + boolean withSubjectCategory) { + this(category, attributes, null, xacmlVersion, withSubjectCategory); + } + + /** + * Creates a request element out of it's category and attributes + * + * @param category the cateogry, must not be null + * @param attributes must be a Set containing + * Attribute objects. + * Must not be null or empty. + * @param content the content element, or null if there is no content. + * @param xacmlVersion The version number of the XACML used (see + * PolicyMetaData for details). + * @param withSubjectCategory Remember if this was a pre 3.0 + * request with attribute category. + */ + public RequestElement(URI category, Set attributes, + Node content, int xacmlVersion, + boolean withSubjectCategory) { + + this.attributes = new HashMap>(); + this.includeAttributes = new HashSet(); + // convert the set to a map for request optimization and + // make sure the contents are of correct type. + Iterator attrs = attributes.iterator(); + while (attrs.hasNext()){ +// Object thing = attrs.next(); +// if (!(thing instanceof Attribute)) { +// throw new IllegalArgumentException(category.toString() +// + " input is not well formed (should be an attribute " +// + "but is a " + thing.getClass().getName() + ")"); +// +// } + Attribute attr = attrs.next(); + URI id = attr.getId(); + if (this.attributes.containsKey(id)) { + Set set = this.attributes.get(id); + set.add(attr); + } else { + Set set = new HashSet(); + set.add(attr); + this.attributes.put(id, set); + } + if (attr.includeInResult()) { + this.includeAttributes.add(attr); + } + } + + if (content != null) { + if (xacmlVersion < Constants.XACML_VERSION_3_0 + && !category.equals(Constants.RESOURCE_CAT)) { + throw new IllegalArgumentException("Can't have Content" + + " in this category for this XACML version"); + } + this.content = content.cloneNode(true); + } + + if (category == null) { + throw new IllegalArgumentException("Request elements " + + "require a category"); + } + this.category = category; + this.xacmlVersion = xacmlVersion; + this.withSubjectCategory = withSubjectCategory; + } + + /** + * Constructor. Creates a request element out of it's name and attributes + * (already in Map), without content. + * + * @param category the cateogry, must not be null + * @param attributes must be a Map of Sets + * containing Attribute objects, keyed + * by the attribute ids. Must not be null or empty. + */ + public RequestElement(URI category, Map> attributes) { + this(category, attributes, null); + + } + + /** + * Constructor. Creates a request element out of it's name and attributes + * (already in Map), with content. + * + * @param category the cateogry, must not be null + * @param attributes must be a Map of Sets + * containing Attribute objects, keyed + * by the attribute ids. Must not be null or empty. + * @param content the content element, or null if there is no content. + */ + public RequestElement(URI category, Map> attributes, Node content) { + this.includeAttributes = new HashSet(); + if (attributes == null || attributes.isEmpty()) { + throw new IllegalArgumentException("Can't create RequestElement" + + " with empty or null attributes map."); + } + Iterator>> entries = attributes.entrySet().iterator(); + while(entries.hasNext()) { + Map.Entry> foo = entries.next(); +// if (!(foo.getKey() instanceof URI)) { +// throw new IllegalArgumentException("Can't create a Request" +// + "Element with non URI keys in the attributes" +// + " Map"); +// } +// Object bar = foo.getValue(); +// if (!(bar instanceof Set)) { +// throw new IllegalArgumentException("Can't create a Request" +// + "Element with non-Set objects in the attributes" +// + " Map"); +// } +// Set attrSet = (Set)bar; + Set attrSet = foo.getValue(); + Iterator iter = attrSet.iterator(); + while(iter.hasNext()) { + Object foobar = iter.next(); + if (!(foobar instanceof Attribute)) { + throw new IllegalArgumentException("Can't create a" + + " RequestElement with non-Attribute objects in" + + " the sets in the attributes Map"); + } + Attribute attr = (Attribute)foobar; + if (!attr.getId().equals(foo.getKey())) { + throw new IllegalArgumentException("Key mapped" + + " to the wrong attribute in attributes map"); + } + if (attr.includeInResult()) { + this.includeAttributes.add(attr); + } + } + + } + this.attributes = new HashMap>(attributes); + if (content != null) { + this.content = content.cloneNode(true); + } + this.category = category; + } + + /** + * The clone method. + * + * @return a copy of this object. + */ + public Object clone() { + try { + RequestElement clone = (RequestElement)super.clone(); + // deep copy of the attributes + clone.attributes = new HashMap>(); + clone.includeAttributes = new HashSet(); + Iterator iter = this.attributes.keySet().iterator(); + while(iter.hasNext()) { + URI key = URI.create(iter.next().toString()); + Set attrs = new HashSet(); + Iterator iter2 = this.attributes.get(key).iterator(); + while(iter2.hasNext()) { + attrs.add( (Attribute) iter2.next().clone()); + } + clone.attributes.put(key, attrs); + } + Iterator iter3 = this.includeAttributes.iterator(); + while(iter3.hasNext()) { + clone.includeAttributes.add( (Attribute) iter3.next().clone()); + } + if (this.content != null) { + clone.content = this.content.cloneNode(true); + } + clone.category = this.category; + clone.xacmlVersion = this.xacmlVersion; + clone.withSubjectCategory = this.withSubjectCategory; + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone RequestElement"); + } + } + + /** + * Create a new RequestElement by parsing a node in a + * request. This node should be created by schema-verified parsing of an + * XML document. + * + * @param root the node to parse for the RequestElement + * @param metaData the meta-data associated with the containing request. + * + * @return a new RequestElement constructed by parsing + * + * @throws ParsingException if the DOM node is invalid + */ + public static RequestElement getInstance(Element root, + PolicyMetaData metaData) throws ParsingException { + URI category = null; + boolean withSubjectCategory = false; + if (metaData.getXACMLVersion() == Constants.XACML_VERSION_3_0) { + NamedNodeMap xmlAttrs = root.getAttributes(); + if (xmlAttrs == null) { + throw new ParsingException("No XML attributes found," + + " where Category attribute was expected"); + } + Node catNode = xmlAttrs.getNamedItem("Category"); + if (catNode == null) { + throw new ParsingException("'Category' XML attribute " + + "not found"); + } + + String categoryStr = catNode.getNodeValue(); + try { + category = new URI(categoryStr); + } catch (URISyntaxException e) { + throw new ParsingException("Error while parsing " + + "category: " + categoryStr, e); + } + } else if (metaData.getXACMLVersion() + < Constants.XACML_VERSION_3_0) { + if (root.getLocalName().equals("Subject")) { + NamedNodeMap xmlAttrs = root.getAttributes(); + if (xmlAttrs == null) { + category = Constants.SUBJECT_CAT; + } else { + Node catNode = xmlAttrs.getNamedItem("SubjectCategory"); + if (catNode == null) { + category = Constants.SUBJECT_CAT; + } else { + withSubjectCategory = true; + String categoryStr = catNode.getNodeValue(); + try { + category = new URI(categoryStr); + } catch (URISyntaxException e) { + throw new ParsingException("Error while parsing " + + "category: " + categoryStr, e); + } + } + } + } else if (root.getLocalName().equals("Resource")) { + category = Constants.RESOURCE_CAT; + } else if (root.getLocalName().equals("Action")) { + category = Constants.ACTION_CAT; + } else if (metaData.getXACMLVersion() + == Constants.XACML_VERSION_2_0 + && root.getLocalName().equals("Environment")) { + category = Constants.ENVIRONMENT_CAT; + } else { + throw new ParsingException("Invalid node: " + + root.getLocalName() + " in XACML " + + metaData.getXACMLVersion() + " request"); + } + } else { + throw new ParsingException("Invalid/Unsupported XACML version"); + } + + // Find the content element if there is one + Node content = null; + NodeList children = root.getChildNodes(); + for(int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + if (node != null && node.getNodeType() == Node.ELEMENT_NODE) { + if (node.getLocalName().equals("Content")) { + if (metaData.getXACMLVersion() + < Constants.XACML_VERSION_3_0) { + throw new ParsingException("Content element not"+ + " supported for XACML version " + + metaData.getXACMLVersion()); + } + content = node.cloneNode(true); + break; + } else if (node.getLocalName().equals("ResourceContent")) { + if (metaData.getXACMLVersion() + > Constants.XACML_VERSION_2_0) { + throw new ParsingException("ResourceContent element not" + + " supported for XACML version " + + metaData.getXACMLVersion()); + } + content = node.cloneNode(true); + break; + } + } + } + + Set attributes = parseAttributes(root); + + return new RequestElement(category, attributes, content, + metaData.getXACMLVersion(), withSubjectCategory); + } + + /** + * Helper method that parses a set of Attribute types. + * @param root the root Node containing the set of + * Attributes and Contents + * @return A Set Attributes. + */ + private static Set parseAttributes(Node root) throws ParsingException { + Set set = new HashSet(); + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Attribute")) { + List attrs = Attribute.getInstances(node); + set.addAll(attrs); + } + } + return set; + } + + /** + * Get the category of this request element. + * + * @return the category of the request element + */ + public URI getCategory() { + return this.category; + } + + /** + * Get the attributes of the request element as a Map + * The keys of the Map are the attribute ids. + * + * @return the Map of Sets of + * Attributes of the request element. + */ + public Map> getAttributes() { + return Collections.unmodifiableMap(this.attributes); + } + + /** + * Get the content node of the request element if there is one. + * + * @return a Node or null. + * + */ + public Node getContent() { + if (this.content == null) { + return null; + } + return this.content.cloneNode(true); + } + + /** + * @return The Set of attributes with the includeInResult + * flag. + */ + public Set getIncludeInResultSet() { + return Collections.unmodifiableSet(this.includeAttributes); + } + + + /** + * Encodes this request element into its XML representation and writes + * this encoding to the given OutputStream without + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this request element into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + // setup the formatting & outstream stuff + String indent = indenter.makeString(); + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + + // write out the encoded form + String endTag = null; + if (this.xacmlVersion > Constants.XACML_VERSION_2_0) { + out.println(indent + ""); + endTag = indent + ""; + } else { + if (this.category.equals(Constants.RESOURCE_CAT)) { + out.println(indent + ""); + endTag = indent + ""; + } else if (this.category.equals(Constants.ACTION_CAT)) { + out.println(indent + ""); + endTag = indent + ""; + } else if (this.xacmlVersion == Constants.XACML_VERSION_2_0 + && this.category.equals(Constants.ENVIRONMENT_CAT)) { + out.println(indent + ""); + endTag = indent + ""; + } else { + if (this.withSubjectCategory) { + out.println(indent + ""); + endTag = indent + ""; + } else { + out.println(indent + ""); + endTag = indent + ""; + } + } + } + + // go in one more for next-level elements... + indenter.in(); + + if (this.content != null) { + out.println(indenter.makeString() + ""); + encodeContent(this.content, output, charsetName, indenter); + out.println(indenter.makeString() + ""); + } + encodeAttributes(this.attributes, output, charsetName, indenter); + + indenter.out(); + + //Notice: the indent was already included previously + out.println(endTag); + } + + /** + * Private helper function to encode the content node. + * @throws UnsupportedEncodingException + */ + private void encodeContent(Node content, OutputStream output, + String charsetName, Indenter indenter) + throws UnsupportedEncodingException { + indenter.in(); + String indent = indenter.makeString(); + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + StringWriter sw = new StringWriter(); + try { + Transformer serializer + = TransformerFactory.newInstance().newTransformer(); + serializer.setOutputProperty( + OutputKeys.OMIT_XML_DECLARATION, "yes"); + serializer.transform(new DOMSource(content), new StreamResult(sw)); + } catch (TransformerException e) { + throw new RuntimeException( + "'This never happens' error happened"); + } + out.println(indent + sw.toString()); + indenter.out(); + } + + /** + * Private helper function to encode the attribute sets + * @throws UnsupportedEncodingException + */ + private void encodeAttributes(Map> attributes, OutputStream output, + String charsetName, Indenter indenter) + throws UnsupportedEncodingException { + Iterator>> it = attributes.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> entry = it.next(); + Set set = entry.getValue(); + Iterator it2 = set.iterator(); + while (it2.hasNext()) { + Attribute attr = (Attribute) it2.next(); + attr.encode(output, charsetName, indenter); + } + } + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/ResponseCtx.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/ResponseCtx.java new file mode 100644 index 0000000..e6cbb39 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/ResponseCtx.java @@ -0,0 +1,224 @@ + +/* + * @(#)ResponseCtx.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.Constants; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the response to a request made to the XACML PDP. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + */ +public class ResponseCtx +{ + + // The set of Result objects returned by the PDP + private Set results = null; + + /** + * Constructor that creates a new ResponseCtx with only a + * single Result (a common case). + * + * @param result the single result in the response + */ + public ResponseCtx(Result result) { + this.results = new HashSet(); + this.results.add(result); + } + + /** + * Constructor that creates a new ResponseCtx with a + * Set of Results. The Set must + * be non-empty. + * + * @param results a Set of Result objects + */ + public ResponseCtx(Set results) { + this.results = Collections.unmodifiableSet(new HashSet(results)); + } + + /** + * Creates a new instance of ResponseCtx based on the given + * DOM root node. A ParsingException is thrown if the DOM + * root doesn't represent a valid ResponseType. + * + * @param root the DOM root of a ResponseType + * + * @return a new ResponseCtx + * + * @throws ParsingException if the node is invalid + */ + public static ResponseCtx getInstance(Node root) throws ParsingException { + // check if this really is a response + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("Response")) { + throw new ParsingException("Can't create a Response from a " + + root.getLocalName() + " element"); + } + Set results = new HashSet(); + + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Result")) { + results.add(Result.getInstance(node)); + } + } + + if (results.size() == 0) { + throw new ParsingException("must have at least one Result"); + } + return new ResponseCtx(results); + } + + /** + * Creates a new ResponseCtx by parsing XML from an + * input stream. Note that this is a convenience method, and it will + * not do schema validation by default. You should be parsing the data + * yourself, and then providing the root node to the other + * getInstance method. If you use this convenience + * method, you probably want to turn on validation by setting the + * context schema file (see the programmer guide for more information + * on this). + * + * @param input a stream providing the XML data + * + * @return a new ResponseCtx + * + * @throws ParsingException if there is an error parsing the input + */ + public static ResponseCtx getInstance(InputStream input) + throws ParsingException + { + return getInstance(InputParser.parseInput(input, "Response")); + } + + /** + * Get the set of Results from this response. + * + * @return a Set of results + */ + public Set getResults() { + return this.results; + } + + /** + * Encodes this context into its XML representation and writes this + * encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this context into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + + // Make a PrintStream for a nicer printing interface + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + + // Prepare the indentation string + String indent = indenter.makeString(); + + // Now write the XML... + + out.println(indent + ""); + + // Go through all results + Iterator it = this.results.iterator(); + indenter.in(); + + while (it.hasNext()) { + Result result = it.next(); + result.encode(out, charsetName, indenter); + } + + indenter.out(); + + // Finish the XML for a response + out.println(indent + ""); + + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Result.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Result.java new file mode 100644 index 0000000..6a81436 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Result.java @@ -0,0 +1,723 @@ +/* + * @(#)Result.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Indenter; +import com.sun.xacml.Obligation; +import com.sun.xacml.ParsingException; +import com.sun.xacml.PolicyMetaData; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the ResultType XML object from the Context schema. Any number + * of these may included in a ResponseCtx. This class encodes the + * decision effect, as well as an optional resource identifier and optional + * status data. Any number of obligations may also be included. + * + * @since 1.0 + * @author Seth Proctor + * @author Marco Barreno + */ +public class Result implements Cloneable +{ + +// public enum DECISION { +// DECISION_PERMIT, +// DECISION_DENY, +// DECISION_INDETERMINATE, +// DECISION_NOT_APPLICABLE, +// INVALID_DECISION; +// +// private String[] messages = { PERMIT, DENY, +// INDETERMINATE, +// NOT_APPLICABLE, "Invalid" }; +// +// public String getMessage() { +// return messages[this.ordinal()]; +// } +// +// public static DECISION getFromInt(int decision) { +// switch (decision) { +// case Result.DECISION_PERMIT: +// return DECISION_PERMIT; +// case Result.DECISION_DENY: +// return DECISION_DENY; +// case Result.DECISION_INDETERMINATE: +// return DECISION_INDETERMINATE; +// case Result.DECISION_NOT_APPLICABLE: +// return DECISION_NOT_APPLICABLE; +// case Result.INVALID_DECISION: +// return INVALID_DECISION; +// } +// return null; +// } +// } + + /** + * The decision to permit the request + */ + public static final int DECISION_PERMIT = 0; + + /** + * The decision to deny the request + */ + public static final int DECISION_DENY = 1; + + /** + * The decision that a decision about the request cannot be made + */ + public static final int DECISION_INDETERMINATE = 2; + + /** + * The decision that nothing applied to us + */ + public static final int DECISION_NOT_APPLICABLE = 3; + + /** + * An uninitialized decision value + */ + public static final int INVALID_DECISION = 5; + + + public static final String PERMIT = "Permit"; + + public static final String DENY = "Deny"; + + public static final String INDETERMINATE = "Indeterminate"; + + public static final String NOT_APPLICABLE = "NotApplicable"; + + + + /** + * string versions of the 4 Decision types used for encoding + */ + private static final String [] PRIVATE_DECISIONS = { PERMIT, DENY, + INDETERMINATE, + NOT_APPLICABLE}; + + /** + * unmodifiable list of the previous + */ + public static final List DECISIONS = + Collections.unmodifiableList(Arrays.asList(PRIVATE_DECISIONS)); + + + + /** + * Null string for disambiguation. + */ + public static final String nullString = null; + + /** + * the decision effect + */ + private int decision = -1; + + /** + * the status data + */ + private Status status = null; + + /** + * the resource identifier or null if there is none + */ + private String resource = null; + + /** + * the Set of RequestElements describing + * the attributes included in the result. May be empty. + */ + private Set includedAttributes; + + /** + * the set of obligations which may be empty + */ + private Set obligations; + + /** + * Constructs a Result object with default status data (OK). + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision) throws IllegalArgumentException { + this(decision, null, nullString, null); + } + + /** + * Constructs a Result object with default status data (OK), + * and obligations, but no resource identifier. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param obligations the obligations the PEP must handle + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Set obligations) + throws IllegalArgumentException + { + this(decision, null, nullString, obligations); + } + + /** + * Constructs a Result object with status data but without a + * resource identifier. Typically the decision is DECISION_INDETERMINATE + * in this case, though that's not always true. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Status status) throws IllegalArgumentException { + this(decision, status, nullString, null); + } + + /** + * Constructs a Result object with status data and obligations + * but without a resource identifier. Typically the decision is + * DECISION_INDETERMINATE in this case, though that's not always true. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * @param obligations the obligations the PEP must handle + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Status status, Set obligations) + throws IllegalArgumentException + { + this(decision, status, nullString, obligations); + } + + /** + * Constructs a Result object with a resource identifier, + * but default status data (OK). The resource being named must match + * the resource (or a descendent of the resource in the case of a + * hierarchical resource) from the associated request. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param context the evaluation context to determine the ResourceId + * or the included attributes. + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, EvaluationCtx context) + throws IllegalArgumentException + { + this(decision, null, context, null); + } + + /** + * Constructs a Result object with a resource identifier, + * and obligations, but default status data (OK). The resource being named + * must match the resource (or a descendent of the resource in the case of + * a hierarchical resource) from the associated request. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param context the evaluation context to determine the ResourceId + * or the included attributes. + * @param obligations the obligations the PEP must handle + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, EvaluationCtx context, Set obligations) + throws IllegalArgumentException + { + this(decision, null, context, obligations); + } + + /** + * Constructs a Result object with status data and a + * resource identifier. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * @param context the evaluation context to determine the ResourceId + * or the included attributes. + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Status status, EvaluationCtx context) + throws IllegalArgumentException + { + this(decision, status, context, null); + } + + /** + * Constructs a Result object with status data, a + * resource identifier, and obligations. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * @param context the evaluation context to determine the ResourceId + * or the included attributes. + * @param obligations the obligations the PEP must handle + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Status status, EvaluationCtx context, + Set obligations) + throws IllegalArgumentException { + // check that decision is valid + if ((decision != DECISION_PERMIT) && (decision != DECISION_DENY) && + (decision != DECISION_INDETERMINATE) && + (decision != DECISION_NOT_APPLICABLE) ) { + throw new IllegalArgumentException("invalid decision value"); + } + this.decision = decision; + + if (status == null) { + this.status = Status.getOkInstance(); + } else { + this.status = status; + } + if (obligations == null) { + this.obligations = new HashSet(); + } else { + this.obligations = obligations; + } + + this.includedAttributes = new HashSet(); + if (!context.getIncludedAttributes().isEmpty()) { + this.includedAttributes = new HashSet(context.getIncludedAttributes()); + Iterator iter = this.includedAttributes.iterator(); + while (iter.hasNext()) { + if (!(iter.next() instanceof RequestElement)) { + throw new IllegalArgumentException("included attributes" + + " must be RequestElement objects"); + } + } + } else if (context.getResourceId() != null) { + this.resource = context.getResourceId().encode(); + } + } + + /** + * Constructs a Result object with status data, a + * resource identifier, and obligations. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * @param resource the ResourceId this result refers to. + * @param obligations the obligations the PEP must handle + * + * @throws IllegalArgumentException if decision is not valid + */ + public Result(int decision, Status status, String resource, + Set obligations) throws IllegalArgumentException { + // check that decision is valid + if ((decision != DECISION_PERMIT) && (decision != DECISION_DENY) && + (decision != DECISION_INDETERMINATE) && + (decision != DECISION_NOT_APPLICABLE)) { + throw new IllegalArgumentException("invalid decision value"); + } + this.decision = decision; + + if (status == null) { + this.status = Status.getOkInstance(); + } else { + this.status = status; + } + if (obligations == null) { + this.obligations = new HashSet(); + } else { + this.obligations = obligations; + } + + // not used by this constructor + this.includedAttributes = new HashSet(); + + this.resource = resource; + } + + /** + * Constructs a Result object with status data, a + * resource identifier, obligations and included attributes. + * + * @param decision the decision effect to include in this result. This + * must be one of the four fields in this class. + * @param status the Status to include in this result + * @param includedAttributes the Set of + * RequestElements describing + * the attributes included in the result. + * Can be null. + * @param obligations the obligations the PEP must handle@param decision + * + * @throws IllegalArgumentException + */ + public Result(int decision, Status status, Set includedAttributes, + Set obligations) throws IllegalArgumentException { + // check that decision is valid + if ((decision != DECISION_PERMIT) && (decision != DECISION_DENY) && + (decision != DECISION_INDETERMINATE) && + (decision != DECISION_NOT_APPLICABLE)) { + throw new IllegalArgumentException("invalid decision value"); + } + this.decision = decision; + + if (status == null) { + this.status = Status.getOkInstance(); + } else { + this.status = status; + } + if (obligations == null) { + this.obligations = new HashSet(); + } else { + this.obligations = obligations; + } + + this.includedAttributes = new HashSet(); + if (includedAttributes != null && !includedAttributes.isEmpty()) { + this.includedAttributes = includedAttributes; + Iterator iter = this.includedAttributes.iterator(); + while (iter.hasNext()) { + if (!(iter.next() instanceof RequestElement)) { + throw new IllegalArgumentException("included attributes" + + " must be RequestElement objects"); + } + } + } + } + + /** + * The clone method. + * + * @return a copy of this object. + */ + public Object clone() { + try { + Result clone = (Result)super.clone(); + clone.decision = this.decision; + clone.status = this.status; + clone.resource = this.resource; + clone.includedAttributes = this.includedAttributes; + clone.obligations = this.obligations; + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone Result"); + } + } + + + /** + * Creates a new instance of a Result based on the given + * DOM root node. A ParsingException is thrown if the DOM + * root doesn't represent a valid ResultType. + * + * @param root the DOM root of a ResultType + * + * @return a new Result + * + * @throws ParsingException if the node is invalid + */ + public static Result getInstance(Node root) throws ParsingException { + //check if this really is a result + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("Result")) { + throw new ParsingException("Can't create a Result from a " + + root.getLocalName() + " element"); + } + int decision = -1; + Status status = null; + String resource = null; + Set obligations = null; + Set includedAttributes = new HashSet(); + + NamedNodeMap attrs = root.getAttributes(); + Node resourceAttr = attrs.getNamedItem("ResourceId"); + if (resourceAttr != null) { + resource = resourceAttr.getNodeValue(); + } + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + String name = node.getLocalName(); + + if (name.equals("Decision")) { + String type = node.getFirstChild().getNodeValue(); + for (int j = 0; j < DECISIONS.size(); j++) { + if (DECISIONS.get(j).equals(type)) { + decision = j; + break; + } + } + + if (decision == -1) { + throw new ParsingException("Unknown Decision: " + + type); + } + } else if (name.equals("Status")) { + status = Status.getInstance(node); + } else if (name.equals("Obligations")) { + obligations = parseObligations(node); + } else if (name.equals("Attributes")) { + if (resource != null) { + throw new ParsingException("Can not mix ResourceId" + + " and included attributes"); + } + //parse RequestElement with default 3.0 metaData + includedAttributes.add(RequestElement.getInstance( + (Element)node, new PolicyMetaData())); + } + } + } + + if (resource != null) { + return new Result(decision, status, resource, obligations); + } + return new Result(decision, status, includedAttributes, + obligations); + } + + /** + * Helper method that handles the obligations + */ + private static Set parseObligations(Node root) throws ParsingException { + Set set = new HashSet(); + + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE + && node.getLocalName().equals("Obligation")) { + set.add(Obligation.getInstance(node)); + } + } + + if (set.size() == 0) { + throw new ParsingException("ObligationsType must not be empty"); + } + return set; + } + + /** + * Returns the decision associated with this Result. This + * will be one of the four DECISION_* fields in this class. + * + * @return the decision effect + */ + public int getDecision() { + return this.decision; + } + + /** + * Returns the status data included in this Result. + * Typically this will be STATUS_OK except when the decision + * is INDETERMINATE. + * + * @return status associated with this Result + */ + public Status getStatus() { + return this.status; + } + + /** + * Returns the resource to which this Result applies, or null if none + * is specified. + * + * @return a resource identifier or null + */ + public String getResource() { + return this.resource; + } + + /** + * @return Returns the included attributes as a Set of + * Attributes. This may be empty. + */ + public Set getIncludedAttributes() { + return this.includedAttributes; + } + + /** + * Sets the resource identifier if it has not already been set before. + * The core code does not set the resource identifier, so this is useful + * if you want to write wrapper code that needs this information. + * + * @param resource the resource identifier + * + * @return true if the resource identifier was set, false if it already + * had a value + */ + public boolean setResource(String resource) { + if (this.resource != null) { + return false; + } + this.resource = resource; + + return true; + } + + /** + * Returns the set of obligations that the PEP must fulfill, which may + * be empty. + * + * @return the set of obligations + */ + public Set getObligations() { + return this.obligations; + } + + /** + * Adds an obligation to the set of obligations that the PEP must fulfill + * + * @param obligation the Obligation to add + */ + public void addObligation(Obligation obligation) { + if (obligation != null) { + this.obligations.add(obligation); + } + } + + /** + * Encodes this Result into its XML form and writes this + * out to the provided OutputStream with no indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this Result into its XML form and writes this + * out to the provided OutputStream with indentation. + * + * @param output a stream into which the XML-encoded data is written + * @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + indenter.in(); + String indentNext = indenter.makeString(); + + // encode the starting tag + if (this.resource == null || + !this.includedAttributes.isEmpty()) { + out.println(indent + ""); + } else { + out.println(indent + ""); + } + + // encode the decision + out.println(indentNext + "" + DECISIONS.get(this.decision) + + ""); + // encode the included attributes + if (!this.includedAttributes.isEmpty()) { + Iterator it = this.includedAttributes.iterator(); + while (it.hasNext()) { + RequestElement element = (RequestElement)(it.next()); + element.encode(output, charsetName, indenter); + } + } + + // encode the status + if (this.status != null) { + this.status.encode(output, charsetName, indenter); + } + + // encode the obligations + if (this.obligations.size() != 0) { + out.println(indentNext + ""); + + Iterator it = this.obligations.iterator(); + indenter.in(); + + while (it.hasNext()) { + Obligation obligation = (Obligation)(it.next()); + obligation.encode(output, charsetName, indenter); + } + + indenter.out(); + out.println(indentNext + ""); + } + + indenter.out(); + + // finish it off + out.println(indent + ""); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Status.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Status.java new file mode 100644 index 0000000..56f2b73 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/Status.java @@ -0,0 +1,404 @@ + +/* + * @(#)Status.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.Constants; +import com.sun.xacml.Indenter; +import com.sun.xacml.ParsingException; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * Represents the status data that is included in a ResultType. By default, + * the status is OK. + * + * @since 1.0 + * @author Seth Proctor + */ +public class Status +{ + + /** + * Standard identifier for the OK status + */ + public static final String STATUS_OK = + "urn:oasis:names:tc:xacml:1.0:status:ok"; + + /** + * Standard identifier for the MissingAttribute status + */ + public static final String STATUS_MISSING_ATTRIBUTE = + "urn:oasis:names:tc:xacml:1.0:status:missing-attribute"; + + /** + * Standard identifier for the SyntaxError status + */ + public static final String STATUS_SYNTAX_ERROR = + "urn:oasis:names:tc:xacml:1.0:status:syntax-error"; + + /** + * Standard identifier for the ProcessingError status + */ + public static final String STATUS_PROCESSING_ERROR = + "urn:oasis:names:tc:xacml:1.0:status:processing-error"; + + // the status code + private List code; + + // the message + private String message; + + // the detail + private StatusDetail detail; + + // a single OK object we'll use most of the time + private static Status okStatus; + + // initialize the OK Status object + static { + List code = new ArrayList(); + code.add(STATUS_OK); + okStatus = new Status(code); + } + + /** + * Constructor that takes only the status code. + * + * @param code a List of String codes, typically + * just one code, but this may contain any number of minor + * codes after the first item in the list, which is the major + * code + */ + public Status(List code) { + this(code, null, null); + } + + /** + * Constructor that takes both the status code and a message to include + * with the status. + * + * @param code a List of String codes, typically + * just one code, but this may contain any number of minor + * codes after the first item in the list, which is the major + * code + * @param message a message to include with the code + */ + public Status(List code, String message) { + this(code, message, null); + } + + /** + * Constructor that takes the status code, an optional message, and some + * detail to include with the status. Note that the specification + * explicitly says that a status code of OK, SyntaxError or + * ProcessingError may not appear with status detail, so an exception is + * thrown if one of these status codes is used and detail is included. + * + * @param code a List of String codes, typically + * just one code, but this may contain any number of minor + * codes after the first item in the list, which is the major + * code + * @param message a message to include with the code, or null if there + * should be no message + * @param detail the status detail to include, or null if there is no + * detail + * + * @throws IllegalArgumentException if detail is included for a status + * code that doesn't allow detail + */ + public Status(List code, String message, StatusDetail detail) + throws IllegalArgumentException + { + // if the code is ok, syntax error or processing error, there + // must not be any detail included + if (detail != null) { + String c = (String)(code.iterator().next()); + if (c.equals(STATUS_OK) || c.equals(STATUS_SYNTAX_ERROR) || + c.equals(STATUS_PROCESSING_ERROR)) { + throw new IllegalArgumentException("status detail cannot be " + + "included with " + c); + } + } + + this.code = Collections.unmodifiableList(new ArrayList(code)); + this.message = message; + this.detail = detail; + } + + /** + * Returns the status code. + * + * @return the status code + */ + public List getCode() { + return this.code; + } + + /** + * Returns the status message or null if there is none. + * + * @return the status message or null + */ + public String getMessage() { + return this.message; + } + + /** + * Returns the status detail or null if there is none. + * + * @return a StatusDetail or null + */ + public StatusDetail getDetail() { + return this.detail; + } + + /** + * Gets a Status instance that has the OK status and no + * other information. This is the default status data for all responses + * except Indeterminate ones. + * + * @return an instance with STATUS_OK + */ + public static Status getOkInstance() { + return okStatus; + } + + /** + * Creates a new instance of Status based on the given + * DOM root node. A ParsingException is thrown if the DOM + * root doesn't represent a valid StatusType. + * + * @param root the DOM root of a StatusType + * + * @return a new Status + * + * @throws ParsingException if the node is invalid + */ + public static Status getInstance(Node root) throws ParsingException { + if (root.getNodeType() != Node.ELEMENT_NODE + || !root.getLocalName().equals("Status")) { + throw new ParsingException("Can't create a Status from a " + + root.getLocalName() + " element"); + } + List code = null; + String message = null; + StatusDetail detail = null; + + NodeList nodes = root.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + String name = node.getLocalName(); + if (name.equals("StatusCode")) { + code = parseStatusCode(node); + } else if (name.equals("StatusMessage")) { + message = node.getFirstChild().getNodeValue(); + } else if (name.equals("StatusDetail")) { + detail = StatusDetail.getInstance(node); + } + } + } + + return new Status(code, message, detail); + } + + /** + * Private helper that parses the status code + */ + private static List parseStatusCode(Node root) { + // get the top-level code + String val = root.getAttributes().getNamedItem("Value").getNodeValue(); + List code = new ArrayList(); + code.add(val); + + // now get the list of all sub-codes, and work through them + NodeList list = ((Element)root).getElementsByTagName("StatusCode"); + for (int i = 0; i < list.getLength(); i++) { + Node node = list.item(i); + code.add(node.getAttributes().getNamedItem("Value"). + getNodeValue()); + } + + return code; + } + + /** + * Encodes this status data into its XML representation and writes + * this encoding to the given OutputStream with no + * indentation. + * + * @param output a stream into which the XML-encoded data is written + @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName) + throws UnsupportedEncodingException { + encode(output, charsetName, new Indenter(0)); + } + + /** + * Encodes this status data into its XML representation and writes + * this encoding to the given OutputStream with + * indentation. + * + * @param output a stream into which the XML-encoded data is written + @param charsetName the character set to use in encoding of strings. + * This may be null in which case the platform + * default character set will be used. + * @param indenter an object that creates indentation strings + * + * @throws UnsupportedEncodingException + */ + public void encode(OutputStream output, String charsetName, + Indenter indenter) + throws UnsupportedEncodingException { + PrintStream out; + if(charsetName == null) { + out = new PrintStream(output); + } else { + out = new PrintStream(output, false, charsetName); + } + String indent = indenter.makeString(); + + out.println(indent + ""); + + indenter.in(); + + encodeStatusCode(out, indenter, this.code.iterator()); + + if (this.message != null) { + out.println(indenter.makeString() + "" + + this.message + ""); + } + + if (this.detail != null) { + out.println(this.detail.getEncoded()); + } + + indenter.out(); + + out.println(indent + ""); + } + + /** + * Encodes the object in XML + */ + private void encodeStatusCode(PrintStream out, Indenter indenter, + Iterator iterator) { + String in = indenter.makeString(); + String code = iterator.next(); + + if (iterator.hasNext()) { + indenter.in(); + out.println(in + ""); + encodeStatusCode(out, indenter, iterator); + out.println(in + ""); + indenter.out(); + } else { + out.println(in + ""); + } + } + + + /** + * @param indenter + * @return the string representation of this status message + * encoded in XML + */ + public String toString(Indenter indenter) { + String indent = indenter.makeString(); + + String result = indent + "" + Constants.nl; + + indenter.in(); + + result += statusCode2String(indenter, this.code.iterator()); + + if (this.message != null) { + result += indenter.makeString() + "" + + this.message + "" + Constants.nl; + } + if (this.detail != null) { + result += indenter.makeString() + this.detail.getEncoded(); + } + indenter.out(); + + result += indent + "" + Constants.nl; + + return result; + } + + private String statusCode2String(Indenter indenter, Iterator it) { + String in = indenter.makeString(); + String code = it.next(); + String result; + + if (it.hasNext()) { + indenter.in(); + result = in + "" + Constants.nl; + result += statusCode2String(indenter, it); + result += in + "" + Constants.nl; + indenter.out(); + } else { + result = in + "" + + Constants.nl; + } + return result; + } + + public static Status createStatus(String code, String message) { + List codes = new ArrayList(); + codes.add(code); + return new Status(codes, message); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/StatusDetail.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/StatusDetail.java new file mode 100644 index 0000000..ab17224 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/StatusDetail.java @@ -0,0 +1,209 @@ + +/* + * @(#)StatusDetail.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.ctx; + +import com.sun.xacml.Constants; +import com.sun.xacml.ParsingException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import java.util.Collection; +import java.util.Iterator; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + + +/** + * This class represents the StatusDetailType in the context schema. Because + * status detail is defined as a sequence of xs:any XML type, the data in + * this class must be generic, and it is up to the application developer to + * interpret the data appropriately. + * + * @since 1.0 + * @author Seth Proctor + */ +public class StatusDetail +{ + + // the root node + private Node detailRoot; + + // the text version, if it's avilable already + private String detailText = null; + + /** + * Constructor that uses a List of Attributes + * to define the status detail. This is a common form of detail data, + * and can be used for things like providing the information included + * with the missing-attribute status code. + * + * @param attributes a List of Attributes + * + * @throws IllegalArgumentException if there is a problem encoding the + * Attributes + */ + public StatusDetail(Collection attributes) throws IllegalArgumentException { + this.detailText = "" + Constants.nl; + Iterator it = attributes.iterator(); + + while (it.hasNext()) { + Attribute attr = it.next(); + this.detailText += attr.encode() + Constants.nl; + } + + this.detailText += ""; + + try { + this.detailRoot = textToNode(this.detailText); + } catch (ParsingException pe) { + // really, this should never happen, since we just made sure that + // we're working with valid text, but it's possible that encoding + // the attribute could have caused problems... + throw new IllegalArgumentException("invalid Attribute data"); + } + } + + /** + * Constructor that takes the text-encoded form of the XML to use as + * the status data. The encoded text will be wrapped with the + * StatusDetail XML tag, and the resulting text must + * be valid XML or a ParsingException will be thrown. + * + * @param encoded a non-null String that encodes the + * status detail + * + * @throws ParsingException if the encoded text is invalid XML + */ + public StatusDetail(String encoded) throws ParsingException { + this.detailText = "" + Constants.nl + encoded + + Constants.nl + ""; + this.detailRoot = textToNode(this.detailText); + } + + /** + * Private constructor that just sets the root node. This interface + * is provided publically through the getInstance method. + */ + private StatusDetail(Node root) { + this.detailRoot = root; + } + + /** + * Private helper routine that converts text into a node + */ + private Node textToNode(String encoded) throws ParsingException { + try { + String text = "" + Constants.nl; + byte [] bytes = (text + encoded).getBytes(); + + DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + DocumentBuilder db = factory.newDocumentBuilder(); + Document doc = db.parse(new ByteArrayInputStream(bytes)); + + return doc.getDocumentElement(); + } catch (ParserConfigurationException e) { + throw new ParsingException("invalid XML for status detail"); + } catch (SAXException e) { + throw new ParsingException("invalid XML for status detail"); + } catch (IOException e) { + throw new ParsingException("invalid XML for status detail"); + } + } + + /** + * Creates an instance of a StatusDetail object based on + * the given DOM root node. The node must be a valid StatusDetailType + * root, or else a ParsingException is thrown. + * + * @param root the DOM root of the StatusDetailType XML type + * + * @return a new StatusDetail object + * + * @throws ParsingException if the root node is invalid + */ + public static StatusDetail getInstance(Node root) throws ParsingException { + // check that it's really a StatusDetailType root + if (root.getNodeType() != Node.ELEMENT_NODE || + ! root.getLocalName().equals("StatusDetail")) { + throw new ParsingException("not a StatusDetail node"); + } + + return new StatusDetail(root); + } + + /** + * Returns the StatusDetailType DOM root node. This may contain within + * it any type of valid XML data, and it is up to the application writer + * to handle the data accordingly. One common use of status data is to + * include Attributes, which can be created from their + * root DOM nodes using their getInstance method. + * + * @return the DOM root for the StatusDetailType XML type + */ + public Node getDetail() { + return this.detailRoot; + } + + /** + * Returns the text-encoded version of this data, if possible. If the + * String form constructor was used, this will just be the + * original text wrapped with the StatusData tag. If the List + * form constructor was used, it will be the encoded attribute data. + * If this was created using the getInstance method, then + * getEncoded will throw an exception. + * + * @return the encoded form of this data + * + * @throws IllegalStateException if this object was created using the + * getInstance method + */ + public String getEncoded() throws IllegalStateException { + if (this.detailText == null) { + throw new IllegalStateException("no encoded form available"); + } + return this.detailText; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/package.html new file mode 100644 index 0000000..9db9284 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/ctx/package.html @@ -0,0 +1,8 @@ + + All of the classes that support the context schema are in this + package. The context schema contains the request and response formats, + and so there are classes to handle everything that goes into these + exchange formats. All of the classes in this package, and all the + related classes used by this package are parsable and encodable, so + it's easy to build a PEP and a PDP using these routines. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/IndirectLocatable.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/IndirectLocatable.java new file mode 100644 index 0000000..7db62d5 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/IndirectLocatable.java @@ -0,0 +1,36 @@ +package com.sun.xacml.debug; + + +/** + * + * Some elements, i.e., mainly functions, are only referenced + * and do not have a separate java object for every referenced + * function. Thus, such functions are executed within a specific + * context which has to be set before they are called. + *
    + * Note:setting and unsetting the context (i.e., the + * SourceLocator of the encapsulating element) is NOT + * thread safe, thus, this feature should not be used when + * multiple evaluations are executed in parallel + * + * + * + */ +public interface IndirectLocatable extends Locatable { + + /** + * Sets the SourceLocator of the encapsulating element. This + * object should be retrieved from SourceLocator.getExpressionSourceLocator + * @param src + */ + void setRuntimeInfo(RuntimeInfo src); + + /** + * For the unset method, the same object should be used + * as for the set method. The unset is mainly done for detecting + * errors in the implementation. + * + * @param src + */ + void unsetRuntimeInfo(RuntimeInfo src); +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/Locatable.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/Locatable.java new file mode 100644 index 0000000..a4ed5e3 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/Locatable.java @@ -0,0 +1,28 @@ +package com.sun.xacml.debug; + + +/** + * + * This interface is used for all elements which are locatable, + * i.e., elements which + *

      + *
    • have a representation in the source code of the policy, i.e., + * are constructed from a dom node
    • + *
    • should be traceable at runtime, i.e., before/after events can + * be subsribed at evaluation runtime
    • + *
    + * + * + */ +public interface Locatable { + + /** + * + * @return a valid RuntimeInfo or null, if no information is available, + * either, during the parsing of the policies the line tracking feature + * was not activated, or, the element does not have a representation within + * the source policy, e.g., it was retrieved from a AttributeDesignator from + * or is the result of a function. + */ + RuntimeInfo getRuntimeInfo(); +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/RuntimeInfo.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/RuntimeInfo.java new file mode 100644 index 0000000..90eb512 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/debug/RuntimeInfo.java @@ -0,0 +1,306 @@ +package com.sun.xacml.debug; + +import org.apache.log4j.Logger; +import org.w3c.dom.Node; + +import com.sun.xacml.Constants; + + +/** + * This class has two purposes: + *
      + *
    • Manage the information captured at PDP startup, i.e., the parsing + * information (for now: fileName and lineNumber; may change with + * new/other PolicyLoaders)
    • + *
    • Manage the call stack information at Runtime
    • + *
    + * + * + * At runtime, this class is responsible for managing the Runtime Information + * within the XACML Engine. This class itself is NOT able to capture all + * required information at runtime. Instead, it has to be called from the outside and + * provided with the required information. + *
    + * This may be implemented by external code, e.g., by using aspectJ, capturing + * all relevant events and provide the according information to + *
      + *
    • setCalledFrom(Object calledFrom), when an object is called, whereas + * calledFrom is the calling (XACML) object
    • + *
    • unsetCalledFrom(Object calledFrom), when a call returns, i.e., the + * evaluation is finished. This function is mainly to detect bugs in + * the implementation and may be removed in productive environments
    • + *
    + *
    + * To capture all required events, the following functions have to be monitored: + *
      + *
    • PolicyTreeElement.evaluate(EvaluationCtx), which includes + * Policy, PolicySet, PolicyReference, Rule
    • + *
    • Evaluatable.evaluate(EvaluationCtx), which includes AttributeDesignator, + * AttributeSelector, AttributeValue, VariableReference, Condition, Apply
    • + *
    • MatchElement.match(EvaluationCtx ), which includes Target, TargetMatch, + * TargetMatchGroup, TargetSection
    • + *
    • Function.evaluate(List, EvaluationCtx) which includes all + * Functions
    • + *
    • CombiningAlgorithm.combine(EvaluationCtx, List, List) + * which includes all Combing Algorithms
    • + *
    + * + * + * + */ +public class RuntimeInfo { + + /** + * line number, -1 if undefined + */ + private int lineNumber = -1; + /** + * File name, null if undefined + */ + private String fileName = null; + + /** + * Defines the element type this RuntimeInfo object is assigned to + */ + private ELEMENT_TYPE eleType; + + private boolean indirectLocateable = false; + + /** + * needed to create the call stack + */ + private RuntimeInfo calledFrom; + + /** + * + */ + private Locatable xacmlObject; + + private static Logger logger = Logger.getLogger(RuntimeInfo.class); + + public enum SOURCE_TYPE { + FILE + } + + public enum ELEMENT_TYPE { + POLICY_SET ("Policy Set"), //Locatable + POLICY ("Policy"), //Locatable + POLICY_REFERENCE ("Policy Reference"), //Locatable + TARGET ("Target"), //Locatable + TARGET_SECTION ("Target Section"), //Locatable + TARGET_MATCH_GROUP ("Target Match Group"), //Locatable + TARGET_MATCH ("Target Match"), //Locatable + RULE ("Rule"), //Locatable + ATTRIBUTE_VALUE ("Attribute Value"), //Locatable + ATTRIBUTE_DESIGNATOR ("Attribute Designator"), //Locatable + ATTRIBUTE_SELECTOR ("Attribtue Selector"), //Locatable + VARIABLE_REFERENCE ("Variable Reference"), //Locatable + VARIABLE_DEFINITION ("Variable Definition"), //Locatable + CONDITION ("Condition"), //Locatable + APPLY ("Apply"), //Locatable + FUNCTION ("Function"), //IndirectLocatable + COMBINING_ALG ("Combining Algorithm"), //IndirectLocatable + OBLIGATION ("Obligation"), //Locatable + COMBINER_PARAMETER ("Combiner Parameter"); //Locatable + //COMBINER_ELEMENT ("Cimbiner Element"); //Locatable + + + private String name; + + ELEMENT_TYPE(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + } + + protected RuntimeInfo(Locatable xacmlElement, Node node, ELEMENT_TYPE type) { + this.xacmlObject = xacmlElement; + Object tmp = node.getUserData(Constants.LINE_NUMBER); + if (tmp instanceof Integer ) { + lineNumber = ((Integer) tmp).intValue(); + } + + tmp = node.getUserData(Constants.SOURCE_FILE); + if ( tmp instanceof String ) { + fileName = (String) tmp; + } + this.eleType = type; + } + + /** + * returns the line number of the object within the + * XACML source file + * @return + */ + public int getLineNumber() { + return this.lineNumber; + } + + /** + * returns the source file name + * @return + */ + public String getFileName() { + return this.fileName; + } + + public ELEMENT_TYPE getElementType() { + return this.eleType; + } + + /** + * create a new Runtime Information object or null, if no source locations are available within + * the node + * @param node + * @return + */ + public static RuntimeInfo getRuntimeInfo(Node node, ELEMENT_TYPE type ) { + if ( node.getUserData(Constants.LINE_NUMBER) != null || + node.getUserData(Constants.SOURCE_FILE) != null ) { + return new RuntimeInfo(null, node, type); + } else { + return null; + } + } + + /** + * create a new Runtime Information object or null, if no source locations are available within + * the node + * @param node + * @return + */ + public static RuntimeInfo getRuntimeInfo(Locatable xacmlObject, Node node, ELEMENT_TYPE type ) { + if ( node.getUserData(Constants.LINE_NUMBER) != null || + node.getUserData(Constants.SOURCE_FILE) != null ) { + return new RuntimeInfo(xacmlObject, node, type); + } else { + return null; + } + } + + //public void setXACMLObject(Object xacmlObject) { + public void setXACMLObject(Locatable xacmlObject) { + this.xacmlObject = xacmlObject; + } + + + public Object getXACMLObject() { + return xacmlObject; + } + + private RuntimeInfo() { + //empty constructor + } + + /** + * This function provides a new SourceLocator object which is used to set and unset + * the SourceLocator objects of IndirectLoatable elements, (i.e., used as parameter + * for setSourceLocator and unsetSourceLocator methods). + *
    + * Note: it is mainly a copy constructor which sets the new element type, thus, allow + * to differentiate + * + * @param contextSrcLocator + * @return + */ + public RuntimeInfo getIndirectRuntimeInfo(IndirectLocatable xacmlObject, ELEMENT_TYPE type) { + RuntimeInfo src = new RuntimeInfo(); + src.fileName = this.fileName; + src.lineNumber = this.lineNumber; + src.indirectLocateable = true; + src.calledFrom = this; + src.xacmlObject = xacmlObject; + src.eleType = type; + return src; + } + + /** + * This function provides a new SourceLocator object with the same location + * information as it is based on. + *
    This function should be used at parsing time and not at runtime, + * as the calledFrom information is not set (this is done at runtime). + * Currently, the only case where it is used is for XACML1.0 when an apply + * element is created to wrap a function defined by the FunctionId of the + * Condition element. + * @param xacmlObject + * @param type + * @return + */ + public RuntimeInfo getSourceLocator(Locatable xacmlObject, ELEMENT_TYPE type) { + RuntimeInfo src = new RuntimeInfo(); + src.fileName = this.fileName; + src.lineNumber = this.lineNumber; + src.xacmlObject = xacmlObject; + src.eleType = type; + return src; + } + + public boolean isIndirectLocateable() { + return indirectLocateable; + } + + public String getLocationMsgForError() { + return " near line " + ( lineNumber == -1 ? "unkown" : lineNumber ) + + " from file " + ( fileName == null ? "unkown" : fileName ); + //+ ( eleType == null ? "" : " (" + eleType.getName() + ")"); + } + + public String getLocationMsgShort() { + return " (line " + ( lineNumber == -1 ? "unkown" : lineNumber ) + + "@" + ( fileName == null ? "unkown" : fileName ) + ")"; + //+ ( eleType == null ? "" : " (" + eleType.getName() + ")"); + // + (this.calledFrom != null ? " from " + calledFrom.getClass().getSimpleName() : "") + } + + public String getLocationMsgRuntime() { + if ( calledFrom != null && calledFrom.xacmlObject != null ) { + return getLocationMsgShort() + + " called from " + calledFrom.xacmlObject.getClass().getSimpleName() + + ( calledFrom instanceof Locatable && ((Locatable) calledFrom).getRuntimeInfo() != null ? + ((Locatable) calledFrom).getRuntimeInfo().getLocationMsgShort() : "" ) ; + } else { + return getLocationMsgShort(); + } + } + + public String getElementDescr() { + return xacmlObject.getClass().getSimpleName() + getLocationMsgForError(); + } + + public void setCalledFrom(RuntimeInfo calledFrom) { + if ( indirectLocateable ) { + if ( calledFrom != this.calledFrom ) { + logger.warn("For indirect locateable RuntimeInfo objects, calledFrom provided to this" + + "function should be the same als already stored"); + } + } else if ( this.calledFrom != null ) { + logger.warn("Overwriting calledFrom object: " + this.calledFrom.getElementDescr() + " overwritten with " + calledFrom.getElementDescr()); + if (logger.isDebugEnabled()) { + try { + throw new RuntimeException("getStackTrace for Overwriting calledFrom object"); + } catch(RuntimeException e) { + e.printStackTrace(); + } + } + } + this.calledFrom = calledFrom; + } + + public void unsetCalledFrom(RuntimeInfo calledFrom) { + if ( this.calledFrom == null ) { + logger.warn("calledFrom is already unset!"); + } else if ( this.calledFrom != calledFrom) { + logger.warn("Unsetting different object (" + calledFrom.getClass().getSimpleName() + + ") than was set (" + this.calledFrom.getClass().getSimpleName() + ")!"); + } + this.calledFrom = null; + } + + public RuntimeInfo getCalledFrom() { + return calledFrom; + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinder.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinder.java new file mode 100644 index 0000000..afcd360 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinder.java @@ -0,0 +1,300 @@ + +/* + * @(#)AttributeFinder.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.BagAttribute; + +import com.sun.xacml.cond.EvaluationResult; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; + + +/** + * This class is used by the PDP to find attribute values that weren't + * originally supplied in the request. It can be called with the data supplied + * in AttributeDesignators or AttributeSelectors. + * Because the modules in this finder may themselves need attribute data + * to search for attribute data, it's possible that the modules will look + * for values in the EvaluationCtx, which may in turn result + * in the invocation of this finder again, so module writers need to be + * careful about how they build their modules. + *

    + * Note that unlike the PolicyFinder, this class doesn't always need to + * use every module it has to find a value. The ordering is maintained, + * however, so it will always start with the first module, and proceed + * in order until it finds a value or runs out of modules. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public class AttributeFinder implements Cloneable +{ + + // the list of all modules + private List allModules; + + // + private List designatorModules; + + // + private List selectorModules; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(AttributeFinder.class.getName()); + + /** + * Default constructor. + */ + public AttributeFinder() { + this.allModules = new ArrayList(); + this.designatorModules = new ArrayList(); + this.selectorModules = new ArrayList(); + } + + + /** + * The clone method. + * FIXME: this does no deep copy on the Lists. + * + * @return a copy of this object. + */ + public Object clone() { + try { + AttributeFinder clone = (AttributeFinder)super.clone(); + clone.allModules = new ArrayList(this.allModules); + clone.designatorModules = new ArrayList(this.designatorModules); + clone.selectorModules = new ArrayList(this.selectorModules); + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone AttributeFinder"); + } + } + + /** + * copy constructor + * @param attrFinder + */ + protected AttributeFinder(AttributeFinder attrFinder) { + this.allModules = attrFinder.allModules; + this.designatorModules = attrFinder.designatorModules; + this.selectorModules = attrFinder.selectorModules; + } + + /** + * Returns the ordered List of + * AttributeFinderModules used by this class to find + * attribute values. + * + * @return a List of AttributeFinderModules + */ + public List getModules() { + return new ArrayList(this.allModules); + } + + /** + * Sets the ordered List of + * AttributeFinderModules used by this class to find + * attribute values. The ordering will be maintained. + * + * @param modules a List of + * AttributeFinderModules + */ + public void setModules(List modules) { + Iterator it = modules.iterator(); + + this.allModules = new ArrayList(modules); + this.designatorModules = new ArrayList(); + this.selectorModules = new ArrayList(); + + while (it.hasNext()) { + AttributeFinderModule module = it.next(); + + if (module.isDesignatorSupported()) { + this.designatorModules.add(module); + } + if (module.isSelectorSupported()) { + this.selectorModules.add(module); + } + } + } + + /** + * Sets only the designatorModules + * @param modules + */ + public void setDesignatorModules(List modules) { + + for ( AttributeFinderModule mod : modules) { + if ( mod.isDesignatorSupported() ) { + logger.warn(mod + " does not support designator selection!"); + } + } + + this.designatorModules = modules; + } + + /** + * Tries to find attribute values based on the given designator data. + * The result, if successful, will always contain a + * BagAttribute, even if only one value was found. If no + * values were found, but no other error occurred, an empty bag is + * returned. + * + * @param category the category of the attribute + * @param attributeType the datatype of the attributes to find or null + * @param attributeId the identifier of the attributes to find or null + * @param issuer the issuer of the attributes, or null if unspecified + * @param context the representation of the request data + * + * @return the result of attribute retrieval, which will be a bag of + * attributes or an error + */ + public EvaluationResult findAttribute(URI category, URI attributeType, + URI attributeId, URI issuer, + EvaluationCtx context) { + Iterator it = this.designatorModules.iterator(); + + // go through each module in order + while (it.hasNext()) { + AttributeFinderModule module = it.next(); + + // see if the module can find an attribute value + EvaluationResult result = + module.findAttribute(category, attributeType, attributeId, + issuer, context); + + // if there was an error, we stop right away + if (result.indeterminate()) { + if (logger.isInfoEnabled()) { + logger.info("Error while trying to resolve values: " + + result.getStatus().getMessage()); + } + + return result; + } + + // if the result wasn't empty, then return the result + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + if (! bag.isEmpty()) { + return result; + } + } + + // if we got here then there were no errors but there were also no + // matches, so we have to return an empty bag + if (logger.isDebugEnabled()) { + logger.debug("Failed to resolve any values for " + + attributeId.toString()); + + } + + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + } + + /** + * Tries to find attribute values based on the given selector data. + * The result, if successful, must always contain a + * BagAttribute, even if only one value was found. If no + * values were found, but no other error occurred, an empty bag is + * returned. + * + * @param contextPath the XPath expression to search against + * @param namespaceNode the DOM node defining namespace mappings to use, + * or null if mappings come from the context root + * @param attributeType the datatype of the attributes to find + * @param context the representation of the request data + * @param xpathVersion the XPath version to use + * + * @return the result of attribute retrieval, which will be a bag of + * attributes or an error + */ + public EvaluationResult findAttribute(String contextPath, + Node namespaceNode, + URI attributeType, + EvaluationCtx context, + String xpathVersion) { + Iterator it = this.selectorModules.iterator(); + + // go through each module in order + while (it.hasNext()) { + AttributeFinderModule module = it.next(); + + // see if the module can find an attribute value + EvaluationResult result = + module.findAttribute(contextPath, namespaceNode, attributeType, + context, xpathVersion); + + // if there was an error, we stop right away + if (result.indeterminate()) { + if (logger.isInfoEnabled()) { + logger.info("Error while trying to resolve values: " + + result.getStatus().getMessage()); + } + return result; + } + + // if the result wasn't empty, then return the result + BagAttribute bag = (BagAttribute)(result.getAttributeValue()); + if (! bag.isEmpty()) { + return result; + } + } + + // if we got here then there were no errors but there were also no + // matches, so we have to return an empty bag + if (logger.isInfoEnabled()) { + logger.info("Failed to resolve any values for " + contextPath); + } + + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinderModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinderModule.java new file mode 100644 index 0000000..4e3ab5b --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/AttributeFinderModule.java @@ -0,0 +1,201 @@ + +/* + * @(#)AttributeFinderModule.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.BagAttribute; + +import com.sun.xacml.cond.EvaluationResult; +import java.net.URI; + +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * This is the abstract class that all AttributeFinder modules + * extend. All methods have default values to represent that the given + * feature isn't supported by this module, so module writers needs only + * implement the methods for the features they're supporting. + * + * @since 1.0 + * @author Seth Proctor + * @author Ludwig Seitz + */ +public abstract class AttributeFinderModule +{ + + /** + * Returns this module's identifier. A module does not need to provide + * a unique identifier, but it is a good idea, especially in support of + * management software. Common identifiers would be the full package + * and class name (the default if this method isn't overridden), just the + * class name, or some other well-known string that identifies this class. + * + * @return this module's identifier + */ + public String getIdentifier() { + return getClass().getName(); + } + + /** + * Returns true if this module supports retrieving attributes based on the + * data provided in an AttributeDesignatorType. By default this method + * returns false. + * + * @return true if retrieval based on designator data is supported + */ + public boolean isDesignatorSupported() { + return false; + } + + /** + * Returns true if this module supports retrieving attributes based on the + * data provided in an AttributeSelectorType. By default this method + * returns false. + * + * @return true if retrieval based on selector data is supported + */ + public boolean isSelectorSupported() { + return false; + } + + /** + * Returns a Set of Integers that represent + * which AttributeDesignator types are supported (eg, Subject, Resource, + * etc.), or null meaning that no particular types are supported. A + * return value of null can mean that this module doesn't support + * designator retrieval, or that it supports designators of all types. + * If the set is non-null, it should contain the values specified in + * the AttributeDesignator *_TARGET fields. + * + * @return a Set of Integers, or null + */ + public Set getSupportedDesignatorTypes() { + return null; + } + + /** + * Returns a Set of URIs that represent the + * attributeIds handled by this module, or null if this module doesn't + * handle any specific attributeIds. A return value of null means that + * this module will try to resolve attributes of any id. + * + * @return a Set of URIs, or null + */ + public Set getSupportedIds() { + return null; + } + + /** + * This is an experimental method that asks the module to invalidate any + * cache values it may contain. This is not used by any of the core + * processing code, but it may be used by management software that wants + * to have some control over these modules. Since a module is free to + * decide how or if it caches values, and whether it is capable of + * updating values once in a cache, a module is free to intrepret this + * message in any way it sees fit (including igoring the message). It + * is preferable, however, for a module to make every effort to clear + * any dynamically cached values it contains. + *

    + * This method has been introduced to see what people think of this + * functionality, and how they would like to use it. It may be removed + * in future versions, or it may be changed to a more general + * message-passing system (if other useful messages are identified). + * + * @since 1.2 + */ + public void invalidateCache() { + //not defined yet, for future extensions + } + + /** + * Tries to find attribute values based on the given designator data. + * The result, if successful, must always contain a + * BagAttribute, even if only one value was found. If no + * values were found, but no other error occurred, an empty bag is + * returned. This method may need to invoke the context data to look + * for other attribute values, so a module writer must take care not + * to create a scenario that loops forever. + * + * @param category the category of the attribute + * @param attributeType the datatype of the attributes to find + * @param attributeId the identifier of the attributes to find + * @param issuer the issuer of the attributes, or null if unspecified + * @param context the representation of the request data + * + * @return the result of attribute retrieval, which will be a bag of + * attributes or an error + */ + public EvaluationResult findAttribute(URI category, URI attributeType, + URI attributeId, URI issuer, + EvaluationCtx context) { + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + } + + /** + * Tries to find attribute values based on the given selector data. + * The result, if successful, must always contain a + * BagAttribute, even if only one value was found. If no + * values were found, but no other error occurred, an empty bag is + * returned. This method may need to invoke the context data to look + * for other attribute values, so a module writer must take care not + * to create a scenario that loops forever. + * + * @param contextPath the XPath expression to search against + * @param namespaceNode the DOM node defining namespace mappings to use, + * or null if mappings come from the context root + * @param attributeType the datatype of the attributes to find + * @param context the representation of the request data + * @param xpathVersion the XPath version to use + * + * @return the result of attribute retrieval, which will be a bag of + * attributes or an error + */ + public EvaluationResult findAttribute(String contextPath, + Node namespaceNode, + URI attributeType, + EvaluationCtx context, + String xpathVersion) { + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinder.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinder.java new file mode 100644 index 0000000..4d7c1c8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinder.java @@ -0,0 +1,314 @@ + +/* + * @(#)PolicyFinder.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.PDPConfig; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.PolicyReference; +import com.sun.xacml.VersionConstraints; + +import com.sun.xacml.ctx.Status; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.apache.log4j.Logger; + +/** + * This class is used by the PDP to find all policies used in evaluation. A + * PDP is given a pre-configured PolicyFinder on construction. + * The PolicyFinder provides the functionality both to find + * policies based on a request (ie, retrieve policies and match against the + * target) and based on an idReference (as can be included in a PolicySet). + *

    + * While this class is typically used by the PDP, it is intentionally + * designed to support stand-alone use, so it could be the base for a + * distributed service, or for some application that needs just this + * functionality. There is nothing in the PolicyFinder + * Note that it is an error to have more than one top-level policy (as + * explained in the OnlyOneApplicable combining algorithm), so any module + * that is added to this finder will be evaluated each time a policy is + * requested. This means that you should think carefully about how many + * modules you include, and how they can cache policy data. + * + * @since 1.0 + * @author Seth Proctor + */ +public class PolicyFinder +{ + + private PDPConfig config; + + // all modules in this finder + private Set allModules = new HashSet(); + + // all the request modules + private Set requestModules = new HashSet(); + + // all the reference modules + private Set referenceModules = new HashSet(); + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(PolicyFinder.class.getName()); + + /** + * Returns the unordered Set of + * PolicyFinderModules used by this class to find policies. + * + * @return a Set of PolicyFinderModules + */ + public Set getModules() { + return new HashSet(this.allModules); + } + + + /** + * Sets the unordered Set of PolicyFinderModules + * used by this class to find policies. + * + * @param modules a Set of PolicyFinderModules + */ + public void setModules(Set modules) { + Iterator it = modules.iterator(); + + this.allModules = new HashSet(modules); + this.requestModules = new HashSet(); + this.referenceModules = new HashSet(); + + while (it.hasNext()) { + storeModule( (PolicyFinderModule)(it.next())); + } + } + + /** + * private helper function, whichs stores modules to + * the correct internal store. + * @param module + */ + private void storeModule(PolicyFinderModule module) { + if (module.isRequestSupported()) { + this.requestModules.add(module); + } + if (module.isIdReferenceSupported()) { + this.referenceModules.add(module); + } + } + + /** + * adds a new PolicyFinderModule to the existing ones (at runtime) + * @param policyFinder + */ + public void addPolicyFinderModule(PolicyFinderModule policyFinder) { + this.allModules.add(policyFinder); + storeModule(policyFinder); + policyFinder.init(this); + } + + /** + * Initializes all modules in this finder. + */ + public void init(PDPConfig config) { + logger.debug("Initializing PolicyFinder"); + + this.config = config; + + Iterator it = this.allModules.iterator(); + + while (it.hasNext()) { + PolicyFinderModule module = it.next(); + module.init(this); + } + } + + + + /** + * Finds a policy based on a request's context. This may involve using + * the request data as indexing data to lookup a policy. This will always + * do a Target match to make sure that the given policy applies. If more + * than one applicable policy is found, this will return an error. + * + * @param context the representation of the request data + * + * @return the result of trying to find an applicable policy + */ + public PolicyFinderResult findPolicy(EvaluationCtx context) { + PolicyFinderResult result = null; + Iterator it = this.requestModules.iterator(); + + // look through all of the modules + while (it.hasNext()) { + PolicyFinderModule module = it.next(); + PolicyFinderResult newResult = module.findPolicy(context); + + // if there was an error, we stop right away + if (newResult.indeterminate()) { + if (logger.isInfoEnabled()) { + logger.info("An error occured while trying to find a " + + "single applicable policy for a request: " + + newResult.getStatus().getMessage()); + } + + return newResult; + } + + // if we found a policy... + if (! newResult.notApplicable()) { + // ...if we already had found a policy, this is an error... + if (result != null) { + logger.info("More than one top-level applicable policy " + + "for the request"); + + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + Status status = new Status(code, "too many applicable " + + "top-level policies"); + return new PolicyFinderResult(status); + } + + // ...otherwise we remember the result + result = newResult; + } + } + + // if we got here then we didn't have any errors, so the only + // question is whether or not we found anything + if (result != null) { + return result; + } + +// logger.info("No applicable policies were found for the request"); + return new PolicyFinderResult(); + } + + /** + * Finds a policy based on an id reference. This may involve using + * the reference as indexing data to lookup a policy. This will always + * do a Target match to make sure that the given policy applies. If more + * than one applicable policy is found, this will return an error. + * + * @param idReference the identifier used to resolve a policy + * @param type type of reference (policy or policySet) as identified by + * the fields in PolicyReference + * @param constraints any optional constraints on the version of the + * referenced policy + * @param parentMetaData the meta-data from the parent policy, which + * provides XACML version, factories, etc. + * + * @return the result of trying to find an applicable policy + * + * @throws IllegalArgumentException if type is invalid + */ + public PolicyFinderResult findPolicy(EvaluationCtx context, URI idReference, int type, + VersionConstraints constraints, + PolicyMetaData parentMetaData) + throws IllegalArgumentException + { + PolicyFinderResult result = null; + Iterator it = this.referenceModules.iterator(); + + if ((type != PolicyReference.POLICY_REFERENCE) && + (type != PolicyReference.POLICYSET_REFERENCE)) { + throw new IllegalArgumentException("Unknown reference type"); + } + // look through all of the modules + while (it.hasNext()) { + PolicyFinderModule module = it.next(); + PolicyFinderResult newResult = + module.findPolicy(context, idReference, type, constraints, + parentMetaData); + + // if there was an error, we stop right away + if (newResult.indeterminate()) { + if (logger.isInfoEnabled()) { + logger.info("An error occured while trying to find the " + + "referenced policy " + idReference.toString() + + ": " + newResult.getStatus().getMessage()); + } + return newResult; + } + + // if we found a policy... + if (! newResult.notApplicable()) { + // ...if we already had found a policy, this is an error... + if (result != null) { + if (logger.isInfoEnabled()) { + logger.info("More than one policy applies for the " + + "reference: " + idReference.toString()); + } + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + Status status = new Status(code, "too many applicable " + + "top-level policies"); + return new PolicyFinderResult(status); + } + + // ...otherwise we remember the result + result = newResult; + } + } + + // if we got here then we didn't have any errors, so the only + // question is whether or not we found anything + if (result != null) { + return result; + } + + if (logger.isInfoEnabled()) { + logger.info("No policies were resolved for the reference: " + + idReference.toString()); + } + return new PolicyFinderResult(); + } + + public PDPConfig getPDPConfiguration() { + return this.config; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderModule.java new file mode 100644 index 0000000..4952f96 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderModule.java @@ -0,0 +1,169 @@ + +/* + * @(#)PolicyFinderModule.java + * + * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.PolicyMetaData; +import com.sun.xacml.VersionConstraints; + +import java.net.URI; + + +/** + * This is the abstract class that all PolicyFinder modules + * extend. All methods have default values to represent that the given + * feature isn't supported by this module, so module writers needs only + * implement the methods for the features they're supporting. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class PolicyFinderModule +{ + + /** + * Returns this module's identifier. A module does not need to provide + * a unique identifier, but it is a good idea, especially in support of + * management software. Common identifiers would be the full package + * and class name (the default if this method isn't overridden), just the + * class name, or some other well-known string that identifies this class. + * + * @return this module's identifier + */ + public String getIdentifier() { + return getClass().getName(); + } + + /** + * Returns true if the module supports finding policies based on a + * request (ie, target matching). By default this method returns false. + * + * @return true if request retrieval is supported + */ + public boolean isRequestSupported() { + return false; + } + + /** + * Returns true if the module supports finding policies based on an + * id reference (in a PolicySet). By default this method returns false. + * + * @return true if idReference retrieval is supported + */ + public boolean isIdReferenceSupported() { + return false; + } + + /** + * Initializes this module for use by the given finder. Typically this + * is called when a PDP is initialized with a + * PDPConfig containing the given PolicyFinder. + * Because PolicyFinderModules usually need to parse + * policies, and this requires knowing their PolicyFinder, + * parsing is usually done at or after this point in the lifetime + * of this module. This might also be a good time to reset any internal + * caches or temporary data. Note that this method may be called more + * than once in the lifetime of a module. + * + * @param finder the PolicyFinder using this module + */ + public abstract void init(PolicyFinder finder); + + /** + * This is an experimental method that asks the module to invalidate any + * cache values it may contain. This is not used by any of the core + * processing code, but it may be used by management software that wants + * to have some control over these modules. Since a module is free to + * decide how or if it caches values, and whether it is capable of + * updating values once in a cache, a module is free to intrepret this + * message in any way it sees fit (including igoring the message). It + * is preferable, however, for a module to make every effort to clear + * any dynamically cached values it contains. + *

    + * This method has been introduced to see what people think of this + * functionality, and how they would like to use it. It may be removed + * in future versions, or it may be changed to a more general + * message-passing system (if other useful messages are identified). + * + * @since 1.2 + */ + public void invalidateCache() { + //not defined yet, for future extensions + } + + /** + * Tries to find one and only one matching policy given the request + * represented by the context data. If more than one policy is found, + * this is an error and must be reported as such. If no policies are + * found, then an empty result must be returned. By default this + * method returns an empty result. This method should never return null. + * + * @param context the representation of the request + * + * @return the result of looking for a matching policy + */ + public PolicyFinderResult findPolicy(EvaluationCtx context) { + return new PolicyFinderResult(); + } + + /** + * Tries to find one and only one matching policy given the idReference + * If more than one policy is found, this is an error and must be reported + * as such. If no policies are found, then an empty result must be + * returned. By default this method returns an empty result. This method + * should never return null. + * + * @param idReference an identifier specifying some policy + * @param type type of reference (policy or policySet) as identified by + * the fields in PolicyReference + * @param constraints any optional constraints on the version of the + * referenced policy (this will never be null, but + * it may impose no constraints, and in fact will + * never impose constraints when used from a pre-2.0 + * XACML policy) + * @param parentMetaData the meta-data from the parent policy, which + * provides XACML version, factories, etc. + * + * @return the result of looking for a matching policy + */ + public PolicyFinderResult findPolicy(EvaluationCtx context, URI idReference, int type, + VersionConstraints constraints, + PolicyMetaData parentMetaData) { + return new PolicyFinderResult(); + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderResult.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderResult.java new file mode 100644 index 0000000..dcc9698 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/PolicyFinderResult.java @@ -0,0 +1,130 @@ + +/* + * @(#)PolicyFinderResult.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.AbstractPolicy; + +import com.sun.xacml.ctx.Status; + + +/** + * This is used as the return value for the findPolicy() methods in the + * PolicyFinder. It communicates either a found policy that + * applied to the request (eg, the target matches), an Indeterminate state, + * or no applicable policies. + *

    + * The OnlyOneApplicable combining logic is used in looking for a policy, + * so the result from calling findPolicy can never be more than one policy. + * + * @since 1.0 + * @author Seth Proctor + */ +public class PolicyFinderResult +{ + + // the single policy being returned + private AbstractPolicy policy; + + // status that represents an error occurred + private Status status; + + /** + * Creates a result saying that no applicable policies were found. + */ + public PolicyFinderResult() { + this.policy = null; + this.status = null; + } + + /** + * Creates a result containing a single applicable policy. + * + * @param policy the applicable policy + */ + public PolicyFinderResult(AbstractPolicy policy) { + this.policy = policy; + this.status = null; + } + + /** + * Create a result of Indeterminate, including Status data. + * + * @param status the error information + */ + public PolicyFinderResult(Status status) { + this.policy = null; + this.status = status; + } + + /** + * Returns true if the result was NotApplicable. + * + * @return true if the result was NotApplicable + */ + public boolean notApplicable() { + return ((this.policy == null) && (this.status == null)); + } + + /** + * Returns true if the result was Indeterminate. + * + * @return true if there was an error + */ + public boolean indeterminate() { + return (this.status != null); + } + + /** + * Returns the found policy, or null if there was an error or no policy + * was found. + * + * @return the applicable policy or null + */ + public AbstractPolicy getPolicy() { + return this.policy; + } + + /** + * Returns the status if there was an error, or null if no error occurred. + * + * @return the error status data or null + */ + public Status getStatus() { + return this.status; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RequiredAttributesModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RequiredAttributesModule.java new file mode 100644 index 0000000..547e9f8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RequiredAttributesModule.java @@ -0,0 +1,13 @@ +package com.sun.xacml.finder; + +import java.util.Set; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.ctx.Attribute; + +public abstract class RequiredAttributesModule { + + public abstract Set resolveRequiredAttributes(EvaluationCtx context, AttributeDesignator attrDesignator); + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinder.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinder.java new file mode 100644 index 0000000..7243d1a --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinder.java @@ -0,0 +1,301 @@ + +/* + * @(#)ResourceFinder.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + + +/** + * This class is used by the PDP to handle resource scopes other than + * Immediate. In the case of a scope of Children, Descendants, + * XPath-expression or EntireHierarchy the PDP needs a list of Resource Ids + * to evaluate, each of which will get its own Result. Like the PolicyFinder, + * this is not tied in any way to the rest of the PDP code, and could be + * provided as a stand-alone resource. + *

    + * This class basically is a coordinator that asks each module in turn + * if it can handle the given identifier. Evaluation proceeds in order through + * the given modules, and once a module returns a non-empty response (whether + * or not it contains any errors or only errors), the evaluation is + * finished and the result is returned. One of the issues here is ordering, + * since a given resource may look to several modules like something that + * they can handle. So, you must be careful when assigning to ordering of + * the modules in this finder. + *

    + * + * @since 1.0 + * @author Seth Proctor + */ +public class ResourceFinder +{ + + /** + * the list of all modules + */ + private List allModules; + + /** + * the list of child modules + */ + private List childModules; + + /** + * the list of descendant modules + */ + private List descendantModules; + + /** + * the list of xpath modules + */ + private List xpathModules; + + /** + * the list of hierarchy modules + */ + private List hierarchyModules; + + // the logger we'll use for all messages + private static final Logger logger = + Logger.getLogger(ResourceFinder.class.getName()); + + /** + * Default constructor. + */ + public ResourceFinder() { + this.allModules = new ArrayList(); + this.childModules = new ArrayList(); + this.descendantModules = new ArrayList(); + this.xpathModules = new ArrayList(); + this.hierarchyModules = new ArrayList(); + } + + /** + * Returns the ordered List of + * ResourceFinderModules used by this class to find resources. + * + * @return a List of ResourceFinderModules + */ + public List getModules() { + return new ArrayList(this.allModules); + } + + /** + * Sets the ordered List of ResourceFinderModules + * used by this class to find resources. The ordering will be maintained. + * + * @param modules a code>List of ResourceFinderModules + */ + public void setModules(List modules) { + Iterator it = modules.iterator(); + + this.allModules = new ArrayList(modules); + this.childModules = new ArrayList(); + this.descendantModules = new ArrayList(); + + while (it.hasNext()) { + ResourceFinderModule module = it.next(); + + if (module.isChildSupported()) { + this.childModules.add(module); + } + if (module.isDescendantSupported()) { + this.descendantModules.add(module); + } + if (module.isXPathSupported()) { + this.xpathModules.add(module); + } + if (module.isHierarchySupported()) { + this.hierarchyModules.add(module); + } + } + } + + /** + * Finds Resource Ids using the Children scope, and returns all resolved + * identifiers as well as any errors that occurred. If no modules can + * handle the given Resource Id, then an empty result is returned. + * + * @param parentResourceId the root of the resources + * @param context the representation of the request data + * + * @return the result of looking for child resources + */ + public ResourceFinderResult findChildResources(AttributeValue + parentResourceId, + EvaluationCtx context) { + Iterator it = this.childModules.iterator(); + + while (it.hasNext()) { + ResourceFinderModule module = it.next(); + + // ask the module to find the resources + ResourceFinderResult result = + module.findChildResources(parentResourceId, context); + + // if we found something, then always return that result + if (! result.isEmpty()) { + return result; + } + } + + // no modules applied, so we return an empty result + if (logger.isInfoEnabled()) { + logger.info("No ResourceFinderModule existed to handle the " + + "children of " + parentResourceId.encode()); + } + + return new ResourceFinderResult(); + } + + /** + * Finds Resource Ids using the Descendants scope, and returns all resolved + * identifiers as well as any errors that occurred. If no modules can + * handle the given Resource Id, then an empty result is returned. + * + * @param parentResourceId the root of the resources + * @param context the representation of the request data + * + * @return the result of looking for descendant resources + */ + public ResourceFinderResult findDescendantResources(AttributeValue + parentResourceId, + EvaluationCtx + context) { + Iterator it = this.descendantModules.iterator(); + + while (it.hasNext()) { + ResourceFinderModule module = it.next(); + + // ask the module to find the resources + ResourceFinderResult result = + module.findDescendantResources(parentResourceId, context); + + // if we found something, then always return that result + if (! result.isEmpty()) { + return result; + } + } + + // no modules applied, so we return an empty result + if (logger.isInfoEnabled()) { + logger.info("No ResourceFinderModule existed to handle the " + + "descendants of " + parentResourceId.encode()); + } + return new ResourceFinderResult(); + } + + /** + * Finds Resource Ids using an XPath expression on the Content with the + * "urn:oasis:names:tc:xacml:3.0:attribute-category:resource" category + * and returns all matching nodes as identifiers as well as any errors + * that occurred. If no modules can handle the given Resource Id, then + * an empty result is returned. + * + * @param xpathResourceId the root of the resources + * @param context the representation of the request data + * + * @return the result of looking for descendant resources + */ + public ResourceFinderResult findXPathResources( + AttributeValue xpathResourceId, EvaluationCtx context) { + Iterator it = this.xpathModules.iterator(); + + while (it.hasNext()) { + ResourceFinderModule module = it.next(); + + // ask the module to find the resources + ResourceFinderResult result = + module.findXPathResources(xpathResourceId, context); + + // if we found something, then always return that result + if (! result.isEmpty()) { + return result; + } + } + + // no modules returned results, so we return an empty result + if (logger.isInfoEnabled()) { + logger.info("No ResourceFinderModule returned results for the " + + "xpath " + xpathResourceId.encode()); + } + return new ResourceFinderResult(); + } + + /** + * Finds Resource Ids using the EntireHierarchy scope and returns all + * matching nodes as identifiers as well as any errors that occurred. + * If no modules can handle the given Resource Id, then an empty result + * is returned. + * + * @param parentResourceId the root of the resources + * @param context the representation of the request data + * + * @return the result of looking for descendant resources + */ + public ResourceFinderResult findHierarchyResources( + AttributeValue parentResourceId, EvaluationCtx context) { + Iterator it = this.hierarchyModules.iterator(); + + while (it.hasNext()) { + ResourceFinderModule module = it.next(); + + // ask the module to find the resources + ResourceFinderResult result = + module.findHierarchicyResources(parentResourceId, context); + + // if we found something, then always return that result + if (! result.isEmpty()) { + return result; + } + } + + // no modules applied, so we return an empty result + if (logger.isInfoEnabled()) { + logger.info("No ResourceFinderModule existed to handle the " + + "hierarchy of " + parentResourceId.encode()); + } + return new ResourceFinderResult(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderModule.java new file mode 100644 index 0000000..4095434 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderModule.java @@ -0,0 +1,200 @@ + +/* + * @(#)ResourceFinderModule.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; + + +/** + * This is the abstract class that all ResourceFinder modules + * extend. All methods have default values to represent that the given + * feature isn't supported by this module, so module writers needs only + * implement the methods for the features they're supporting. + * + * @since 1.0 + * @author Seth Proctor + */ +public abstract class ResourceFinderModule +{ + + /** + * Returns this module's identifier. A module does not need to provide + * a unique identifier, but it is a good idea, especially in support of + * management software. Common identifiers would be the full package + * and class name (the default if this method isn't overridden), just the + * class name, or some other well-known string that identifies this class. + * + * @return this module's identifier + */ + public String getIdentifier() { + return getClass().getName(); + } + + /** + * Returns true if this module supports finding resources with the + * "Children" scope. By default this method returns false. + * + * @return true if the module supports the Children scope + */ + public boolean isChildSupported() { + return false; + } + + /** + * Returns true if this module supports finding resources with the + * "Descendants" scope. By default this method returns false. + * + * @return true if the module supports the Descendants scope + */ + public boolean isDescendantSupported() { + return false; + } + + /** + * Returns true if this module supports finding resources with the + * "XPath-expression" scope. By default this method returns false. + * + * @return true if the module supports the XPath-expression scope + */ + public boolean isXPathSupported() { + return false; + } + + /** + * Returns true if this module supports finding resources with the + * "EntireHierarchy" scope. By default this method returns false. + * + * @return true if the module supports the EntireHierarchy scope + */ + public boolean isHierarchySupported() { + return false; + } + + /** + * This is an experimental method that asks the module to invalidate any + * cache values it may contain. This is not used by any of the core + * processing code, but it may be used by management software that wants + * to have some control over these modules. Since a module is free to + * decide how or if it caches values, and whether it is capable of + * updating values once in a cache, a module is free to intrepret this + * message in any way it sees fit (including igoring the message). It + * is preferable, however, for a module to make every effort to clear + * any dynamically cached values it contains. + *

    + * This method has been introduced to see what people think of this + * functionality, and how they would like to use it. It may be removed + * in future versions, or it may be changed to a more general + * message-passing system (if other useful messages are identified). + * + * @since 1.2 + */ + public void invalidateCache() { + //not defined yet, for future extensions + } + + /** + * Tries to find the child Resource Ids associated with the parent. If + * this module cannot handle the given identifier, then an empty result is + * returned, otherwise the result will always contain at least the + * parent Resource Id, either as a successfully resolved Resource Id or an + * error case, but never both. + * + * @param parentResourceId the parent resource identifier + * @param context the representation of the request data + * + * @return the result of finding child resources + */ + public ResourceFinderResult findChildResources(AttributeValue + parentResourceId, + EvaluationCtx context) { + return new ResourceFinderResult(); + } + + /** + * Tries to find the descendant Resource Ids associated with the parent. If + * this module cannot handle the given identifier, then an empty result is + * returned, otherwise the result will always contain at least the + * parent Resource Id, either as a successfuly resolved Resource Id or an + * error case, but never both. + * + * @param parentResourceId the parent resource identifier + * @param context the representation of the request data + * + * @return the result of finding descendant resources + */ + public ResourceFinderResult findDescendantResources(AttributeValue + parentResourceId, + EvaluationCtx + context) { + return new ResourceFinderResult(); + } + + /** + * Tries to find the Resource Ids identified by an XPath. If + * this module cannot handle the given identifier, then an empty result is + * returned, otherwise the result will contain the result of applying this + * XPath to the Content with id="Resource". This may be an empty result. + * + * @param xpathResourceId the parent resource identifier + * @param context the representation of the request data + * + * @return the result of finding descendant resources + */ + public ResourceFinderResult findXPathResources( + AttributeValue xpathResourceId, EvaluationCtx context) { + return new ResourceFinderResult(); + } + + /** + * Tries to find the hierarchy of Resource Ids associated with the parent. + * If this module cannot handle the given identifier, then an empty result + * is returned, otherwise the result will always contain at least the + * parent Resource Id, either as a successfuly resolved Resource Id or an + * error case, but never both. + * + * @param parentResourceId the parent resource identifier + * @param context the representation of the request data + * + * @return the result of finding descendant resources + */ + public ResourceFinderResult findHierarchicyResources( + AttributeValue parentResourceId, EvaluationCtx context) { + return new ResourceFinderResult(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderResult.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderResult.java new file mode 100644 index 0000000..43a4f82 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/ResourceFinderResult.java @@ -0,0 +1,159 @@ + +/* + * @(#)ResourceFinderResult.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.ctx.Status; + + +/** + * This is used to return Resource Ids from the ResourceFinder. Unlike the + * PolicyFinder, this never returns an empty set, since it will always + * contain at least the original parent resource. This class will provide + * two sets of identifiers: those that were successfully resolved and those + * that had an error. + * + * @since 1.0 + * @author Seth Proctor + */ +public class ResourceFinderResult +{ + + // the set of resource identifiers + private Set resources; + + // the map of failed identifiers to their failure status data + private Map failures; + + // a flag specifying whether or not result contains resource listings + private boolean empty; + + /** + * Creates an empty result. + */ + public ResourceFinderResult() { + this.resources = Collections.unmodifiableSet(new HashSet()); + this.failures = Collections.unmodifiableMap(new HashMap()); + this.empty = true; + } + + /** + * Creates a result containing the given Set of resource + * identifiers. The Setmust not be null. The new + * ResourceFinderResult represents a resource retrieval that + * encountered no errors. + * + * @param resources a non-null Set of + * AttributeValues + */ + public ResourceFinderResult(Set resources) { + this(resources, new HashMap()); + } + + /** + * Creates a result containing only Resource Ids that caused errors. The + * Map must not be null. The keys in the Map + * are AttributeValues identifying the resources that could + * not be resolved, and they map to a Status object + * explaining the error. The new ResourceFinderResult + * represents a resource retrieval that did not succeed in finding any + * resource identifiers. + * + * @param failures a non-null Map mapping failed + * AttributeValue identifiers to their + * Status + */ + public ResourceFinderResult(HashMap failures) { + this(new HashSet(), failures); + } + + /** + * Creates a new result containing both successfully resolved Resource Ids + * and resources that caused errors. + * + * @param resources a non-null Set of + * AttributeValues + * @param failures a non-null Map mapping failed + * AttributeValue identifiers to their + * Status + */ + public ResourceFinderResult(Set resources, Map failures) { + this.resources = Collections.unmodifiableSet(new HashSet(resources)); + this.failures = Collections.unmodifiableMap(new HashMap(failures)); + this.empty = false; + } + + /** + * Returns whether or not this result contains any Resource Id listings. + * This will return false if either the set of successfully resolved + * resource identifiers or the map of failed resources is not empty. + * + * @return false if this result names any resources, otherwise true + */ + public boolean isEmpty() { + return this.empty; + } + + /** + * Returns the Set of successfully resolved Resource Id + * AttributeValues, which will be empty if no resources + * were successfully resolved. + * + * @return a Set of AttributeValues + */ + public Set getResources() { + return this.resources; + } + + /** + * Returns the Map of Resource Ids that caused an error on + * resolution, which will be empty if no resources caused any error. + * + * @return a Map of AttributeValues to + * Status + */ + public Map getFailures() { + return this.failures; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinder.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinder.java new file mode 100644 index 0000000..3b47a23 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinder.java @@ -0,0 +1,136 @@ + +/* + * @(#)RevocationFinder.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This class is used by the PDP to find revocations of policies + * + * @since 3.0 + * @author Ludwig Seitz + */ +public class RevocationFinder implements Cloneable { + + // the list of all modules + private List allModules = null; + + /** + * Default constructor. + */ + public RevocationFinder() { + this.allModules = new ArrayList(); + } + + /** + * The clone method. + * + * @return a copy of this object + */ + public Object clone() { + try { + RevocationFinder clone = (RevocationFinder)super.clone(); + clone.allModules = new ArrayList(this.allModules); + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone RevocationFinder"); + } + } + + /** + * Returns the ordered List of modules used by this class + * to find policy revocations + * + * @return the list of modules used by this class + */ + public List getModules() { + return new ArrayList(this.allModules); + } + + /** + * Sets the ordered List of modules used by this class + * to find attribute values. The ordering will be maintained. + * + * @param modules the modules this class will use + */ + public void setModules(List modules) { + this.allModules = new ArrayList(modules); + } + + /** + * Checks whether a policy supports the revocation of a candidate policy. + * + * @param policy The policy that may support a revocation + * @param candidate The id of the policy or policy set that is candidate + * for revocation. + * @param context the context in which this policy may support revocations + * + * @return true if this policy supports a the revocation of the candidate, + * false otherwise. + */ + public boolean supportsRevocation(AbstractPolicy policy, URI candidate, + EvaluationCtx context) { + if (this.allModules != null) { + Iterator it = this.allModules.iterator(); + + // go through each module in order + while (it.hasNext()) { + RevocationFinderModule module = it.next(); + + // see if the module can find a revocation + boolean result = module.supportsRevocation(policy, + candidate, + context); + + if (result == true) { + // we found a revocation + return true; + } + } + } + // we found no revocation or there is no revocation finder module + return false; + + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinderModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinderModule.java new file mode 100644 index 0000000..c8f116d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/RevocationFinderModule.java @@ -0,0 +1,86 @@ + +/* + * @(#)RevocationFinderModule.java + * + * Copyright 2005-2006 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder; + +import java.net.URI; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; + +/** + * This is the abstract class that all RevocationFinder modules + * extend. All methods have default values to represent that the given + * feature isn't supported by this module, so module writers needs only + * implement the methods for the features they're supporting. + * + * @since 3.0 + * @author Ludwig Seitz + */ +public abstract class RevocationFinderModule +{ + + /** + * Returns this module's identifier. A module does not need to provide + * a unique identifier, but it is a good idea, especially in support of + * management software. Common identifiers would be the full package + * and class name (the default if this method isn't overridden), just the + * class name, or some other well-known string that identifies this class. + * + * @return this module's identifier + */ + public String getIdentifier() { + return getClass().getName(); + } + + /** + * Checks whether a policy supports the revocation of a candidate policy. + * + * @param policy The policy that may support a revocation + * @param candidate The id of the policy or policy set that is candidate + * for revocation. + * @param context the context in which this policy may support revocations + * + * @return true if this policy supports a the revocation of the candidate, + * false otherwise. + */ + public boolean supportsRevocation(AbstractPolicy policy, URI candidate, + EvaluationCtx context) { + return false; + } +} + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentEnvModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentEnvModule.java new file mode 100644 index 0000000..bff421d --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentEnvModule.java @@ -0,0 +1,208 @@ + +/* + * @(#)CurrentEnvModule.java + * + * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder.impl; + +import com.sun.xacml.ConfigurationStore; +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; + +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; +import com.sun.xacml.attr.DateAttribute; +import com.sun.xacml.attr.DateTimeAttribute; +import com.sun.xacml.attr.TimeAttribute; + +import com.sun.xacml.cond.EvaluationResult; + +import com.sun.xacml.finder.AttributeFinderModule; + +//import foo.xacml.finder.IRecordEvaluationContext; + +import java.net.URI; + +import java.util.HashSet; +import java.util.Set; + + +/** + * Supports the current date, time, and dateTime values. The XACML + * specification states that these three values must always be available to + * a PDP. They may be included in the request, but if they're not, a PDP + * must be able to recognize the attribute and generate a correct value. + *

    + * The XACML specification doesn't require that values be cached (ie, + * remain consistent within an evaluation), but does allow it. Any caching, + * as well as details of which time to use (time at the PEP, PDP, etc.) is + * taken care of by the EvaluationCtx which is used to supply + * the current values. + * + * @since 1.0 + * @author Seth Proctor + */ +public class CurrentEnvModule extends AttributeFinderModule +{ + + /** + * Standard environment variable that represents the current time + */ + public static final String ENVIRONMENT_CURRENT_TIME = + "urn:oasis:names:tc:xacml:1.0:environment:current-time"; + + /** + * Standard environment variable that represents the current date + */ + public static final String ENVIRONMENT_CURRENT_DATE = + "urn:oasis:names:tc:xacml:1.0:environment:current-date"; + + /** + * Standard environment variable that represents the current date and time + */ + public static final String ENVIRONMENT_CURRENT_DATETIME = + "urn:oasis:names:tc:xacml:1.0:environment:current-dateTime"; + + /** + * Returns true always because this module supports designators. + * + * @return true always + */ + public boolean isDesignatorSupported() { + return true; + } + + /** + * Used to get the current time, date, or dateTime. If one of those + * values isn't being asked for, or if the types are wrong, then an + * empty bag is returned. + * + * @param category the category of the attribute + * @param attributeType the datatype of the attributes to find, which + * must be time, date, or dateTime for this module + * to resolve a value + * @param attributeId the identifier of the attributes to find, which + * must be one of the three ENVIRONMENT_* fields for + * this module to resolve a value + * @param issuer the issuer of the attributes, or null if unspecified + * @param context the representation of the request data + * + * @return the result of attribute retrieval, which will be a bag with + * a single attribute, an empty bag, or an error + */ + public EvaluationResult findAttribute(URI category, URI attributeType, + URI attributeId, URI issuer, + EvaluationCtx context) { + // we only know about environment attributes + if (!category.equals(Constants.ENVIRONMENT_CAT)) { + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + + } + + // figure out which attribute we're looking for + String attrName = attributeId.toString(); + + if (attrName.equals(ENVIRONMENT_CURRENT_TIME)) { + return handleTime(attributeType, issuer, context); + } else if (attrName.equals(ENVIRONMENT_CURRENT_DATE)) { + return handleDate(attributeType, issuer, context); + } else if (attrName.equals(ENVIRONMENT_CURRENT_DATETIME)) { + return handleDateTime(attributeType, issuer, context); + } + + // if we got here, then it's an attribute that we don't know + return new EvaluationResult(BagAttribute. + createEmptyBag(attributeType)); + } + + /** + * Handles requests for the current Time. + */ + private EvaluationResult handleTime(URI type, URI issuer, + EvaluationCtx context) { + // make sure they're asking for a time attribute + if (! type.toString().equals(TimeAttribute.identifier)) { + return new EvaluationResult(BagAttribute. + createEmptyBag(type)); + } + // get the value from the context + return makeBag(context.getCurrentTime()); + } + + /** + * Handles requests for the current Date. + */ + private EvaluationResult handleDate(URI type, URI issuer, + EvaluationCtx context) { + // make sure they're asking for a date attribute + if (! type.toString().equals(DateAttribute.identifier)) { + return new EvaluationResult(BagAttribute. + createEmptyBag(type)); + } + // get the value from the context + return makeBag(context.getCurrentDate()); + } + + /** + * Handles requests for the current DateTime. + */ + private EvaluationResult handleDateTime(URI type, URI issuer, + EvaluationCtx context) { + // make sure they're asking for a dateTime attribute + if (! type.toString().equals(DateTimeAttribute.identifier)) { + return new EvaluationResult(BagAttribute. + createEmptyBag(type)); + } + // get the value from the context + return makeBag(context.getCurrentDateTime()); + } + + /** + * Private helper that makes a bag containing only the given attribute. + */ + private EvaluationResult makeBag(AttributeValue attribute) { + Set set = new HashSet(); + set.add(attribute); + + BagAttribute bag = new BagAttribute(attribute.getType(), set); + + return new EvaluationResult(bag); + } + + public void setConfigurationStore(ConfigurationStore confStore) { + + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentRequiredAttributeModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentRequiredAttributeModule.java new file mode 100644 index 0000000..5ce4b35 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/CurrentRequiredAttributeModule.java @@ -0,0 +1,44 @@ +package com.sun.xacml.finder.impl; + +import java.util.HashSet; +import java.util.Set; + +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.attr.StandardAttributeFactory; +import com.sun.xacml.ctx.Attribute; +import com.sun.xacml.finder.RequiredAttributesModule; + +/** + * + * Simple class / naiv implementation which does not do any prefetching + * and simply returns the currently required attribute + * + * + */ +public class CurrentRequiredAttributeModule extends RequiredAttributesModule { + + private static StandardAttributeFactory attrFactory = StandardAttributeFactory.getFactory(); + + @Override + public Set resolveRequiredAttributes(EvaluationCtx context, + AttributeDesignator attrDesignator) { + + Set attr = new HashSet(); + + try { + attr.add(new Attribute(attrDesignator.getId(), + attrDesignator.getIssuer() == null ? null : attrDesignator.getIssuer().toString(), + attrFactory.createValue(attrDesignator.getType(), null))); + } catch (UnknownIdentifierException e) { + e.printStackTrace(); + } catch (ParsingException e) { + e.printStackTrace(); + } + + return attr; + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/SelectorModule.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/SelectorModule.java new file mode 100644 index 0000000..b721589 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/SelectorModule.java @@ -0,0 +1,241 @@ + +/* + * @(#)SelectorModule.java + * + * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") + * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE + * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS + * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST + * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, + * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY + * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.finder.impl; + +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.ParsingException; +import com.sun.xacml.UnknownIdentifierException; + +import com.sun.xacml.attr.AttributeFactory; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.BagAttribute; + +import com.sun.xacml.cond.EvaluationResult; + +import com.sun.xacml.ctx.Status; + +import com.sun.xacml.finder.AttributeFinderModule; + +import java.net.URI; + +import java.util.ArrayList; + +import org.apache.xpath.XPathAPI; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * This module implements the basic behavior of the AttributeSelectorType, + * looking for attribute values in the physical request document using the + * given XPath expression. This is implemented as a separate module (instead + * of being implemented directly in AttributeSelector so that + * programmers can remove this functionality if they want (it's optional in + * the spec), so they can replace this code with more efficient, specific + * code as needed, and so they can easily swap in different XPath libraries. + *

    + * Note that if no matches are found, this module will return an empty bag + * (unless some error occurred). The AttributeSelector is still + * deciding what to return to the policy based on the MustBePresent + * attribute. + *

    + * This module uses the Xalan XPath implementation, and supports only version + * 1.0 of XPath. It is a fully functional, correct implementation of XACML's + * AttributeSelector functionality, but is not designed for environments + * that make significant use of XPath queries. Developers for any such + * environment should consider implementing their own module. + * + * @since 1.0 + * @author Seth Proctor + */ +public class SelectorModule extends AttributeFinderModule +{ + + /** + * Returns true since this module supports retrieving attributes based on + * the data provided in an AttributeSelectorType. + * + * @return true + */ + public boolean isSelectorSupported() { + return true; + } + + /** + * Private helper to create a new processing error status result + */ + private EvaluationResult createProcessingError(String msg) { + ArrayList code = new ArrayList(); + code.add(Status.STATUS_PROCESSING_ERROR); + return new EvaluationResult(new Status(code, msg)); + } + + /** + * Tries to find attribute values based on the given selector data. + * The result, if successful, always contains a BagAttribute, + * even if only one value was found. If no values were found, but no other + * error occurred, an empty bag is returned. + * + * @param path the XPath expression to search against + * @param namespaceNode the DOM node defining namespace mappings to use, + * or null if mappings come from the context root + * @param type the datatype of the attributes to find + * @param context the representation of the request data + * @param xpathVersion the XPath version to use + * + * @return the result of attribute retrieval, which will be a bag of + * attributes or an error + */ + public EvaluationResult findAttribute(String path, Node namespaceNode, + URI type, EvaluationCtx context, + String xpathVersion) { + // we only support 1.0 + if (! xpathVersion.equals(Constants.XPATH_1_0_IDENTIFIER)) { + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + + // get the DOM root of the request document + Node root = context.getRequestRoot(); + + // if we were provided with a non-null namespace node, then use it + // to resolve namespaces, otherwise use the context root node + Node nsNode = (namespaceNode != null) ? namespaceNode : root; + + // setup the root path (pre-pended to the context path), which... + String rootPath = ""; + + // ...only has content if the context path is relative + if (path.charAt(0) != '/') { + String rootName = root.getLocalName(); + + // see if the request root is in a namespace + String namespace = root.getNamespaceURI(); + + if (namespace == null) { + // no namespacing, so we're done + rootPath = "/" + rootName + "/"; + } else { + // namespaces are used, so we need to lookup the correct + // prefix to use in the search string + NamedNodeMap nmap = namespaceNode.getAttributes(); + rootPath = null; + + for (int i = 0; i < nmap.getLength(); i++) { + Node n = nmap.item(i); + if (n.getNodeValue().equals(namespace)) { + // we found the matching namespace, so get the prefix + // and then break out + String name = n.getNodeName(); + int pos = name.indexOf(':'); + + if (pos == -1) { + // the namespace was the default namespace + rootPath = "/"; + } else { + // we found a prefixed namespace + rootPath = "/" + name.substring(pos + 1); + } + + // finish off the string + rootPath += ":" + rootName + "/"; + + break; + } + } + + // if the rootPath is still null, then we don't have any + // definitions for the namespace + if (rootPath == null) { + return createProcessingError("Failed to map a namespace" + + " in an XPath expression"); + } + } + } + + // now do the query, pre-pending the root path to the context path + NodeList matches = null; + try { + // NOTE: see comments in XALAN docs about why this is slow + matches = XPathAPI.selectNodeList(root, rootPath + path, nsNode); + } catch (Exception e) { + // in the case of any exception, we need to return an error + return createProcessingError("error in XPath: " + e.getMessage()); + } + + if (matches.getLength() == 0) { + // we didn't find anything, so we return an empty bag + return new EvaluationResult(BagAttribute.createEmptyBag(type)); + } + + // there was at least one match, so try to generate the values + try { + ArrayList list = new ArrayList(); + AttributeFactory attrFactory = AttributeFactory.getInstance(); + + for (int i = 0; i < matches.getLength(); i++) { + String text = null; + Node node = matches.item(i); + short nodeType = node.getNodeType(); + + // see if this is straight text, or a node with data under + // it and then get the values accordingly + if ((nodeType == Node.CDATA_SECTION_NODE) || + (nodeType == Node.COMMENT_NODE) || + (nodeType == Node.TEXT_NODE) || + (nodeType == Node.ATTRIBUTE_NODE)) { + // there is no child to this node + text = node.getNodeValue(); + } else { + // the data is in a child node + text = node.getFirstChild().getNodeValue(); + } + + list.add(attrFactory.createValue(type, text)); + } + + return new EvaluationResult(new BagAttribute(type, list)); + } catch (ParsingException pe) { + return createProcessingError(pe.getMessage()); + } catch (UnknownIdentifierException uie) { + return createProcessingError("unknown attribute type: " + type); + } + } + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/package.html new file mode 100644 index 0000000..c187560 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/impl/package.html @@ -0,0 +1,8 @@ + + The few included finder modules are provided in this package. These + provide some basic functionality to get an application started, but + should by no means be considered enterprise quality. They provide a + file-based access to a specific set of policies, a way of getting + current time/date/dateTime values, and simple XPath support for + selectors. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/package.html new file mode 100644 index 0000000..69212d8 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/finder/package.html @@ -0,0 +1,11 @@ + + The finder package supports all of the pieces of the + XACML specification that require custom implementation. Specifically, + there are classes here to manage looking for attributes outside of the + physical request document, finding policies, and resolving resource + identifiers. There are also base classes used to build new modules + that can perform different application specific tasks to support these + three kinds of operations. These managers are used directly by the + PDP, and the managers in turn use the modules, and return values using + the return-value classes in this package. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/package.html b/src/com.sun.xacml/src/main/java/com/sun/xacml/package.html new file mode 100644 index 0000000..6de2999 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/package.html @@ -0,0 +1,9 @@ + + This is the root package, which contains the PDP class where most + people will want to start. This package also contains most of the + classes that represent the XML elements from the XACML policy schema, + like Target, Policy, Rule, and Obligation. Most of the classes here + are used when parsing or processing a policy, but a few (like + EvaluationCtx) are used throughout the code and by many + of the extension APIs. There are also some common Exceptions here. + diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/EdgeExplorer.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/EdgeExplorer.java new file mode 100644 index 0000000..dfd2061 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/EdgeExplorer.java @@ -0,0 +1,346 @@ +/* + * @(#)EdgeExplorer.java + * + * Copyright 2007 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.reduction; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.MatchResult; +import com.sun.xacml.PolicyReference; +import com.sun.xacml.PolicySet; +import com.sun.xacml.PolicyTreeElement; +import com.sun.xacml.ctx.Result; + +/** + * This class provides an iterator that goes through the support + * edges of a policy. + * + * @author Ludwig Seitz + * + */ +public class EdgeExplorer { + + /** + * The node we are exploring from. + */ + private ReductionGraphNode node; + + /** + * The type of edges we want to explore encoded as + * bitwise or of the codes in + * ReductionGraphEdge. + */ + private int allowedEdges; + + /** + * The context we want to explore in. + */ + private EvaluationCtx ctx; + + /** + * The List of neighboring nodes. + */ + private List neighbors; + + /** + * Iterator going through the neighbors. + */ + private Iterator neighborIter; + + /** + * Constructor. + * + * @param allowedEdges The type of edges we want to explore + * as bitwise or of the corresponding + * codes in ReductionGraphEdge. + * @param ctx The context we want to explore in. + * @param startPolicy The PolicyId we are exploring from. + */ + public EdgeExplorer(int allowedEdges, EvaluationCtx ctx, + URI startPolicy) { + this.node = ctx.getReductionGraph().getNode(startPolicy); + this.ctx = ctx; + this.allowedEdges = allowedEdges; + // first get the parent policy set from the stack in context + AbstractPolicy parentPolicySet = ctx.getParentPolicySet(); + if (parentPolicySet != null) { + this.neighbors = getActiveChilds(parentPolicySet.getChildren(), + ctx); + } else { + this.neighbors = new ArrayList(); + } + + this.neighborIter = this.neighbors.iterator(); + + } + + /** + * @return true if there are potential edges left to explore, + * false otherwise. + */ + public boolean hasNext() { + return this.neighborIter.hasNext(); + } + + /** + * @return The next node that is reachable by one of the allowed + * edge types, or null if there aren't any more. + */ + public URI next() { + if (!this.neighborIter.hasNext()) { + return null; + } + AbstractPolicy neighbor = (AbstractPolicy)this.neighborIter.next(); + // First check if there are already matching edges + Set fromEdges = this.ctx.getReductionGraph().getFromEdges( + this.node.getNodeId()); + Iterator edgeIt = fromEdges.iterator(); + while (edgeIt.hasNext()) { + ReductionGraphEdge edge = edgeIt.next(); + if (edge.getTo().equals(neighbor.getId())) { + // we use bitwise AND to see if the edge type is allowed + if ((this.allowedEdges & edge.getType()) + == edge.getType()) { + //report this event + this.ctx.newEvent(edge); + this.ctx.closeCurrentEvent(); + return neighbor.getId(); + } else if (edge.getType() + == ReductionGraphEdge.NOT_APPLICABLE) { + // we don't need to process this any further + // so we can go to the next element + this.ctx.newEvent(edge); + this.ctx.closeCurrentEvent(); + return next(); + } else if (((this.allowedEdges & ReductionGraphEdge.PP) + == ReductionGraphEdge.PP) + && edge.getType() == ReductionGraphEdge.PI) { + // we don't need to process this any further + // so we can go to the next element + this.ctx.newEvent(edge); + this.ctx.closeCurrentEvent(); + return next(); + } else if (((this.allowedEdges & ReductionGraphEdge.DP) + == ReductionGraphEdge.DP) + && edge.getType() == ReductionGraphEdge.DI) { + // we don't need to process this any further + // so we can go to the next element + this.ctx.newEvent(edge); + this.ctx.closeCurrentEvent(); + return next(); + } + } + } + //This edge hasn't been evaluated before, so we do it now + this.ctx.newEvent(neighbor); + MatchResult matchResult = neighbor.match(this.ctx); + switch (matchResult.getResult()) { + case MatchResult.NO_MATCH: + this.ctx.closeCurrentEvent( + new Result(Result.DECISION_NOT_APPLICABLE)); + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.NOT_APPLICABLE)); + return next(); + case MatchResult.INDETERMINATE: + this.ctx.closeCurrentEvent( + new Result(Result.DECISION_INDETERMINATE, this.ctx)); + if (this.ctx.getDecision() == Result.DECISION_PERMIT) { + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.PI, + matchResult.getStatus())); + if ((this.allowedEdges & ReductionGraphEdge.PI) + == ReductionGraphEdge.PI) { + return neighbor.getId(); + } + } else { // decision is DENY + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.DI, + matchResult.getStatus())); + if ((this.allowedEdges & ReductionGraphEdge.DI) + == ReductionGraphEdge.DI) { + return neighbor.getId(); + } + } + return next(); + case MatchResult.MATCH: + //evaluate policy + if (neighbor instanceof PolicySet) { + this.ctx.saveParentPolicySet(neighbor); + } else if (neighbor instanceof PolicyReference) { + PolicyReference ref = (PolicyReference)neighbor; + if (ref.getReferenceType() + == PolicyReference.POLICYSET_REFERENCE) { + this.ctx.saveParentPolicySet(neighbor); + } + } + + Result eval = neighbor.getCombiningAlg().combine(this.ctx, + neighbor.getCombiningParameters(), + neighbor.getChildElements()); + // check for maxDelegationDepth + if (this.ctx.getDelegationDepth() + > neighbor.getMaxDelegationDepth()) { + this.ctx.closeCurrentEvent("MaxDelegationDepth violated"); + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.NOT_APPLICABLE)); + return null; + } + // Check if it supports the revocation of + // a policy down the delegation chain + if (this.ctx.supportsRevocation(neighbor, this.node.getNodeId())) { + Result nullResult = null; + this.ctx.closeCurrentEvent(nullResult); + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.NOT_APPLICABLE)); + return null; + } + this.ctx.closeCurrentEvent(eval); + if (neighbor instanceof PolicySet) { + this.ctx.popParentPolicySet(); + this.ctx.popReductionGraph(); + } else if (neighbor instanceof PolicyReference) { + PolicyReference ref = (PolicyReference)neighbor; + if (ref.getReferenceType() + == PolicyReference.POLICYSET_REFERENCE) { + this.ctx.popParentPolicySet(); + this.ctx.popReductionGraph(); + } + } + switch (eval.getDecision()) { + case Result.DECISION_PERMIT : + if (this.ctx.getDecision() == Result.DECISION_PERMIT) { + this.ctx.getReductionGraph().setEdge( + new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.PP)); + if ((this.allowedEdges & ReductionGraphEdge.PP) + == ReductionGraphEdge.PP) { + return neighbor.getId(); + } + } else if (this.ctx.getDecision() == Result.DECISION_DENY) { + this.ctx.getReductionGraph().setEdge( + new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.DP)); + if ((this.allowedEdges & ReductionGraphEdge.DP) + == ReductionGraphEdge.DP) { + return neighbor.getId(); + } + } + return next(); + case Result.DECISION_INDETERMINATE : + if (this.ctx.getDecision() == Result.DECISION_PERMIT) { + this.ctx.getReductionGraph().setEdge( + new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.PI, + eval.getStatus())); + + if ((this.allowedEdges & ReductionGraphEdge.PI) + == ReductionGraphEdge.PI) { + return neighbor.getId(); + } + } else if (this.ctx.getDecision() == Result.DECISION_DENY) { + this.ctx.getReductionGraph().setEdge( + new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.DI, + eval.getStatus())); + if ((this.allowedEdges & ReductionGraphEdge.DI) + == ReductionGraphEdge.DI) { + return neighbor.getId(); + } + } + return next(); + default: + this.ctx.getReductionGraph().setEdge(new ReductionGraphEdge( + this.node.getNodeId(), neighbor.getId(), + ReductionGraphEdge.NOT_APPLICABLE)); + return next(); + } + } + return next(); + } + + /** + * Private helper that builds the list of active child policies/policy sets + * from the list of all childs and the list of deactivated childs. + * Used in reduction steps of a delegation chain. + * + * @param allChilds a List of CombinerElements. + * @param context the context containing the deactivated childs. + * + * @return A list of CombinerElemets. + */ + private List getActiveChilds(List allChilds, EvaluationCtx context) { + List activeChilds = new ArrayList(); + Iterator iter = allChilds.iterator(); + while (iter.hasNext()) { + AbstractPolicy policy = (AbstractPolicy)iter.next(); + URI elementId = null; + if (policy instanceof PolicyReference) { + //PolicyReferences get special treatment here. + //this is due to the fact that in certain cases we do not + // want to run the resolvePolicy() method of a policy + // reference here, which would be the case if we used getId(). + // An example for such cases can be found in the XACML 2.0 + // test cases, test group E, test 003. + PolicyReference pr = (PolicyReference)policy; + elementId = pr.getReference(); + } else { + elementId = policy.getId(); + } + if (!context.getInactivePolicyIds().contains(elementId)) { + activeChilds.add(policy); + } + } + return activeChilds; + } + + + +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraph.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraph.java new file mode 100644 index 0000000..8562ebe --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraph.java @@ -0,0 +1,369 @@ +/* + * @(#)ReductionGraph.java + * + * Copyright 2007 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.reduction; + +import java.net.URI; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.Constants; +import com.sun.xacml.EvaluationCtx; +import com.sun.xacml.Obligation; +import com.sun.xacml.PolicyTreeElement; +import com.sun.xacml.ctx.RequestElement; +import com.sun.xacml.ctx.Result; +import com.sun.xacml.ctx.Status; + +/** + * This class saves a graph structure for reducing untrusted policies. + * + * @author Ludwig Seitz + * + */ +public class ReductionGraph implements Cloneable { + + /** + * Sets of ReductionGraphEdges of the graph + * keyed by the nodeIds (i.e. policyId URIs) they go out from. + */ + private Map> fromEdges; + + /** + * Sets of ReductionGraphEdges of the graph + * keyed by the nodeIds (i.e. policyId URIs) they go in to. + */ + private Map> toEdges; + + /** + * The ReductionGraphNodes keyed by the id. + */ + private Map nodes; + + /** + * Constructor, starts a new ReductionGraph. + * + * @param pps The parent policy set, from which we gather the nodes + * of the graph. + */ + public ReductionGraph(AbstractPolicy pps) { + this.fromEdges = new HashMap>(); + this.toEdges = new HashMap>(); + this.nodes = new HashMap(); + if (pps != null) { + Iterator iter = pps.getChildren().iterator(); + while(iter.hasNext()) { + AbstractPolicy policy = (AbstractPolicy)iter.next(); + this.nodes.put(policy.getId(), new ReductionGraphNode(policy)); + } + } + } + + /** + * The clone method. + * FIXME: this does no deep copy on the content of the Maps. + * + * @return a copy of this object. + */ + public Object clone() { + try { + ReductionGraph clone = (ReductionGraph) super.clone(); + clone.fromEdges = new HashMap>(this.fromEdges); + clone.toEdges = new HashMap>(this.toEdges); + clone.nodes = new HashMap(this.nodes); + return clone; + } catch (CloneNotSupportedException e) {//this should never happen + throw new RuntimeException("Couldn't clone ReductionGraph"); + } + } + + /** + * A private helper that does the reduction of an untrusted policy or + * policyset. + * + * @param ctx The evaluation context. + * @param result The evaluation result of this policy. + * @param policyId The id of the policy being reduced. + * + * @return The adapted evaluation result of this policy + * (see standard). + */ + public Result reduce(EvaluationCtx ctx, Result result, URI policyId) { + int allowedEdges = 0; + int extendedAllowedEdges = 0; + if (result.getDecision() == Result.DECISION_PERMIT) { + allowedEdges = ReductionGraphEdge.PP; + extendedAllowedEdges + = ReductionGraphEdge.PP | ReductionGraphEdge.PI; + } else if (result.getDecision() == Result.DECISION_DENY) { + allowedEdges = ReductionGraphEdge.DP; + extendedAllowedEdges + = ReductionGraphEdge.DP | ReductionGraphEdge.DI; + } else if (result.getDecision() == Result.DECISION_INDETERMINATE) { + allowedEdges + = ReductionGraphEdge.PP | ReductionGraphEdge.PI; + extendedAllowedEdges + = ReductionGraphEdge.DP | ReductionGraphEdge.DI; + } + + Result reductionResult = graphSearch(allowedEdges, ctx, policyId); + if(reductionResult == null) { + reductionResult = graphSearch(extendedAllowedEdges, ctx, policyId); + if (reductionResult == null) { + return null; + } + List codes = new ArrayList(); + codes.add(Status.STATUS_PROCESSING_ERROR); + return new Result(Result.DECISION_INDETERMINATE, + new Status(codes, "Error while reducing")); + } + return reductionResult; // Permit because reductionResult != null + } + + private Result graphSearch(int allowedEdges, EvaluationCtx ctx, + URI policyId) { + // Get the node. + ReductionGraphNode node = (ReductionGraphNode)this.nodes.get(policyId); + + // Prepare the 'discarded' result (see standard). + Result nullResult = null; + + // Check if there is a parent policy set + if (node == null) { + ctx.newEvent(Integer.valueOf(allowedEdges)); + ctx.closeCurrentEvent(nullResult); + return null; + } + + // Recursion end clause + if (node.isTrusted()) { + return new Result(Result.DECISION_PERMIT, node.getObligations()); + } + + // Signal the reduction event + ctx.newEvent(Integer.valueOf(allowedEdges)); + + Result result = node.previousReduction(allowedEdges); + if (result == null || result.getDecision() != Result.DECISION_DENY) { + //DENY means that the node has not yet been reduced. + //Its a fix so we can just transmit the result. + ctx.closeCurrentEvent(result); + return result; + } + + // create an administrative context + int newDecision = ctx.getDecision(); + //Figure out decision if necessary + if (newDecision == Result.INVALID_DECISION) { + if ((allowedEdges & ReductionGraphEdge.PP) + == ReductionGraphEdge.PP) { + newDecision = Result.DECISION_PERMIT; + } else if ((allowedEdges & ReductionGraphEdge.DP) + == ReductionGraphEdge.DP) { + newDecision = Result.DECISION_DENY; + } else { // this should never happen because decision should be + // permit or deny. + //close the reduction event + ctx.closeCurrentEvent(nullResult); + return null; + } + } + Set newDelegate = null; + // btw: we can safely assume that the policyIssuer is not + // null here otherwise this function would not have been called. + newDelegate = new HashSet(); + RequestElement delegate = new RequestElement(Constants.DELEGATE, + node.getIssuer().getAttributes()); + newDelegate.add(delegate); + EvaluationCtx admCtx = ctx.createAdminCtx(newDecision, + newDelegate); + + // deactivate this policy, we don't want to search it again. + admCtx.addInactivePolicyId(node.getNodeId()); + + // Create edgeExplorer to go through the graph edges from this node + EdgeExplorer potentialEdges = new EdgeExplorer(allowedEdges, admCtx, + node.getNodeId()); + while (potentialEdges.hasNext()) { + URI nextPolicyId = potentialEdges.next(); + if (nextPolicyId == null) { + ctx.closeCurrentEvent(nullResult); + node.setState(null, allowedEdges, + admCtx.getDelegationDepth()); + return null; + } + result = graphSearch(allowedEdges, admCtx, nextPolicyId); + if (result != null && + result.getDecision() == Result.DECISION_PERMIT) { + ctx.closeCurrentEvent(result); + Set obligations = new HashSet(node.getObligations()); + obligations.addAll(result.getObligations()); + node.setState(result, allowedEdges, + admCtx.getDelegationDepth()); + //now return the result + return new Result(Result.DECISION_PERMIT, obligations); + } + } + ctx.closeCurrentEvent(nullResult); + node.setState(nullResult, allowedEdges, admCtx.getDelegationDepth()); + return null; + } + + /** + * Return the type of edge there is for two policies identified + * by their PolicyId URIs. + * + * @param from The policy from which the edge originates. + * @param to The policy to which the edge goes. + * + * @return the type of edge as in the static list above. + */ + public int getEdge(URI from, URI to) { + Set rteSet = this.fromEdges.get(from); + if (rteSet == null) { + return ReductionGraphEdge.NOT_EVALUATED; + } + Iterator iter = rteSet.iterator(); + while (iter.hasNext()) { + ReductionGraphEdge rte = (ReductionGraphEdge)iter.next(); + if (rte.getTo().equals(to)) { + return rte.getType(); + } + } + //if we arrived here, no edges between the two policies where found + return ReductionGraphEdge.NOT_EVALUATED; + + } + + /** + * Set an edge in the ReductionGraph. + * + * @param edge The edge to be set. + */ + public void setEdge(ReductionGraphEdge edge) { + Set fromSet = this.fromEdges.get(edge.getFrom()); + if (fromSet == null) { + fromSet = new HashSet(); + this.fromEdges.put(edge.getFrom(), fromSet); + } + fromSet.add(edge); + Set toSet = this.toEdges.get(edge.getTo()); + if (toSet == null) { + toSet = new HashSet(); + this.toEdges.put(edge.getTo(), toSet); + } + toSet.add(edge); + } + + /** + * Returns the Set of ReductionGraphEdges + * that go out from a specific policy. + * + * @param from The policy identified its PolicyId URI. + * + * @return A Set of ReductionGraphEdges. + */ + public Set getFromEdges(URI from) { + Set result = this.fromEdges.get(from); + if (result == null) { + result = new HashSet(); + this.fromEdges.put(from, result); + } + return result; + } + + /** + * Returns the Set of ReductionGraphEdges + * that go to a specific policy. + * + * @param to The policy identified its PolicyId URI. + * + * @return A Set of ReductionGraphEdges. + */ + public Set getToEdges(URI to) { + Set result = this.fromEdges.get(to); + if (result == null) { + result = new HashSet(); + this.fromEdges.put(to, result); + } + return result; + } + + /** + * Get a node from the graph. + * + * @param nodeId The node's id. + * + * @return The node. + */ + public ReductionGraphNode getNode(URI nodeId) { + return (ReductionGraphNode)this.nodes.get(nodeId); + } + + /** + * Encode to string for debugging + * + * @return String representation of the graph. + */ + public String toString() { + String result = ""; + Iterator> iter = this.nodes.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + ReductionGraphNode node = (ReductionGraphNode) entry.getValue(); + result += node.toString(); + if (this.fromEdges.get(entry.getKey()) != null) { + Iterator iter2 = (this.fromEdges.get(entry.getKey())).iterator(); + while (iter2.hasNext()) { + ReductionGraphEdge edge = iter2.next(); + result += "[" + edge.toString() + "] "; + } + } + result += Constants.nl; + } + return result; + } +} + + + \ No newline at end of file diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphEdge.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphEdge.java new file mode 100644 index 0000000..8d0d553 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphEdge.java @@ -0,0 +1,207 @@ +/* + * @(#)ReductionGraphEdge.java + * + * Copyright 2007 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.reduction; + +import java.net.URI; + +import com.sun.xacml.ctx.Status; + +/** + * This class stores an edge of the reduction graph. + * + * @author Ludwig Seitz + * + */ +public class ReductionGraphEdge { + + /** + * An edge that has not yet been evaluated. + * Binary encoding for bitwise manipulation. + * Only PP | PI and DP | DI are possible making + * the values 1, 2, 3, 4 and 12 reserved. Leaving + * 0 for NOT_EVALUATED and 13 for NOT_APPLICABLE + */ + public static final int NOT_EVALUATED = 0; + + /** + * An edge that reduces PERMIT to PERMIT. + */ + public static final int PP = 1; + + /** + * An edge that reductes PERMIT to INDETERMINATE + */ + public static final int PI = 2; + + + /** + * An edge that reductes DENY to PERMIT + */ + public static final int DP = 4; + + /** + * An edge that reductes DENY to INDETERMINATE + */ + public static final int DI = 8; + + /** + * An edge that reduces to NOT_APPLICABLE + */ + public static final int NOT_APPLICABLE = 16; + + /** + * The policyId URI this edge originates in. + */ + private URI from; + + /** + * The policyId URI this edge points to. + */ + private URI to; + + /** + * The type of edge this is from the types specified in + * ReductionGraph class. + */ + private int type; + + /** + * The status for a PI or DI edge. Null for all other types. + */ + private Status status; + + /** + * Constructor. + * + * @param from The policyId URI this edge originates in. + * @param to The policyId URI this edge points to. + * @param type The type of edge this is, from the types specified + * in ReductionGraph class. + */ + public ReductionGraphEdge(URI from, URI to, int type) { + this(from, to, type, null); + } + + /** + * Constructor. + * + * @param from The policyId URI this edge originates in. + * @param to The policyId URI this edge points to. + * @param type The type of edge this is, from the types specified + * in ReductionGraph class. + */ + public ReductionGraphEdge(URI from, URI to, Integer type) { + this(from, to, type, null); + } + + /** + * Constructor. + * + * @param from The policyId URI this edge originates in. + * @param to The policyId URI this edge points to. + * @param type The type of edge this is, from the types specified + * in ReductionGraph class. + * @param status The status for a PI or DI edge. + */ + public ReductionGraphEdge(URI from, URI to, int type, Status status) { + this.from = from; + this.to = to; + this.type = type; + this.status = status; + } + + /** + * Constructor. + * + * @param from The policyId URI this edge originates in. + * @param to The policyId URI this edge points to. + * @param type The type of edge this is, from the types specified + * in ReductionGraph class. + * @param status The status for a PI or DI edge. + */ + public ReductionGraphEdge(URI from, URI to, Integer type, Status status) { + this.from = from; + this.to = to; + this.type = type.intValue(); + this.status = status; + } + + + /** + * @return The policyId URI this edge originates in. + */ + public URI getFrom() { + return this.from; + } + + /** + * @return The policyId URI this edge points to. + */ + public URI getTo() { + return this.to; + } + + /** + * @return The type of edge this is from the types specified in + * ReductionGraph class. + */ + public int getType() { + return this.type; + } + + /** + * @return The Status or null if there isn't one. + */ + public Status getStatus() { + return this.status; + } + + /** + * Encode edge to string for debugging. + * + * @return String representation of the graph edge. + */ + public String toString() { + //Values for the reduction graph edges. + //Currently only the values NE, PP, (PP,PI), DP, (DP,DI) and NA + //are legal + String [] values = {"NE", "PP", "PI", "PP,PI", "DP", "PP,DP", + "PI,DP", "PP,PI,DP", "DI", "PP,DI", "PI,DI", "PP,PI,DI", + "DP,DI", "PP,DP,DI", "PP,PI,DI", "PP,PI,DP,DI", "NA"}; + return values[this.type] + "->" + this.to.toString(); + } +} diff --git a/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphNode.java b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphNode.java new file mode 100644 index 0000000..af367e2 --- /dev/null +++ b/src/com.sun.xacml/src/main/java/com/sun/xacml/reduction/ReductionGraphNode.java @@ -0,0 +1,387 @@ +/* + * @(#)ReductionGraphNode.java + * + * Copyright 2007 Swedish Institute of Computer Science All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistribution of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Swedish Institute of Computer Science or the names of + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE SWEDISH INSTITUE OF COMPUTER + * SCIENCE ("SICS") AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES + * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SICS OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE THIS SOFTWARE, EVEN IF SICS HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use in + * the design, construction, operation or maintenance of any nuclear facility. + */ + +package com.sun.xacml.reduction; + +import java.net.URI; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import com.sun.xacml.AbstractPolicy; +import com.sun.xacml.Obligation; +import com.sun.xacml.ctx.PolicyIssuer; +import com.sun.xacml.ctx.Result; + +public class ReductionGraphNode { + + /** + * Static value for the reducable* members. + */ + public static final int UNKNOWN = -1; + + /** + * Static value for the reducable* members. + */ + public static final int NO = 0; + + /** + * Static value for the reducable* members. + */ + public static final int YES = 1; + + /** + * Describes if this node can be reduced to a trusted + * node by PP edges. + */ + private int reducablePP; + + /** + * Describes if this node can be reduced to a trusted + * node by PP and PI edges. + */ + private int reducablePI; + + /** + * Describes if this node can be reduced to a trusted + * node by DP edges. + */ + private int reducableDP; + + /** + * Describes if this node can be reduced to a trusted + * node by DP and DI edges. + */ + private int reducableDI; + + /** + * Saves the length of the shortest path for a reducable node. + */ + private int reductionPathLength; + + /** + * Describes if this is a trusted node. + */ + private boolean trusted; + + /** + * Node id. + */ + private URI nodeId; + + /** + * The obligations related to this nodes reduction path. + */ + private Set obligations; + + /** + * The policy issuer of the policy represented by this node. + */ + private PolicyIssuer issuer; + + /** + * Creates a new untrusted node. + * + * @param policy The policy which is represented by the node. + */ + public ReductionGraphNode(AbstractPolicy policy) { + this.trusted = policy.hasTrustedIssuer(); + this.nodeId = policy.getId(); + if (this.trusted) { + this.reducablePP = YES; + this.reducablePI = YES; + this.reducableDP = YES; + this.reducableDI = YES; + this.reductionPathLength = 0; + } else { + this.reducablePP = UNKNOWN; + this.reducablePI = UNKNOWN; + this.reducableDP = UNKNOWN; + this.reducableDI = UNKNOWN; + this.reductionPathLength = UNKNOWN; + } + this.obligations = new HashSet(); + this.obligations.addAll(policy.getObligations()); + this.issuer = policy.getPolicyIssuer(); + + } + + /** + * @return Can this node be reduced to a trusted node by DP and DI edges. + * Meaning of the return values as in the static declarations of + * this class. + */ + public int getReducableDI() { + return this.reducableDI; + } + + /** + * Set new value for reducableDI. Meaning of the values as in the static + * declarations of this class. You also need to set the length of + * the reduction path. + * + * @param reducableDI + * @param reductionPathLength + */ + public void setReducableDI(int reducableDI, int reductionPathLength) { + this.reducableDI = reducableDI; + this.reductionPathLength = reductionPathLength; + } + + /** + * @return Can this node be reduced to a trusted node by DP edges. + * Meaning of the return values as in the static declarations of + * this class. + */ + public int getReducableDP() { + return this.reducableDP; + } + + /** + * Set new value for reducableDP. Meaning of the values as in the static + * declarations of this class. You also need to set the length of + * the reduction path. + * + * @param reducableDP + * @param reductionPathLength + */ + public void setReducableDP(int reducableDP, int reductionPathLength) { + this.reducableDP = reducableDP; + this.reductionPathLength = reductionPathLength; + } + + /** + * @return Can this node be reduced to a trusted node by PP and PI edges. + * Meaning of the return values as in the static declarations of + * this class. + */ + public int getReducablePI() { + return this.reducablePI; + } + + /** + * Set new value for reducablePI. Meaning of the values as in the static + * declarations of this class. You also need to set the length of + * the reduction path. + * + * @param reducablePI + * @param reductionPathLength + */ + public void setReducablePI(int reducablePI, int reductionPathLength) { + this.reducablePI = reducablePI; + this.reductionPathLength = reductionPathLength; + } + + /** + * @return Can this node be reduced to a trusted node by PP. + * Meaning of the return values as in the static declarations of + * this class. + */ + public int getReducablePP() { + return this.reducablePP; + } + + /** + * Set new value for reducablePP. Meaning of the values as in the static + * declarations of this class. You also need to set the length of + * the reduction path. + * + * @param reducablePP + * @param reductionPathLength + */ + public void setReducablePP(int reducablePP, int reductionPathLength) { + this.reducablePP = reducablePP; + this.reductionPathLength = reductionPathLength; + } + + /** + * Set the state of the reducable variables based on a reduction result + * and the type of reduction (i.e. PP, PP-PI, DP, DP-DI). + * + * @param result The reduction result (PERMIT or null) + * @param reductionType The int code determining the allowed edges + * for this type of reduction. A bitwise or + * of the codes from + * ReductionGraphEdge. + * @param delegationDepth The length of the reduction path. + */ + public void setState(Result result, int reductionType, + int delegationDepth) { + if (reductionType + == (ReductionGraphEdge.PP | ReductionGraphEdge.PI)) { + if (result == null) { + this.reducablePP = ReductionGraphNode.NO; + this.reducablePI = ReductionGraphNode.NO; + } else { + this.reducablePI = ReductionGraphNode.YES; + this.reductionPathLength = delegationDepth; + } + } else if (reductionType == ReductionGraphEdge.PP) { + if (result == null) { + this.reducablePP = ReductionGraphNode.NO; + } else { + this.reducablePP = ReductionGraphNode.YES; + this.reducablePI = ReductionGraphNode.YES; + this.reductionPathLength = delegationDepth; + } + } else if (reductionType + == (ReductionGraphEdge.DP | ReductionGraphEdge.DI)) { + if (result == null) { + this.reducableDP = ReductionGraphNode.NO; + this.reducableDI = ReductionGraphNode.NO; + } else { + this.reducableDI = ReductionGraphNode.YES; + this.reductionPathLength = delegationDepth; + } + } else if (reductionType == ReductionGraphEdge.DP){ + if (result == null) { + this.reducableDP = ReductionGraphNode.NO; + } else { + this.reducableDP = ReductionGraphNode.YES; + this.reducableDI = ReductionGraphNode.YES; + this.reductionPathLength = delegationDepth; + } + } else { + throw new RuntimeException("invalid reductionType ==" + + reductionType); + } + + } + + /** + * Determines if the node is already reduced for this type + * of reduction (i.e. PP, PP-PI, DP, DP-DI). + * + * @param reductionType The int code determining the allowed edges + * for this type of reduction. A bitwise or + * of the codes from + * ReductionGraphEdge. + * @return The result of the previous reduction. + */ + public Result previousReduction(int reductionType) { + if ((reductionType & ReductionGraphEdge.PP) + == ReductionGraphEdge.PP) { + if (this.reducablePP == ReductionGraphNode.YES) { + return new Result(Result.DECISION_PERMIT, this.obligations); + } else if ((reductionType & ReductionGraphEdge.PI) + == ReductionGraphEdge.PI) { + if (this.reducablePI == ReductionGraphNode.YES) { + return new Result(Result.DECISION_INDETERMINATE); + } else if (this.reducablePI == ReductionGraphNode.NO) { + return null; + } + } else if (this.reducablePP == ReductionGraphNode.NO) { + return null; + } + } else if ((reductionType & ReductionGraphEdge.DP) + == ReductionGraphEdge.DP) { + if (this.reducableDP == ReductionGraphNode.YES) { + return new Result(Result.DECISION_PERMIT, this.obligations); + } else if ((reductionType & ReductionGraphEdge.DI) + == ReductionGraphEdge.DI) { + if (this.reducableDI == ReductionGraphNode.YES) { + return new Result(Result.DECISION_INDETERMINATE); + } else if (this.reducableDI == ReductionGraphNode.NO) { + return null; + } + } else if (this.reducableDP == ReductionGraphNode.NO) { + return null; + } + } + //means this node has not yet been reduced + return new Result(Result.DECISION_DENY); + } + + /** + * @return True if this node is trusted. + */ + public boolean isTrusted() { + return this.trusted; + } + + /** + * @return The node id. + */ + public URI getNodeId() { + return this.nodeId; + } + + /** + * @return The policy issuer. + */ + public PolicyIssuer getIssuer() { + return (PolicyIssuer)this.issuer.clone(); + } + + /** + * @return A Set of Obligations related + * to this nodes reduction path. + */ + public Set getObligations() { + return Collections.unmodifiableSet(this.obligations); + } + + /** + * @return the reductionPathLength. + */ + public int getReductionPathLength() { + return this.reductionPathLength; + } + + /** + * Add new obligations to this nodes set of obligations. + * + * @param obligations the new obligations, a Set + * of Obligations. + */ + public void addObligations(Set obligations) { + this.obligations.addAll(obligations); + } + + /** + * Encode this node to string for debugging. + * + * @return String representation of the graph. + */ + public String toString() { + String [] values = {"Unknown", "NO", "YES"}; + return this.nodeId.toString() + "{PP=" + values[this.reducablePP+1] + + ", PI=" + values[this.reducablePI+1] + ", DP=" + + values[this.reducableDP+1] + ", DI=" + + values[this.reducableDI+1] + "}"; + } + +} diff --git a/src/com.sun.xacml/src/test/java/com/sun/xacml/AppTest.java b/src/com.sun.xacml/src/test/java/com/sun/xacml/AppTest.java new file mode 100644 index 0000000..74a91ec --- /dev/null +++ b/src/com.sun.xacml/src/test/java/com/sun/xacml/AppTest.java @@ -0,0 +1,66 @@ +package com.sun.xacml; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Properties; + +import org.apache.log4j.PropertyConfigurator; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } + + public static void main(String[] args) throws IOException, ParsingException, UnknownIdentifierException { + Properties log4jProps = new Properties(); + log4jProps.load(new BufferedInputStream(new FileInputStream(new File("../pdp/src/test/log4j.properties")))); + PropertyConfigurator.configure(log4jProps); + // //AppTest test = new AppTest("pdpServer test"); + //test.testApp(); + foo(); + } + + private static void foo() throws FileNotFoundException, ParsingException, UnknownIdentifierException { + + ConfigurationStore config = new ConfigurationStore(new FileInputStream(new File("src/main/resources/policy-config.xml")), "src/main/resources/"); + + //PDP pdp = + new PDP(config.getDefaultPDPConfig()); + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/META-INF/MANIFEST.MF b/src/eu.aniketos.securebpmn.export.aslan/META-INF/MANIFEST.MF new file mode 100644 index 0000000..fd21ca6 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/META-INF/MANIFEST.MF @@ -0,0 +1,27 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - SecureBPMN: ASLan Export +Bundle-SymbolicName: eu.aniketos.securebpmn.export.aslan;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: eu.aniketos.securebpmn.export.aslan.bundle.Activator +Bundle-Vendor: SAP SE +Require-Bundle: org.eclipse.core.runtime, + org.activiti.designer.eclipse, + org.activiti.designer.model, + org.activiti.designer.gui, + org.eclipse.emf, + org.eclipse.graphiti.mm, + org.eclipse.graphiti.ui, + org.eclipse.core.resources +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Import-Package: eu.aniketos.securebpmn.util, + org.activiti.designer.util.preferences +Bundle-ClassPath: ., + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + com.sun.xacml-0.1.jar, + jdi.jar, + jdimodel.jar, + junit.jar diff --git a/src/eu.aniketos.securebpmn.export.aslan/build.properties b/src/eu.aniketos.securebpmn.export.aslan/build.properties new file mode 100644 index 0000000..2d59375 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java/ +output.. = target/ +bin.includes = META-INF/,\ + plugin.xml,\ + . \ No newline at end of file diff --git a/src/eu.aniketos.securebpmn.export.aslan/plugin.xml b/src/eu.aniketos.securebpmn.export.aslan/plugin.xml new file mode 100644 index 0000000..a9a394d --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/plugin.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/eu.aniketos.securebpmn.export.aslan/pom.xml b/src/eu.aniketos.securebpmn.export.aslan/pom.xml new file mode 100644 index 0000000..c71d680 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + eu.aniketos.securebpmn.export.aslan + eclipse-plugin + Activiti Designer - SecureBPMN: ASLan Export + diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/bundle/Activator.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/bundle/Activator.java new file mode 100644 index 0000000..b4600a5 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/bundle/Activator.java @@ -0,0 +1,55 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.bundle; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + */ +public class Activator implements BundleActivator { + // The plug-in ID + public static final String PLUGIN_ID = "eu.aniketos.securebpmn.export.aslan"; //$NON-NLS-1$ + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanExportMarshaller.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanExportMarshaller.java new file mode 100644 index 0000000..d5bf49f --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanExportMarshaller.java @@ -0,0 +1,306 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.List; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.export.AbstractExportMarshaller; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.Process; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.securebpmn2.BindingOfDuty; +import org.eclipse.securebpmn2.Role; +import org.eclipse.securebpmn2.SeparationOfDuty; +import org.eclipse.securebpmn2.Subject; +import org.eclipse.securebpmn2.User; + +import eu.aniketos.securebpmn.util.SecurityUtil; + +/** + * Exports an ASLan representation of the diagram being saved to the workspace. + * + * @since 0.5.7 + * @version 1 + * + */ +public class AslanExportMarshaller extends AbstractExportMarshaller { + private static final String FILENAME_PATTERN = ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION + + ".aslan"; + private IProgressMonitor monitor; + private Diagram diagram; + + public AslanExportMarshaller() { + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * getMarshallerName() + */ + @Override + public String getMarshallerName() { + return ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME; + } + + /* + * (non-Javadoc) + * + * @see + * org.activiti.designer.eclipse.extension.export.ExportMarshaller#getFormatName + * () + */ + @Override + public String getFormatName() { + return "SecureBPMN: ASLan"; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * marshallDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void marshallDiagram(Diagram diagram, IProgressMonitor monitor) { + + this.monitor = monitor; + this.diagram = diagram; + + this.monitor.beginTask("Exporting to ASLan", 100); + + // Clear problems for this marshaller first + clearMarkers(getResource(diagram.eResource().getURI())); + + this.monitor.worked(10); + + // diagram validation + + // Retrieve validatorId to allow for overriding the default validator + String validatorId = ActivitiBPMNDiagramConstants.ASLAN_VALIDATOR_ID; + + boolean validBpmn = invokeValidator(validatorId, diagram, + new SubProgressMonitor(this.monitor, 10)); + + if (validBpmn) { + marshallAslan(); + } else { + addProblemToDiagram( + diagram, + "ASLan Export skipped because SecureBPMN validation failed.", + null); + } + + this.monitor.worked(80); + this.monitor.done(); + + } + + /** + * Controls and executes the ASLan file generation. + */ + public void marshallAslan() { + try { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8"); + final Writer out = new BufferedWriter(osw); + + final List contents = diagram.eResource().getContents(); + + Process process = null; + + for (final EObject eObject : contents) { + if (eObject instanceof Process) { + process = (Process) eObject; + } + } + + if (process == null) { + addProblemToDiagram(diagram, "Process cannot be null", null); + } + + final AslanFileBuilder afb = new AslanFileBuilder(out); + + createSignatureSection(afb); + + createUserRoleMappings(afb); + + createStaticRuleSection(afb); + + // element-specific content generation + for (EObject object : contents) { + if (object instanceof ParallelGateway) { + + ParallelGatewayExport.createParallelGatewayElements( + (ParallelGateway) object, afb); + + } else if (object instanceof ExclusiveGateway) { + + ExclusiveGatewayExport.createExclusiveGatewayElements( + (ExclusiveGateway) object, afb); + + } else if (object instanceof StartEvent) { + + final String startEventFact = "start_event_" + + ((StartEvent) object).getId(); + afb.addType("fact", startEventFact); + afb.addInit(startEventFact); + + } else if (object instanceof Task) { + + TaskExport.createTaskElements((Task) object, afb); + + } else if (object instanceof SeparationOfDuty) { + + SeparationOfDutyExport.createSeparationOfDutyElements( + (SeparationOfDuty) object, afb); + + } else if (object instanceof BindingOfDuty) { + + BindingOfDutyExport.createBindingOfDutyElements( + (BindingOfDuty) object, afb); + } + } + + int writeStatus = afb.writeOutput(); + out.flush(); + + final byte[] bytes = baos.toByteArray(); + final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + saveResource(getRelativeURIForDiagram(diagram, FILENAME_PATTERN), + bais, new NullProgressMonitor()); + + if (writeStatus == AslanFileBuilder.NO_GOALS) { + addWarningToDiagram( + diagram, + "The ASLan file contains no goals. Analyzing it with SATMC will result in an error.", + null); + } + + } catch (Exception e) { + e.printStackTrace(); + addProblemToDiagram( + diagram, + "An exception occurred while creating the ASLan file: " + + e.getMessage(), null); + } + } + + /** + * Writes the signature section of the ASLan file to the provided + * AslanFileBuilder. + * + * @param afb + * The AslanFileBuilder the output is sent to. + */ + private void createSignatureSection(AslanFileBuilder afb) { + afb.addSignature("user_to_role : user * role -> fact"); + afb.addSignature("poto : userORrole * taskName -> fact"); + afb.addSignature("task_to_data : taskName * set * set -> fact"); + afb.addSignature("aknows : entity * data -> fact"); + afb.addSignature("mc_pair : data * data -> data"); + afb.addSignature("contains : set * data -> fact"); + afb.addSignature("task : taskName * nat -> taskInstance"); + afb.addSignature("canExecute : user * role * humanTaskName -> fact"); + afb.addSignature("granted : user * role * taskInstance -> fact"); + afb.addSignature("executed : user * taskInstance -> fact"); + afb.addSignature("ready : taskInstance -> fact"); + afb.addSignature("done : taskInstance -> fact"); + + afb.addSignature("entity > organization"); + afb.addSignature("entity > user"); + afb.addSignature("data > object"); + afb.addSignature("data > set"); + afb.addSignature("userORrole > user"); + afb.addSignature("userORrole > role"); + afb.addSignature("taskName > automatedTaskName"); + afb.addSignature("taskName > humanTaskName"); + } + + /** + * Writes the static rules of the ASLan file to the provided + * AslanFileBuilder. + * + * @param afb + * The AslanFileBuilder the output is sent to. + */ + private void createStaticRuleSection(AslanFileBuilder afb) { + // variable type definitions + afb.addType("user", "A"); + afb.addType("role", "R"); + afb.addType("humanTaskName", "HT"); + afb.addType("nat", "N"); + afb.addType("set", "IN"); + afb.addType("set", "OUT"); + afb.addType("automatedTaskName", "AT"); + + // task claiming authorization + afb.addHornClause("hc rbac_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(R,HT)"); + afb.addHornClause("hc direct_ac (A,R,HT) := canExecute(A,R,HT) :- user_to_role(A,R), poto(A,HT)"); + + // task claiming + afb.addRule("step authorizeTaskExecution(A,R,HT,N) := canExecute(A,R,HT). ready(task(HT,N)) => granted(A,R,task(HT,N))"); + + // human task execution + afb.addRule("step h_taskExecution(A,R,HT,N,IN,OUT) := granted(A,R,task(HT,N)). task_to_data(HT,IN,OUT) => executed(A,task(HT,N)). done(task(HT,N)). task_to_data(HT,IN,OUT). aknows(A,IN). aknows(A,OUT)"); + + // automated task execution + afb.addRule("step atask_execution(AT,N,IN,OUT) := ready(task(AT,N)). task_to_data(AT,IN,OUT) => done(task(AT,N)). task_to_data(AT,IN,OUT)"); + } + + /** + * Writes the user to role mappings of the ASLan file to the provided + * AslanFileBuilder. + * + * @param afb + * The AslanFileBuilder the output is sent to. + */ + private void createUserRoleMappings(AslanFileBuilder afb) { + + final List roles = SecurityUtil.getRoles(diagram); + + for (Role r : roles) { + + final String roleName = r.getName().toLowerCase(); + afb.addType("role", roleName); + + for (Subject s : r.getSubjects()) { + if (s instanceof User) { + final User u = (User) s; + final String userName = u.getUserName().toLowerCase(); + afb.addType("user", userName); + afb.addInit("user_to_role(" + userName + "," + roleName + + ")"); + } + } + } + } +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanFileBuilder.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanFileBuilder.java new file mode 100644 index 0000000..f74b69a --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/AslanFileBuilder.java @@ -0,0 +1,254 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.util.preferences.Preferences; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; + +/** + * Writes an ASLan system file to the provided Writer. + * + */ +public class AslanFileBuilder { + + public static final int NO_ERRORS = 0; + public static final int NO_GOALS = 1; + + private Writer writer; + + private List signatures; + private Map> types; + private List inits; + private List hornClauses; + private List rules; + private List goals; + private Map goalCounter; + + private int goalNatVars = 0; + + private final String lineSeparator = System.getProperty("line.separator");; + + public AslanFileBuilder(Writer writer) { + this.writer = writer; + signatures = new ArrayList(); + types = new HashMap>(); + inits = new ArrayList(); + hornClauses = new ArrayList(); + rules = new ArrayList(); + goals = new ArrayList(); + goalCounter = new HashMap(); + } + + /** + * Writes the contents to the given Writer. + * + * @throws IOException + * on IO error of the Writer + */ + public int writeOutput() throws IOException { + writer.write("section signature:" + lineSeparator + lineSeparator); + for (String signature : signatures) { + writer.write("\t" + signature + lineSeparator); + } + + writer.write(lineSeparator + "section types:" + lineSeparator + + lineSeparator); + + for (String type : types.keySet()) { + writer.write("\t"); + boolean first = true; + for (String var : types.get(type)) { + if (first) + first = false; + else + writer.write(","); + + writer.write(var); + } + writer.write(": " + type + lineSeparator); + } + + writer.write(lineSeparator + "section inits:" + lineSeparator + + lineSeparator + "\tinitial_state init_1 :=" + lineSeparator); + boolean firstInitFact = true; + for (String init : inits) { + if (firstInitFact) { + firstInitFact = false; + } else { + writer.write("."); + } + writer.write(lineSeparator + "\t\t" + init); + } + + writer.write(lineSeparator + lineSeparator + "section hornClauses:" + + lineSeparator + lineSeparator); + for (String hornClause : hornClauses) { + writer.write("\t" + hornClause + lineSeparator); + } + + writer.write(lineSeparator + "section rules:" + lineSeparator + + lineSeparator); + for (String rule : rules) { + writer.write("\t" + rule + lineSeparator); + } + + writer.write(lineSeparator + "section goals:" + lineSeparator + + lineSeparator); + for (String goal : goals) { + writer.write("\t" + goal + lineSeparator); + } + + if (goals.size() == 0) { + return NO_GOALS; + } else { + return NO_ERRORS; + } + } + + /** + * Adds a line to the SignatureSection + * + * @param signature + * signature line + */ + public void addSignature(String signature) { + signatures.add(signature); + } + + /** + * Adds type definitions to the TypesSection, duplicates won't be added + * + * @param type + * variable/constant type + * @param name + * name of the variable/constant + */ + public void addType(String type, String name) { + List list; + + if (types.containsKey(type)) { + list = types.get(type); + + for (String var : list) { + if (var.equals(name)) + return; + } + + } else { + list = new ArrayList(); + } + + list.add(name); + types.put(type, list); + } + + /** + * Adds a constant in the TypesSection for a given Task. The subtype is + * automatically detected. + * + * @param task + * task the constant should be generated for + */ + public void addTaskType(Task task) { + + boolean isHumanTask = false; + + if (task instanceof UserTask + || PreferencesUtil + .getBooleanPreference(Preferences.ALL_TASKS_AS_HUMANTASKS)) + isHumanTask = true; + + if (isHumanTask) { + addType("humanTaskName", task.getId()); + } else { + addType("automatedTaskName", task.getId()); + } + } + + /** + * Adds a variable in the TypesSection with the type "nat" and returns its + * name. Using this function ensures that the "nat" variables are globally + * unique. + * + * @return The name of the newly created variable. + */ + public String addNatVar() { + String newNatVar = "N" + goalNatVars; + addType("nat", newNatVar); + goalNatVars++; + + return newNatVar; + } + + /** + * Adds a fact to the initial state. + * + * @param initFact + * fact that gets added + */ + public void addInit(String initFact) { + inits.add(initFact); + } + + /** + * Adds a line to the HornClausesSection. + * + * @param hornClause + * line to be added + */ + public void addHornClause(String hornClause) { + hornClauses.add(hornClause); + } + + /** + * Adds a line to the RulesSection. + * + * @param ruleDecl + * line to be added + */ + public void addRule(String ruleDecl) { + rules.add(ruleDecl); + } + + /** + * Adds a line to the GoalsSection + * + * @param goalDecl + * line to be added + */ + public void addGoalLine(String goalDecl) { + goals.add(goalDecl); + } + + public void addGoal(String name, String param) { + + if (goalCounter.get(name) == null) + goalCounter.put(name, 1); + + goals.add("attack_state " + name + goalCounter.get(name) + param); + goalCounter.put(name, goalCounter.get(name) + 1); + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/BindingOfDutyExport.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/BindingOfDutyExport.java new file mode 100644 index 0000000..9203ae4 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/BindingOfDutyExport.java @@ -0,0 +1,265 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.BindingOfDuty; +import org.eclipse.securebpmn2.Permission; + +/** + * Creates the ASLan representation of a SecureBPMN BindingOfDuty element. + * + * + */ +public class BindingOfDutyExport { + + /** + * Generates the ASLan representation of the provided BindingOfDuty element + * and sends the output to the provided AslanFileBuilder. + * + * @param bod + * The BindingOfDuty element for which the representation should + * be generated. + * @param afb + * The AslanFileBuilder the output is sent to. + */ + public static void createBindingOfDutyElements(BindingOfDuty bod, + AslanFileBuilder afb) { + + if (bod.isDynamicEnforcement()) + return; + + List assignTasks = new ArrayList(); + List claimTasks = new ArrayList(); + List completeTasks = new ArrayList(); + + for (Permission p : bod.getPermissions()) { + + if (p.getActions().size() == 0) { + System.err + .println("[WARNING] The permission with name=\"" + + p.getPName() + + "\" and id=\"" + + p.getId() + + "\" has no action. This should never happen! Check your .activiti diagram file."); + continue; + } + + // Permissions only have one Action + if (p.getActions().get(0) instanceof ActivityAction) { + ActivityAction a = (ActivityAction) p.getActions().get(0); + + if (a.getActionName().equals("Complete")) { + + completeTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Claim")) { + + claimTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Assign")) { + + assignTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Full Access")) { + + assignTasks.add(a.getActivity().getId()); + claimTasks.add(a.getActivity().getId()); + completeTasks.add(a.getActivity().getId()); + + } + + } + } + + if (assignTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (claimTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (completeTasks.size() > 1) { + // safe default assumptions + int maxUsers = 1; + int numActions = completeTasks.size(); + + if (bod.getMaxUsers() == null) { + System.out + .println("[SCVM-EXPORT-ASLAN] maximum users for BoD \"" + + bod.getId() + "\" not set, using " + maxUsers + + "."); + } else { + if (bod.getMaxUsers() < 1) { + System.err + .println("[SCVM-EXPORT-ASLAN] invalid input for maximum users at BoD \"" + + bod.getId() + + "\", using " + + maxUsers + + "."); + } else { + maxUsers = bod.getMaxUsers(); + } + } + + if (bod.getSameUserActionCount() == null) { + System.out + .println("[SCVM-EXPORT-ASLAN] number of actions for BoD \"" + + bod.getId() + + "\" not set, using " + + numActions + "."); + } else { + if (bod.getSameUserActionCount() > completeTasks.size() + || bod.getSameUserActionCount() < 1) { + System.err + .println("[SCVM-EXPORT-ASLAN] invalid input for number of actions at BoD \"" + + bod.getId() + + "\", using " + + numActions + + "."); + } else { + numActions = bod.getSameUserActionCount(); + } + } + + // calculate numeric partitions + final List allPartitions = ExportUtil + .generateIntegerPartitions(completeTasks.size()); + + // select invalid partitions + List selectedPartitions = new ArrayList(); + for (int[] part : allPartitions) { + boolean invalidSummandFound = false; + for (int i : part) { + if (i != numActions) + invalidSummandFound = true; + } + if (part.length > 0 + && (part.length > maxUsers || invalidSummandFound)) { + selectedPartitions.add(part); + } + } + + // create goals for partitions + String[] tasks = new String[completeTasks.size()]; + for (int i = 0; i < completeTasks.size(); i++) { + tasks[i] = completeTasks.get(i); + } + List permList = ExportUtil + .generateLocationPermutations(tasks.length); + + for (int[] part : selectedPartitions) { + // we assume that tasks.lengh equals the sum of each partition + List>> sets = new ArrayList>>(); + + // loop over index permutations + for (int[] perm : permList) { + int indexStart = 0; + // list of sets (parts of the partition) for the current + // permutation + List> setList = new ArrayList>(); + // create the sets + for (int partLength : part) { + Set partTasks = new HashSet(); + // get the tasks and add them to the set + for (int i = 0; i < partLength; i++) { + partTasks.add(tasks[perm[indexStart + i] - 1]); + } + indexStart += partLength; + setList.add(partTasks); + } + // check if partition config already exists + boolean newSet = true; + for (List> presentSetList : sets) { + if (presentSetList.equals(setList)) { + newSet = false; + break; + } + } + // add partition config if new + if (newSet) { + sets.add(setList); + } + + } + + // create goals for this partition + for (List> setArray : sets) { + // generate goal + int numUsers = setArray.size(); + int numTasks = tasks.length; + List natVars = new ArrayList(); + StringBuilder goalString = new StringBuilder(); + goalString.append("("); + + // generate user variables + for (int i = 0; i < numUsers; i++) { + afb.addType("user", "U" + i); + if (i > 0) + goalString.append(","); + goalString.append("U" + i); + } + + // generate task nat variables + for (int i = 0; i < numTasks; i++) { + String currentVar = afb.addNatVar(); + natVars.add(currentVar); + goalString.append("," + currentVar); + } + + goalString.append("):="); + + // generate "executed" facts + int natVarPos = 0; + for (int i = 0; i < numUsers; i++) { + for (String currentTask : setArray.get(i)) { + goalString.append(" executed(U" + i + ",task(" + + currentTask + "," + + natVars.get(natVarPos) + "))."); + natVarPos++; + } + } + + // generate "not equal" facts + StringBuilder neqString = new StringBuilder(); + for (int i = 0; i < numUsers - 1; i++) { + for (int j = i + 1; j < numUsers; j++) { + neqString.append("& not(equal(U" + i + ",U" + j + + "))"); + } + } + + // add goal + String finalGoalString = goalString.toString(); + afb.addGoal( + "bod_" + bod.getId() + "_", + finalGoalString.substring(0, + finalGoalString.length() - 1) + + neqString.toString()); + } + } + + } + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExclusiveGatewayExport.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExclusiveGatewayExport.java new file mode 100644 index 0000000..6133a26 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExclusiveGatewayExport.java @@ -0,0 +1,145 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.util.List; + +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; + +/** + * Creates the ASLan representation for a BPMN 2.0 ExclusiveGateway element. + * + */ +public class ExclusiveGatewayExport { + + /** + * Generates the ASLan representation of the provided ExclusiveGateway + * element and sends the output to the provided AslanFileBuilder. + * + * @param exclusiveGateway + * The ExclusiveGateway for which the representation should be + * generated. + * @param afb + * The AslanFileBuilder the output is sent to. + */ + public static void createExclusiveGatewayElements( + ExclusiveGateway exclusiveGateway, AslanFileBuilder afb) { + + final List incoming = exclusiveGateway.getIncoming(); + + if (incoming.size() > 1) { + + // XOR-join + final List outgoing = exclusiveGateway.getOutgoing(); + + FlowElement successor = null; + String auxFact = ""; + + if (outgoing.size() > 0) { + successor = outgoing.get(0).getTargetRef(); + auxFact += exclusiveGateway.getId() + "_to_" + + successor.getId(); + } + + int branchCounter = 1; + for (SequenceFlow parentFlow : incoming) { + + final FlowElement predecessor = parentFlow.getSourceRef(); + + String lhs = ""; + + if (predecessor instanceof Task) { + + String natVar = afb.addNatVar(); + + lhs += "(" + natVar + ") := done(task(" + + predecessor.getId() + "," + natVar + "))"; + + } else if (predecessor instanceof Gateway) { + + lhs += " := " + predecessor.getId() + "_to_" + + exclusiveGateway.getId(); + + } else if (predecessor instanceof StartEvent) { + + lhs += " := start_event_" + predecessor.getId(); + + } + + if (lhs.length() > 0) { + + afb.addType("fact", auxFact); + afb.addRule("step " + exclusiveGateway.getId() + "_branch" + + branchCounter + lhs + " => " + auxFact); + + branchCounter++; + } + } + + } else { + + // XOR-split + FlowElement predecessor = null; + + if (incoming.size() > 0) { + predecessor = incoming.get(0).getSourceRef(); + } else { + // ExclusiveGateway not reachable + return; + } + + String lhs = ""; + + if (predecessor instanceof Task) { + + String natVar = afb.addNatVar(); + + lhs += "(" + natVar + ") := done(task(" + predecessor.getId() + + "," + natVar + "))"; + + } else if (predecessor instanceof Gateway) { + + lhs += " := " + predecessor.getId() + "_to_" + + exclusiveGateway.getId(); + + } else if (predecessor instanceof StartEvent) { + + lhs += " := start_event_" + predecessor.getId(); + + } + + int branchCounter = 1; + for (SequenceFlow childFlow : exclusiveGateway.getOutgoing()) { + + final String auxFact = exclusiveGateway.getId() + "_to_" + + childFlow.getTargetRef().getId(); + + afb.addType("fact", auxFact); + afb.addRule("step " + exclusiveGateway.getId() + "_branch" + + branchCounter + lhs + " => " + auxFact); + + branchCounter++; + + } + } + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExportUtil.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExportUtil.java new file mode 100644 index 0000000..2738dea --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ExportUtil.java @@ -0,0 +1,160 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class contains utility methods that are being used in the ASLan export. + * + * + */ +public class ExportUtil { + + private static int permLevel = -1; + + /** + * Generates integer partitions in anti-lexicographic order using the + * algorithm ZS1 as described in Zoghbi, A. and Stojmenovic, I. + * "Fast Algorithms for Generating Integer Partitions", published in 1998. + * For each partition, the parts are provided in descending order. + * + * @param n + * The integer for which the partitions should be generated. + * @return A List containing the integer partitions, each represented as a + * integer Array. + */ + public static List generateIntegerPartitions(int n) { + + List res = new ArrayList(); + + int[] x = new int[n]; + + for (int i = 1; i <= n; i++) { + x[i - 1] = 1; + } + + x[0] = n; + int m = 1; + int h = 1; + + res.add(copySubarray(x, 0, 1)); + + while (x[0] != 1) { + + if (x[h - 1] == 2) { + m = m + 1; + x[h - 1] = 1; + h = h - 1; + } else { + int r = x[h - 1] - 1; + int t = m - h + 1; + x[h - 1] = r; + + while (t >= r) { + h = h + 1; + x[h - 1] = r; + t = t - r; + } + + if (t == 0) { + m = h; + } else { + m = h + 1; + + if (t > 1) { + h = h + 1; + x[h - 1] = t; + } + } + } + res.add(copySubarray(x, 0, m)); + } + + return res; + + } + + /** + * Copies a subarray of a given array and returns it. + * + * @param src + * The source array that should be used. + * @param start + * The start index. + * @param end + * The end index. + * @return A subarray of the source array, including the value at the start + * index and excluding the value at the end index. + */ + private static int[] copySubarray(int[] src, int start, int end) { + + int[] res = new int[end - start]; + int resPos = 0; + + for (int i = start; i < end; i++) { + res[resPos] = src[i]; + resPos++; + } + + return res; + } + + /** + * Generates all permutations of a sequence containing the numbers from 1 to + * n. + * + * @param n + * The upper bound of the permutations. + * @return A List with all permutations of the sequence. + */ + public static List generateLocationPermutations(int n) { + List res = new ArrayList(); + permLevel = -1; + + int[] value = new int[n]; + for (int i = 0; i < value.length; i++) { + value[i] = 0; + } + permVisit(value, n, 0, res); + + return res; + } + + /** + * Helper method for generating the integer sequence permutations. Should + * not be used on its own! + * + */ + private static void permVisit(int[] value, int n, int k, List res) { + permLevel = permLevel + 1; + value[k] = permLevel; + + if (permLevel == n) { + res.add(copySubarray(value, 0, value.length)); + } else { + for (int i = 0; i < n; i++) { + if (value[i] == 0) + permVisit(value, n, i, res); + } + } + permLevel = permLevel - 1; + value[k] = 0; + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ParallelGatewayExport.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ParallelGatewayExport.java new file mode 100644 index 0000000..9a5b552 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/ParallelGatewayExport.java @@ -0,0 +1,139 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.bpmn2.EndEvent; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; + +/** + * Creates the ASLan representation for a BPMN 2.0 ParallelGateway element. + * + */ +public class ParallelGatewayExport { + + /** + * Generates the ASLan representation of the provided ParallelGateway + * element and sends the output to the provided AslanFileBuilder. + * + * @param parallelGateway + * The ParallelGateway for which the representation should be + * generated. + * @param afb + * The AslanFileBuilder the output is sent to. + */ + public static void createParallelGatewayElements( + ParallelGateway parallelGateway, AslanFileBuilder afb) { + + final List incoming = parallelGateway.getIncoming(); + String rule = "step w_" + parallelGateway.getId(); + + if (incoming.size() > 0) { + + // AND-join, AND-split + String ruleDef = " := "; + + boolean firstDone = true; + List natVars = new ArrayList(); + for (SequenceFlow parentFlow : incoming) { + + final FlowElement predecessor = parentFlow.getSourceRef(); + + if (predecessor instanceof Task) { + + if (firstDone) { + firstDone = false; + } else { + ruleDef += ". "; + } + + String natVar = afb.addNatVar(); + + ruleDef += "done(task(" + predecessor.getId() + "," + + natVar + "))"; + natVars.add(natVar); + + } else if (predecessor instanceof Gateway) { + + if (firstDone) { + firstDone = false; + } else { + ruleDef += ". "; + } + + ruleDef += predecessor.getId() + "_to_" + + parallelGateway.getId(); + + } else if (predecessor instanceof StartEvent) { + + if (firstDone) { + firstDone = false; + } else { + ruleDef += ". "; + } + + ruleDef += "start_event_" + predecessor.getId(); + + } + } + + if (natVars.size() > 0) { + + rule += "("; + + for (int i = 0; i < natVars.size() - 1; i++) { + rule += natVars.get(i) + ","; + } + rule += natVars.get(natVars.size() - 1) + ")"; + + } + + rule += ruleDef + " => "; + + boolean firstAuxFact = true; + for (SequenceFlow childFlow : parallelGateway.getOutgoing()) { + + final FlowElement successor = childFlow.getTargetRef(); + + if (successor instanceof Task || successor instanceof Gateway + || successor instanceof EndEvent) { + + final String auxFact = parallelGateway.getId() + "_to_" + + successor.getId(); + afb.addType("fact", auxFact); + + if (firstAuxFact) { + rule += auxFact; + firstAuxFact = false; + } else { + rule += ". " + auxFact; + } + } + } + + afb.addRule(rule); + + } + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/SeparationOfDutyExport.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/SeparationOfDutyExport.java new file mode 100644 index 0000000..aa9fcab --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/SeparationOfDutyExport.java @@ -0,0 +1,216 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.Permission; +import org.eclipse.securebpmn2.SeparationOfDuty; + +/** + * Creates the ASLan representation of a SecureBPMN SeparationOfDuty element. + * + * + */ +public class SeparationOfDutyExport { + + /** + * Generates the ASLan representation of the provided SeparationOfDuty element + * and sends the output to the provided AslanFileBuilder. + * + * @param sod + * The SeparationOfDuty element for which the representation should + * be generated. + * @param afb + * The AslanFileBuilder the output is sent to. + */ + public static void createSeparationOfDutyElements(SeparationOfDuty sod, AslanFileBuilder afb) { + + if (sod.isDynamicEnforcement()) return; + + List assignTasks = new ArrayList(); + List claimTasks = new ArrayList(); + List completeTasks = new ArrayList(); + + for (Permission p : sod.getPermissions()) { + + if (p.getActions().size() == 0) { + System.err.println("[WARNING] The permission with name=\"" + p.getPName() + "\" and id=\"" + p.getId() + "\" has no action. This should never happen! Check your .activiti diagram file."); + continue; + } + + // Permissions only have one Action + if (p.getActions().get(0) instanceof ActivityAction) { + ActivityAction a = (ActivityAction) p.getActions().get(0); + + if (a.getActionName().equals("Complete")) { + + completeTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Claim")) { + + claimTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Assign")) { + + assignTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Full Access")) { + + assignTasks.add(a.getActivity().getId()); + claimTasks.add(a.getActivity().getId()); + completeTasks.add(a.getActivity().getId()); + + } + + } + } + + if (assignTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (claimTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (completeTasks.size() > 1) { + // safe default assumptions + int minUsers = completeTasks.size(); + int maxActions = 1; + + if (sod.getMinimumUsers() == null) { + System.out.println("[SCVM-EXPORT-ASLAN] minimum users for SoD \"" + sod.getId() + "\" not set, using " + minUsers + "."); + } else { + if (sod.getMinimumUsers() > completeTasks.size() || sod.getMinimumUsers() < 1) { + System.err.println("[SCVM-EXPORT-ASLAN] invalid input for minimum users at SoD \"" + sod.getId() + "\", using " + minUsers + "."); + } else { + minUsers = sod.getMinimumUsers(); + } + } + + if (sod.getMaxUserActionsPermitted() == null) { + System.out.println("[SCVM-EXPORT-ASLAN] maximum permitted actions for SoD \"" + sod.getId() + "\" not set, using " + maxActions + "."); + } else { + if (sod.getMaxUserActionsPermitted() < 1) { + System.err.println("[SCVM-EXPORT-ASLAN] invalid input for maximum permitted actions at SoD \"" + sod.getId() + "\", using " + maxActions + "."); + } else { + maxActions = sod.getMaxUserActionsPermitted(); + } + } + + // calculate numeric partitions + final List allPartitions = ExportUtil.generateIntegerPartitions(completeTasks.size()); + + // select invalid partitions + List selectedPartitions = new ArrayList(); + for (int[] part : allPartitions) { + if (part.length > 0 && (part.length < minUsers + || part[0] > maxActions)) { + selectedPartitions.add(part); + } + } + + // create goals for partitions + String[] tasks = new String[completeTasks.size()]; + for (int i = 0; i < completeTasks.size(); i++) { + tasks[i] = completeTasks.get(i); + } + List permList = ExportUtil.generateLocationPermutations(tasks.length); + + for (int[] part : selectedPartitions) { + // we assume that tasks.lengh equals the sum of each partition + List>> sets = new ArrayList>>(); + + // loop over index permutations + for (int[] perm : permList) { + int indexStart = 0; + // list of sets (parts of the partition) for the current permutation + List> setList = new ArrayList>(); + // create the sets + for (int partLength : part) { + Set partTasks = new HashSet(); + // get the tasks and add them to the set + for (int i = 0; i < partLength; i++) { + partTasks.add(tasks[perm[indexStart + i]-1]); + } + indexStart += partLength; + setList.add(partTasks); + } + // check if partition config already exists + boolean newSet = true; + for (List> presentSetList : sets) { + if (presentSetList.equals(setList)) { + newSet = false; + break; + } + } + // add partition config if new + if (newSet) { + sets.add(setList); + } + + } + + // create goals for this partition + for (List> setArray : sets) { + // generate goal + int numUsers = setArray.size(); + int numTasks = tasks.length; + List natVars = new ArrayList(); + StringBuilder goalString = new StringBuilder(); + goalString.append("("); + + // generate user variables + for (int i = 0; i < numUsers; i++) { + afb.addType("user", "U" + i); + if (i > 0) goalString.append(","); + goalString.append("U" + i); + } + + // generate task nat variables + for (int i = 0; i < numTasks; i++) { + String currentVar = afb.addNatVar(); + natVars.add(currentVar); + goalString.append("," + currentVar); + } + + goalString.append("):="); + + // generate facts + int natVarPos = 0; + for (int i = 0; i < numUsers; i++) { + for (String currentTask : setArray.get(i)) { + goalString.append(" executed(U" + i + ",task(" + currentTask + "," + natVars.get(natVarPos) + "))."); + natVarPos++; + } + } + + // add goal + String finalGoalString = goalString.toString(); + afb.addGoal("sod_" + sod.getId() + "_", finalGoalString.substring(0, finalGoalString.length()-1)); + } + } + + } + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/TaskExport.java b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/TaskExport.java new file mode 100644 index 0000000..9134dda --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.aslan/src/main/java/eu/aniketos/securebpmn/export/aslan/export/TaskExport.java @@ -0,0 +1,126 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.aslan.export; + +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.util.preferences.Preferences; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.Permission; +import org.eclipse.securebpmn2.Role; + +/** + * Creates the ASLan representation of a BPMN 2.0 Task element. + * + */ +public class TaskExport { + + /** + * Generates the ASLan representation of the provided Task element and sends + * the output to the provided AslanFileBuilder. + * + * @param task + * The Task element for which the representation should be + * generated. + * @param afb + * The AslanFileBuilder the output is sent to. + */ + public static void createTaskElements(Task task, AslanFileBuilder afb) { + // task_to_data assignments + afb.addTaskType(task); + + final String taskID = task.getId(); + + afb.addType("set", "in_" + taskID); + afb.addType("set", "out_" + taskID); + afb.addInit("task_to_data(" + taskID + ",in_" + taskID + ",out_" + + taskID + ")"); + + boolean isHumanTask = false; + + if (task instanceof UserTask + || PreferencesUtil + .getBooleanPreference(Preferences.ALL_TASKS_AS_HUMANTASKS)) + isHumanTask = true; + + if (isHumanTask) { + + // SecureBPMN RBAC + for (ActivityAction a : task.getActivityActions()) { + if (a.getActionName() != null + && (a.getActionName().equals("Assign") || a + .getActionName().equals("Full Access"))) { + + for (Permission p : a.getPermissions()) { + for (Role r : p.getRoles()) { + + afb.addHornClause("hc poto_" + taskID + ":= poto(" + + r.getName().toLowerCase() + "," + taskID + + ")"); + + } + } + + } + } + } + + // control flow + if (task.getIncoming().size() == 0) { + // no predecessor, ignore + return; + } + + String rule = "step w_" + taskID + "("; + String natVar1 = afb.addNatVar(); + + final FlowElement predecessor = task.getIncoming().get(0) + .getSourceRef(); + + if (predecessor instanceof Task) { + + String natVar2 = afb.addNatVar(); + + // sequence: Task to Task + rule += natVar2 + "," + natVar1 + ") := done(task(" + + predecessor.getId() + "," + natVar2 + "))"; + + } else if (predecessor instanceof Gateway) { + + // AND-split, AND-join, XOR-split, XOR-join + rule += natVar1 + ") := " + predecessor.getId() + "_to_" + taskID; + + } else if (predecessor instanceof StartEvent) { + + // sequence: StartEvent to Task + rule += natVar1 + ") := start_event_" + predecessor.getId(); + + } else { + // predecessor is a not supported FlowElement + return; + } + + rule += "=[exists " + natVar1 + "] => ready(task(" + taskID + "," + + natVar1 + "))"; + + afb.addRule(rule); + } + +} diff --git a/src/eu.aniketos.securebpmn.export.html/META-INF/MANIFEST.MF b/src/eu.aniketos.securebpmn.export.html/META-INF/MANIFEST.MF new file mode 100644 index 0000000..b486dd3 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - SecureBPMN: HTML Export +Bundle-SymbolicName: eu.aniketos.securebpmn.export.html;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: eu.aniketos.securebpmn.export.html.bundle.Activator +Bundle-Vendor: SAP SE +Require-Bundle: org.eclipse.core.runtime, + org.activiti.designer.eclipse, + org.activiti.designer.model, + org.eclipse.emf, + org.eclipse.graphiti.mm, + org.eclipse.graphiti.ui, + org.eclipse.core.resources, + org.eclipse.gef +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: ., + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + com.sun.xacml-0.1.jar, + jdi.jar, + jdimodel.jar, + junit.jar diff --git a/src/eu.aniketos.securebpmn.export.html/plugin.xml b/src/eu.aniketos.securebpmn.export.html/plugin.xml new file mode 100644 index 0000000..d08adc9 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/plugin.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/src/eu.aniketos.securebpmn.export.html/pom.xml b/src/eu.aniketos.securebpmn.export.html/pom.xml new file mode 100644 index 0000000..7cb6d3c --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + eu.aniketos.securebpmn.export.html + eclipse-plugin + Activiti Designer - SecureBPMN: HTML Export + diff --git a/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/bundle/Activator.java b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/bundle/Activator.java new file mode 100644 index 0000000..2646fa1 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/bundle/Activator.java @@ -0,0 +1,58 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.html.bundle; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + * + */ +public class Activator implements BundleActivator { + + // The plug-in ID + public static final String PLUGIN_ID = "eu.aniketos.securebpmn.export.html"; //$NON-NLS-1$ + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlExportMarshaller.java b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlExportMarshaller.java new file mode 100644 index 0000000..317a647 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlExportMarshaller.java @@ -0,0 +1,239 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.html.export; + +import java.util.ArrayList; +import java.util.List; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.export.AbstractExportMarshaller; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.bpmn2.Process; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.SubProcess; + +/** + * Exports an HTML representation of the diagram being saved to the workspace. + * + * @since 0.5.7 + * @version 1 + * + */ +public class HtmlExportMarshaller extends AbstractExportMarshaller { + + private static final String FILENAME_PATTERN = ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION + + ".html"; + + private IProgressMonitor monitor; + private Diagram diagram; + + public HtmlExportMarshaller() { + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * getMarshallerName() + */ + @Override + public String getMarshallerName() { + return ActivitiBPMNDiagramConstants.HTML_MARSHALLER_NAME; + } + + /* + * (non-Javadoc) + * + * @see + * org.activiti.designer.eclipse.extension.export.ExportMarshaller#getFormatName + * () + */ + @Override + public String getFormatName() { + return "SecureBPMN: HTML"; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * marshallDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void marshallDiagram(Diagram diagram, IProgressMonitor monitor) { + + this.monitor = monitor; + this.diagram = diagram; + + this.monitor.beginTask("Exporting to HTML", 100); + + // Clear problems for this marshaller first + clearMarkers(getResource(diagram.eResource().getURI())); + + this.monitor.worked(10); + + marshallHtml(); + + this.monitor.worked(90); + + this.monitor.done(); + + } + + /** + * Initializes and controls the HTML file generation. + */ + private void marshallHtml() { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(baos, "UTF-8"); + Writer out = new BufferedWriter(osw); + + final EList contents = diagram.eResource().getContents(); + + Process process = null; + + boolean found = false; + List flowElements = new ArrayList(); + for (final EObject eObject : contents) { + if (eObject instanceof Process && !found) { + process = (Process) eObject; + found = true; + } + if (eObject instanceof FlowElement) + flowElements.add((FlowElement) eObject); + } + + if (process == null) { + addProblemToDiagram(diagram, "Process cannot be null", null); + } + + HtmlWriter hw = new HtmlWriter(out); + + hw.writeStartDocument(); + hw.writeHead(process.getName()); + hw.writeStartBody(); + + hw.writeHeading(process.getName(), 1); + + createHtml(flowElements, hw, ""); + + hw.writeEndBody(); + hw.writeEndDocument(); + out.flush(); + + final byte[] bytes = baos.toByteArray(); + final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + saveResource(getRelativeURIForDiagram(diagram, FILENAME_PATTERN), + bais, new NullProgressMonitor()); + } catch (Exception e) { + e.printStackTrace(); + addProblemToDiagram( + diagram, + "An exception occurred while creating the HTML: " + + e.getMessage(), null); + } + + } + + /** + * Creates the actual HTML output for a given (Sub)Process. + * + * @param flowElements + * The list of flow elements that should be included in the HTML + * file. + * @param hw + * The HtmlWriter to which the output is sent. + * @param subProcessID + * The ID of the SubProcess, if the function is used for one. + * Provide an empty String otherwise. + * @throws IOException + * Any IOException that might occur during usage of the + * HtmlWriter. + */ + private void createHtml(List flowElements, HtmlWriter hw, + String subProcessID) throws IOException { + if (subProcessID != "") { + hw.writeHorizontalRule(); + hw.writeHeading("FlowElements of " + subProcessID, 2); + } + + hw.writeStartTable(); + hw.writeStartTableRow(); + hw.writeTableHeadingCell("type"); + hw.writeTableHeadingCell("id"); + hw.writeTableHeadingCell("name"); + hw.writeTableHeadingCell("properties"); + hw.writeEndTableRow(); + + List subProcesses = new ArrayList(); + + for (final FlowElement flowElement : flowElements) { + + String type = flowElement.getClass().getName(); + if (type.lastIndexOf('.') > 0) { + type = type.substring(type.lastIndexOf('.') + 1); // trim to + // unqualified + // name + } + type = type.substring(0, type.length() - 4); // cut out "Impl" + + hw.writeStartTableRow(); + + hw.writeTableCell(type); + if (subProcessID.length() > 0) { + hw.writeTableCell(subProcessID + "/" + flowElement.getId()); + } else { + hw.writeTableCell(flowElement.getId()); + } + + if (flowElement.getName().length() > 0) { + hw.writeTableCell(flowElement.getName()); + } else { + hw.writeTableCell(" "); + } + + hw.writeTableCell(PropertiesStringBuilder.create(flowElement)); + + hw.writeEndTableRow(); + + if (flowElement instanceof SubProcess) + subProcesses.add((SubProcess) flowElement); + } + + hw.writeEndTable(); + + if (subProcesses.size() > 0) { + for (final SubProcess sp : subProcesses) { + createHtml(sp.getFlowElements(), hw, sp.getId()); + } + } + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlWriter.java b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlWriter.java new file mode 100644 index 0000000..4ff4022 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/HtmlWriter.java @@ -0,0 +1,222 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.html.export; + +import java.io.IOException; +import java.io.Writer; + +/** + * Writes Process information in HTML format using a Writer. + * + */ +public class HtmlWriter { + + private Writer writer; + private boolean coloredRowsEnabled = true; + private boolean colorRow = false; + + HtmlWriter(Writer writer) { + this.writer = writer; + } + + /** + * Returns if the output will contain colored rows. + * + * @return The current setting for colored rows. + */ + public boolean isColoredRowsEnabled() { + return coloredRowsEnabled; + } + + /** + * Sets if the output will contain colored rows. + * + * @param coloredRowsEnabled + * true if the output should contain colored rows, false if it + * shoud not. + */ + public void setColoredRowsEnabled(boolean coloredRowsEnabled) { + this.coloredRowsEnabled = coloredRowsEnabled; + } + + // HTML Element + + /** + * Writes the start of an HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeStartDocument() throws IOException { + writer.write("\n"); + writer.write("\n"); + } + + /** + * Writes the end of an HTML file, i.e., the closing HTML tag. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeEndDocument() throws IOException { + writer.write(""); + } + + // HEAD Element + + /** + * Writes the HEAD tag of the HTML file. + * + * @param documentTitle + * The title that should be used for the file. + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeHead(String documentTitle) throws IOException { + writer.write("\n"); + writer.write("" + documentTitle + "\n"); + writer.write("\n"); + writer.write("\n"); + writer.write("\n"); + } + + // BODY Element + + /** + * Writes the opening BODY tag of the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeStartBody() throws IOException { + writer.write("\n"); + } + + /** + * Writes the closing BODY tag of the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeEndBody() throws IOException { + writer.write("\n"); + } + + // TABLE, TR, TD, TH Elements + + /** + * Writes an opening TABLE tag to the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeStartTable() throws IOException { + writer.write("\n"); + } + + /** + * Writes an closing TABLE tag to the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeEndTable() throws IOException { + writer.write("
    \n"); + } + + /** + * Writes an opening TR tag to the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeStartTableRow() throws IOException { + writer.write("\t\n"); + } + + /** + * Writes an closing TR tag to the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeEndTableRow() throws IOException { + writer.write("\t\n"); + if (coloredRowsEnabled) + colorRow = !colorRow; + } + + /** + * Writes a table cell, i.e., the TD tag to the HTML file. + * + * @param content + * The content that is written in the table cell. + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeTableCell(String content) throws IOException { + if (coloredRowsEnabled && colorRow) { + writer.write("\t\t" + content + "\n"); + } else { + writer.write("\t\t" + content + "\n"); + } + } + + /** + * Writes a table heading cell, i.e., the TH tag to the HTML file. + * + * @param content + * The content that is written in the heading cell. + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeTableHeadingCell(String content) throws IOException { + writer.write("\t\t" + content + "\n"); + } + + // H1, H2, H3 Elements + + /** + * Writes a text heading, i.e., the H1, H2 or H3 tag to the HTML file. + * + * @param content + * The content that is written as the heading. + * @param headingNr + * 1, 2 or 3, depending on the level of the heading you want. + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeHeading(String content, int headingNr) throws IOException { + if (headingNr < 1 || headingNr > 3) + return; + writer.write("" + content + "\n"); + } + + // HR Element + + /** + * Writes a horizontal rule, i.e., the HR tag to the HTML file. + * + * @throws IOException + * IOException that might occur using the writer. + */ + public void writeHorizontalRule() throws IOException { + writer.write("


    \n"); + } + +} diff --git a/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/PropertiesStringBuilder.java b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/PropertiesStringBuilder.java new file mode 100644 index 0000000..9386c32 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.html/src/main/java/eu/aniketos/securebpmn/export/html/export/PropertiesStringBuilder.java @@ -0,0 +1,569 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.html.export; + +import java.util.List; + +import org.eclipse.bpmn2.BoundaryEvent; +import org.eclipse.bpmn2.BusinessRuleTask; +import org.eclipse.bpmn2.CallActivity; +import org.eclipse.bpmn2.CandidateGroup; +import org.eclipse.bpmn2.CandidateUser; +import org.eclipse.bpmn2.Documentation; +import org.eclipse.bpmn2.EndEvent; +import org.eclipse.bpmn2.ErrorEventDefinition; +import org.eclipse.bpmn2.EventDefinition; +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.FormalExpression; +import org.eclipse.bpmn2.IOParameter; +import org.eclipse.bpmn2.MailTask; +import org.eclipse.bpmn2.ScriptTask; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.TimerEventDefinition; +import org.eclipse.bpmn2.UserTask; + +/** + * Helper class for creating the HTML property string for a given FlowElement. + * + */ +public class PropertiesStringBuilder { + + /** + * Creates the HTML properties string for a given FlowElement. + * + * @param flowElement + * The FlowElement for which the properties should be written to + * a string. + * @return The properties of the given FlowElement represented as a String. + */ + public static String create(FlowElement flowElement) { + if (flowElement instanceof SequenceFlow) { + return createSequenceFlowString((SequenceFlow) flowElement); + } else if (flowElement instanceof StartEvent) { + return createStartEventString((StartEvent) flowElement); + } else if (flowElement instanceof EndEvent) { + return createEndEventString((EndEvent) flowElement); + } else if (flowElement instanceof UserTask) { + return createUserTaskString((UserTask) flowElement); + } else if (flowElement instanceof ScriptTask) { + return createScriptTaskString((ScriptTask) flowElement); + } else if (flowElement instanceof ServiceTask) { + return createServiceTaskString((ServiceTask) flowElement); + } else if (flowElement instanceof MailTask) { + return createMailTaskString((MailTask) flowElement); + } else if (flowElement instanceof ExclusiveGateway) { + return createExclusiveGatewayString((ExclusiveGateway) flowElement); + } else if (flowElement instanceof BusinessRuleTask) { + return createBusinessRuleTaskString((BusinessRuleTask) flowElement); + } else if (flowElement instanceof CallActivity) { + return createCallActivityString((CallActivity) flowElement); + } else if (flowElement instanceof BoundaryEvent) { + return createBoundaryEventString((BoundaryEvent) flowElement); + } else { + return " "; + } + } + + /** + * Writes the source ID, target ID and condition expression of a + * SequenceFlow to a String. + * + * @param sequenceFlow + * The SequenceFlow for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createSequenceFlowString(SequenceFlow sequenceFlow) { + String res = "source ID: " + sequenceFlow.getSourceRef().getId() + + "
    target ID: " + sequenceFlow.getTargetRef().getId(); + + if (sequenceFlow.getConditionExpression() != null) { + res += "
    condition: " + + sequenceFlow.getConditionExpression().getBody(); + } + return res; + } + + /** + * Writes the initiator and the form key of a StartEvent to a String. + * Additionally, for a TimerStartEvent the String contains the time + * duration, time date and the time cycle. + * + * @param startEvent + * The StartEvent for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createStartEventString(StartEvent startEvent) { + boolean first = true; + String res = ""; + + if (startEvent.getInitiator() != null + && startEvent.getInitiator().length() > 0) { + res += "initiator: " + startEvent.getInitiator(); + first = false; + } + + if (startEvent.getFormKey() != null + && startEvent.getFormKey().length() > 0) { + if (!first) + res += "
    "; + res += "form key: " + startEvent.getFormKey(); + if (first) + first = false; + } + + if (startEvent.getEventDefinitions().size() > 0) { + TimerEventDefinition timerDef = (TimerEventDefinition) startEvent + .getEventDefinitions().get(0); + + if (timerDef.getTimeDuration() != null + && (((FormalExpression) timerDef.getTimeDuration()) + .getBody() != null && ((FormalExpression) timerDef + .getTimeDuration()).getBody().length() > 0)) { + + if (!first) + res += "
    "; + res += "time duration: " + + ((FormalExpression) timerDef.getTimeDuration()) + .getBody(); + + } else if (((FormalExpression) timerDef.getTimeDate()).getBody() != null + && ((FormalExpression) timerDef.getTimeDate()).getBody() + .length() > 0) { + + if (!first) + res += "
    "; + res += "time date: " + + ((FormalExpression) timerDef.getTimeDate()).getBody(); + + } else if (((FormalExpression) timerDef.getTimeCycle()).getBody() != null + && ((FormalExpression) timerDef.getTimeCycle()).getBody() + .length() > 0) { + + if (!first) + res += "
    "; + res += "time cycle: " + + ((FormalExpression) timerDef.getTimeCycle()) + .getBody(); + + } + } + + if (res == "") + res = " "; + return res; + } + + /** + * Writes the error code of an EndEvent to a String. + * + * @param endEvent + * The EndEvent for which the String should be generated. + * @return The property represented as a String. + */ + public static String createEndEventString(EndEvent endEvent) { + if (endEvent.getEventDefinitions().size() > 0) { + ErrorEventDefinition errorDef = (ErrorEventDefinition) endEvent + .getEventDefinitions().get(0); + if (errorDef.getErrorCode() != null + && errorDef.getErrorCode().length() > 0) { + + return "error code: " + errorDef.getErrorCode(); + + } + } + + return " "; + } + + /** + * Writes the assignee/candidate groups/candidate users, form key, due date, + * priority and documentation of a UserTask to a String. + * + * @param userTask + * The UserTask for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createUserTaskString(UserTask userTask) { + boolean first = true; + String res = ""; + + if (userTask.getAssignee() != null + && userTask.getAssignee().length() > 0) { + res += "assignee: " + userTask.getAssignee(); + first = false; + + } else if (userTask.getCandidateUsers() != null + && userTask.getCandidateUsers().size() > 0) { + res += "candidate groups: "; + boolean firstInGroup = true; + + for (CandidateGroup candidateGroup : userTask.getCandidateGroups()) { + if (firstInGroup) { + res += candidateGroup.getGroup(); + firstInGroup = false; + } else { + res += ", " + candidateGroup.getGroup(); + } + } + first = false; + + } else if (userTask.getCandidateGroups() != null + && userTask.getCandidateGroups().size() > 0) { + res += "candidate users: "; + boolean firstInGroup = true; + + for (CandidateUser candidateUser : userTask.getCandidateUsers()) { + if (firstInGroup) { + res += candidateUser.getUser(); + firstInGroup = false; + } else { + res += ", " + candidateUser.getUser(); + } + } + first = false; + } + + if (userTask.getFormKey() != null && userTask.getFormKey().length() > 0) { + if (!first) + res += "
    "; + res += "form key: " + userTask.getFormKey(); + first = false; + } + + if (userTask.getDueDate() != null && userTask.getDueDate().length() > 0) { + if (!first) + res += "
    "; + res += "due date: " + userTask.getDueDate(); + first = false; + } + + if (userTask.getPriority() != null) { + if (!first) + res += "
    "; + res += "priority: " + userTask.getPriority(); + first = false; + } + + if (userTask.getDocumentation() != null + && userTask.getDocumentation().size() > 0) { + if (!first) + res += "
    "; + + final Documentation documentation = userTask.getDocumentation() + .get(0); + + if (documentation.getText() != null + && !"".equals(documentation.getText())) { + res += "documentation: " + documentation.getText(); + } + } + + if (res == "") + res = " "; + return res; + } + + /** + * Writes the script language and the script itself of a ScriptTask to a + * String. + * + * @param scriptTask + * The ScriptTask for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createScriptTaskString(ScriptTask scriptTask) { + + return "language: " + scriptTask.getScriptFormat() + "
    script: " + + scriptTask.getScript(); + } + + /** + * Writes the result variable, type and service class/expression/delegate + * expression of a ServiceTask to a String + * + * @param serviceTask + * The ServiceTask for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createServiceTaskString(ServiceTask serviceTask) { + String res = ""; + + res += "type: " + serviceTask.getImplementationType(); + + if (serviceTask.getImplementation() != null + && serviceTask.getImplementation().length() > 0) { + if (serviceTask.getImplementationType().equals( + "delegateExpressionType")) { + res += "
    delegate expression: "; + } else if (serviceTask.getImplementationType().equals( + "expressionType")) { + res += "
    expression: "; + } else { + res += "
    java class: "; + } + res += serviceTask.getImplementation(); + } + + if (serviceTask.getResultVariableName() != null + && serviceTask.getResultVariableName().length() > 0) { + res += "
    result variable: " + + serviceTask.getResultVariableName(); + } + + if (res == "") + res = " "; + return res; + } + + /** + * Writes the to, from, subject, cc, bcc, text and html text properties of a + * MailTask to a String. + * + * @param mailTask + * The MailTask for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createMailTaskString(MailTask mailTask) { + String res = ""; + + if (mailTask.getTo() != null && mailTask.getFrom() != null) + res += "to: " + mailTask.getTo() + "
    from: " + + mailTask.getFrom(); + + if (mailTask.getSubject() != null && mailTask.getSubject().length() > 0) + res += "
    subject: " + mailTask.getSubject(); + + if (mailTask.getCc() != null && mailTask.getCc().length() > 0) + res += "
    cc: " + mailTask.getCc(); + + if (mailTask.getBcc() != null && mailTask.getBcc().length() > 0) + res += "
    bcc: " + mailTask.getBcc(); + + if (mailTask.getText() != null && mailTask.getHtml() != null) + res += "
    text: " + mailTask.getText() + "
    html text: " + + mailTask.getHtml(); + + return res; + } + + /** + * Writes the rule names, input variables, excluded and result variable + * properties of a BusinessRuleTask to a String. + * + * @param businessRuleTask + * The BusinessRuleTask for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createBusinessRuleTaskString( + BusinessRuleTask businessRuleTask) { + String res = ""; + boolean first = true; + + if (businessRuleTask.getRuleNames().size() > 0) { + StringBuilder ruleNameBuilder = new StringBuilder(); + for (String ruleName : businessRuleTask.getRuleNames()) { + if (ruleNameBuilder.length() > 0) { + ruleNameBuilder.append(","); + } + ruleNameBuilder.append(ruleName); + } + res += "rules: " + ruleNameBuilder.toString(); + first = false; + } + + if (businessRuleTask.getInputVariables().size() > 0) { + StringBuilder inputBuilder = new StringBuilder(); + for (String input : businessRuleTask.getInputVariables()) { + if (inputBuilder.length() > 0) { + inputBuilder.append(","); + } + inputBuilder.append(input); + } + if (!first) + res += "
    "; + res += "input variables: " + inputBuilder.toString(); + if (first) + first = false; + } + + if (businessRuleTask.getRuleNames().size() > 0) { + if (!first) + res += "
    "; + res += "excluded: " + businessRuleTask.isExclude(); + if (first) + first = false; + } + + if (businessRuleTask.getResultVariableName() != null + && businessRuleTask.getResultVariableName().length() > 0) { + if (!first) + res += "
    "; + res += "result variable: " + + businessRuleTask.getResultVariableName(); + } + + return res; + } + + /** + * Writes the called element, input parameters and output parameters of a + * CallActivity to a String. + * + * @param callActivity + * The CallActivity for which the String should be generated. + * @return The properties represented as a String. + */ + public static String createCallActivityString(CallActivity callActivity) { + String res = ""; + boolean first = true; + + if (callActivity.getCalledElement() != null + && callActivity.getCalledElement().length() > 0) { + res += "called element: " + callActivity.getCalledElement(); + first = false; + } + + if (callActivity.getInParameters().size() > 0) { + if (!first) + res += "
    "; + res += "input parameters: "; + boolean firstLine = true; + for (IOParameter param : callActivity.getInParameters()) { + if (!firstLine) + res += "
    "; + res += "source=" + param.getSource() + ", target=" + + param.getTarget(); + if (firstLine) + firstLine = false; + } + if (first) + first = false; + } + + if (callActivity.getOutParameters().size() > 0) { + if (!first) + res += "
    "; + res += "output parameters: "; + boolean firstLine = true; + for (IOParameter param : callActivity.getOutParameters()) { + if (!firstLine) + res += "
    "; + res += "source=" + param.getSource() + ", target=" + + param.getTarget(); + if (firstLine) + firstLine = false; + } + } + + if (res == "") + res = " "; + return res; + } + + /** + * Writes the default flow of an ExclusiveGateway to a String. + * + * @param exclusiveGateway + * The ExclusiveGateway for which the String should be generated. + * @return The property represented as a String. + */ + public static String createExclusiveGatewayString( + ExclusiveGateway exclusiveGateway) { + if (exclusiveGateway.getDefault() != null) + return "default flow ID: " + exclusiveGateway.getDefault().getId(); + else + return " "; + } + + /** + * Writes the cancel activity, time duration, time date and time cycle for a + * TimerBoundaryEvent or the error code for a ErrorBoundaryEvent to a + * String. + * + * @param boundaryEvent + * The BoundaryEvent for which the String should be generated. + * @return The propertie(s) represented as a String. + */ + public static String createBoundaryEventString(BoundaryEvent boundaryEvent) { + String res = ""; + + List eventDefinitionList = boundaryEvent + .getEventDefinitions(); + if (eventDefinitionList.size() == 1) { + if (eventDefinitionList.get(0) instanceof TimerEventDefinition) { + TimerEventDefinition timerDef = (TimerEventDefinition) eventDefinitionList + .get(0); + + // start TimerBoundaryEvent element + if (boundaryEvent.isCancelActivity()) { + res += "cancel activity: true"; + } else { + res += "cancel activity: false"; + } + + if (timerDef.getTimeDuration() != null + && (((FormalExpression) timerDef.getTimeDuration()) + .getBody() != null && ((FormalExpression) timerDef + .getTimeDuration()).getBody().length() > 0)) { + + res += "
    time duration: " + + ((FormalExpression) timerDef.getTimeDuration()) + .getBody(); + + } else if (((FormalExpression) timerDef.getTimeDate()) + .getBody() != null + && ((FormalExpression) timerDef.getTimeDate()) + .getBody().length() > 0) { + + res += "
    time date: " + + ((FormalExpression) timerDef.getTimeDate()) + .getBody(); + + } else if (((FormalExpression) timerDef.getTimeCycle()) + .getBody() != null + && ((FormalExpression) timerDef.getTimeCycle()) + .getBody().length() > 0) { + + res += "
    time cycle: " + + ((FormalExpression) timerDef.getTimeCycle()) + .getBody(); + + } + // end TimerBoundaryEvent element + + } else if (eventDefinitionList.get(0) instanceof ErrorEventDefinition) { + ErrorEventDefinition errorDef = (ErrorEventDefinition) eventDefinitionList + .get(0); + + // start ErrorBoundaryEvent element + if (errorDef.getErrorCode() != null + && errorDef.getErrorCode().length() > 0) { + + res += "error code: " + errorDef.getErrorCode(); + + } + // end ErrorBoundaryEvent element + } + } + if (res == "") + res = " "; + return res; + } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/META-INF/MANIFEST.MF b/src/eu.aniketos.securebpmn.export.xacml/META-INF/MANIFEST.MF new file mode 100644 index 0000000..9046870 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/META-INF/MANIFEST.MF @@ -0,0 +1,27 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - SecureBPMN: XACML Export +Bundle-SymbolicName: eu.aniketos.securebpmn.export.xacml;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: eu.aniketos.securebpmn.export.xacml.bundle.Activator +Bundle-Vendor: SAP SE +Require-Bundle: org.eclipse.core.runtime, + org.activiti.designer.eclipse, + org.activiti.designer.model, + org.activiti.designer.gui, + org.eclipse.emf, + org.eclipse.graphiti.mm, + org.eclipse.graphiti.ui, + org.eclipse.core.resources +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Import-Package: eu.aniketos.securebpmn.util, + org.activiti.designer.util.preferences +Bundle-ClassPath: ., + com.sun.xacml-0.1.jar, + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + jdi.jar, + jdimodel.jar, + junit.jar diff --git a/src/eu.aniketos.securebpmn.export.xacml/build.properties b/src/eu.aniketos.securebpmn.export.xacml/build.properties new file mode 100644 index 0000000..32cc241 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java/ +bin.includes = META-INF/,\ + plugin.xml,\ + . + diff --git a/src/eu.aniketos.securebpmn.export.xacml/plugin.xml b/src/eu.aniketos.securebpmn.export.xacml/plugin.xml new file mode 100644 index 0000000..b8175a5 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/plugin.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/eu.aniketos.securebpmn.export.xacml/pom.xml b/src/eu.aniketos.securebpmn.export.xacml/pom.xml new file mode 100644 index 0000000..84664d0 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + eu.aniketos.securebpmn.export.xacml + eclipse-plugin + Activiti Designer - SecureBPMN: XACML Export + + + com.sun.xacml + com.sun.xacml + 0.1 + + + diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/bundle/Activator.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/bundle/Activator.java new file mode 100644 index 0000000..2788bb1 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/bundle/Activator.java @@ -0,0 +1,56 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.bundle; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + * + */ +public class Activator implements BundleActivator { + // The plug-in ID + public static final String PLUGIN_ID = "eu.aniketos.securebpmn.export.xacml"; //$NON-NLS-1$ + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/BindingOfDutyExport.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/BindingOfDutyExport.java new file mode 100644 index 0000000..3cae883 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/BindingOfDutyExport.java @@ -0,0 +1,265 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.BindingOfDuty; +import org.eclipse.securebpmn2.Permission; + +/** + * Creates the ASLan representation of a SecureBPMN BindingOfDuty element. + * + * + */ +public class BindingOfDutyExport { +// +// /** +// * Generates the ASLan representation of the provided BindingOfDuty element +// * and sends the output to the provided AslanFileBuilder. +// * +// * @param bod +// * The BindingOfDuty element for which the representation should +// * be generated. +// * @param afb +// * The AslanFileBuilder the output is sent to. +// */ +// public static void createBindingOfDutyElements(BindingOfDuty bod, +// XacmlFileBuilder afb) { +// +// if (bod.isDynamicEnforcement()) +// return; +// +// List assignTasks = new ArrayList(); +// List claimTasks = new ArrayList(); +// List completeTasks = new ArrayList(); +// +// for (Permission p : bod.getPermissions()) { +// +// if (p.getActions().size() == 0) { +// System.err +// .println("[WARNING] The permission with name=\"" +// + p.getPName() +// + "\" and id=\"" +// + p.getId() +// + "\" has no action. This should never happen! Check your .activiti diagram file."); +// continue; +// } +// +// // Permissions only have one Action +// if (p.getActions().get(0) instanceof ActivityAction) { +// ActivityAction a = (ActivityAction) p.getActions().get(0); +// +// if (a.getActionName().equals("Complete")) { +// +// completeTasks.add(a.getActivity().getId()); +// +// } else if (a.getActionName().equals("Claim")) { +// +// claimTasks.add(a.getActivity().getId()); +// +// } else if (a.getActionName().equals("Assign")) { +// +// assignTasks.add(a.getActivity().getId()); +// +// } else if (a.getActionName().equals("Full Access")) { +// +// assignTasks.add(a.getActivity().getId()); +// claimTasks.add(a.getActivity().getId()); +// completeTasks.add(a.getActivity().getId()); +// +// } +// +// } +// } +// +// if (assignTasks.size() > 1) { +// // TODO what to check? only executed() is persistent... +// } +// +// if (claimTasks.size() > 1) { +// // TODO what to check? only executed() is persistent... +// } +// +// if (completeTasks.size() > 1) { +// // safe default assumptions +// int maxUsers = 1; +// int numActions = completeTasks.size(); +// +// if (bod.getMaxUsers() == null) { +// System.out +// .println("[SCVM-EXPORT-ASLAN] maximum users for BoD \"" +// + bod.getId() + "\" not set, using " + maxUsers +// + "."); +// } else { +// if (bod.getMaxUsers() < 1) { +// System.err +// .println("[SCVM-EXPORT-ASLAN] invalid input for maximum users at BoD \"" +// + bod.getId() +// + "\", using " +// + maxUsers +// + "."); +// } else { +// maxUsers = bod.getMaxUsers(); +// } +// } +// +// if (bod.getSameUserActionCount() == null) { +// System.out +// .println("[SCVM-EXPORT-ASLAN] number of actions for BoD \"" +// + bod.getId() +// + "\" not set, using " +// + numActions + "."); +// } else { +// if (bod.getSameUserActionCount() > completeTasks.size() +// || bod.getSameUserActionCount() < 1) { +// System.err +// .println("[SCVM-EXPORT-ASLAN] invalid input for number of actions at BoD \"" +// + bod.getId() +// + "\", using " +// + numActions +// + "."); +// } else { +// numActions = bod.getSameUserActionCount(); +// } +// } +// +// // calculate numeric partitions +// final List allPartitions = ExportUtil +// .generateIntegerPartitions(completeTasks.size()); +// +// // select invalid partitions +// List selectedPartitions = new ArrayList(); +// for (int[] part : allPartitions) { +// boolean invalidSummandFound = false; +// for (int i : part) { +// if (i != numActions) +// invalidSummandFound = true; +// } +// if (part.length > 0 +// && (part.length > maxUsers || invalidSummandFound)) { +// selectedPartitions.add(part); +// } +// } +// +// // create goals for partitions +// String[] tasks = new String[completeTasks.size()]; +// for (int i = 0; i < completeTasks.size(); i++) { +// tasks[i] = completeTasks.get(i); +// } +// List permList = ExportUtil +// .generateLocationPermutations(tasks.length); +// +// for (int[] part : selectedPartitions) { +// // we assume that tasks.lengh equals the sum of each partition +// List>> sets = new ArrayList>>(); +// +// // loop over index permutations +// for (int[] perm : permList) { +// int indexStart = 0; +// // list of sets (parts of the partition) for the current +// // permutation +// List> setList = new ArrayList>(); +// // create the sets +// for (int partLength : part) { +// Set partTasks = new HashSet(); +// // get the tasks and add them to the set +// for (int i = 0; i < partLength; i++) { +// partTasks.add(tasks[perm[indexStart + i] - 1]); +// } +// indexStart += partLength; +// setList.add(partTasks); +// } +// // check if partition config already exists +// boolean newSet = true; +// for (List> presentSetList : sets) { +// if (presentSetList.equals(setList)) { +// newSet = false; +// break; +// } +// } +// // add partition config if new +// if (newSet) { +// sets.add(setList); +// } +// +// } +// +// // create goals for this partition +// for (List> setArray : sets) { +// // generate goal +// int numUsers = setArray.size(); +// int numTasks = tasks.length; +// List natVars = new ArrayList(); +// StringBuilder goalString = new StringBuilder(); +// goalString.append("("); +// +// // generate user variables +// for (int i = 0; i < numUsers; i++) { +// afb.addType("user", "U" + i); +// if (i > 0) +// goalString.append(","); +// goalString.append("U" + i); +// } +// +// // generate task nat variables +// for (int i = 0; i < numTasks; i++) { +// String currentVar = afb.addNatVar(); +// natVars.add(currentVar); +// goalString.append("," + currentVar); +// } +// +// goalString.append("):="); +// +// // generate "executed" facts +// int natVarPos = 0; +// for (int i = 0; i < numUsers; i++) { +// for (String currentTask : setArray.get(i)) { +// goalString.append(" executed(U" + i + ",task(" +// + currentTask + "," +// + natVars.get(natVarPos) + "))."); +// natVarPos++; +// } +// } +// +// // generate "not equal" facts +// StringBuilder neqString = new StringBuilder(); +// for (int i = 0; i < numUsers - 1; i++) { +// for (int j = i + 1; j < numUsers; j++) { +// neqString.append("& not(equal(U" + i + ",U" + j +// + "))"); +// } +// } +// +// // add goal +// String finalGoalString = goalString.toString(); +// afb.addGoal( +// "bod_" + bod.getId() + "_", +// finalGoalString.substring(0, +// finalGoalString.length() - 1) +// + neqString.toString()); +// } +// } +// +// } +// +// } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExclusiveGatewayExport.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExclusiveGatewayExport.java new file mode 100644 index 0000000..a544c82 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExclusiveGatewayExport.java @@ -0,0 +1,145 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.util.List; + +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; + +/** + * Creates the ASLan representation for a BPMN 2.0 ExclusiveGateway element. + * + */ +public class ExclusiveGatewayExport { +// +// /** +// * Generates the ASLan representation of the provided ExclusiveGateway +// * element and sends the output to the provided AslanFileBuilder. +// * +// * @param exclusiveGateway +// * The ExclusiveGateway for which the representation should be +// * generated. +// * @param afb +// * The AslanFileBuilder the output is sent to. +// */ +// public static void createExclusiveGatewayElements( +// ExclusiveGateway exclusiveGateway, XacmlFileBuilder afb) { +// +// final List incoming = exclusiveGateway.getIncoming(); +// +// if (incoming.size() > 1) { +// +// // XOR-join +// final List outgoing = exclusiveGateway.getOutgoing(); +// +// FlowElement successor = null; +// String auxFact = ""; +// +// if (outgoing.size() > 0) { +// successor = outgoing.get(0).getTargetRef(); +// auxFact += exclusiveGateway.getId() + "_to_" +// + successor.getId(); +// } +// +// int branchCounter = 1; +// for (SequenceFlow parentFlow : incoming) { +// +// final FlowElement predecessor = parentFlow.getSourceRef(); +// +// String lhs = ""; +// +// if (predecessor instanceof Task) { +// +// String natVar = afb.addNatVar(); +// +// lhs += "(" + natVar + ") := done(task(" +// + predecessor.getId() + "," + natVar + "))"; +// +// } else if (predecessor instanceof Gateway) { +// +// lhs += " := " + predecessor.getId() + "_to_" +// + exclusiveGateway.getId(); +// +// } else if (predecessor instanceof StartEvent) { +// +// lhs += " := start_event_" + predecessor.getId(); +// +// } +// +// if (lhs.length() > 0) { +// +// afb.addType("fact", auxFact); +// afb.addRule("step " + exclusiveGateway.getId() + "_branch" +// + branchCounter + lhs + " => " + auxFact); +// +// branchCounter++; +// } +// } +// +// } else { +// +// // XOR-split +// FlowElement predecessor = null; +// +// if (incoming.size() > 0) { +// predecessor = incoming.get(0).getSourceRef(); +// } else { +// // ExclusiveGateway not reachable +// return; +// } +// +// String lhs = ""; +// +// if (predecessor instanceof Task) { +// +// String natVar = afb.addNatVar(); +// +// lhs += "(" + natVar + ") := done(task(" + predecessor.getId() +// + "," + natVar + "))"; +// +// } else if (predecessor instanceof Gateway) { +// +// lhs += " := " + predecessor.getId() + "_to_" +// + exclusiveGateway.getId(); +// +// } else if (predecessor instanceof StartEvent) { +// +// lhs += " := start_event_" + predecessor.getId(); +// +// } +// +// int branchCounter = 1; +// for (SequenceFlow childFlow : exclusiveGateway.getOutgoing()) { +// +// final String auxFact = exclusiveGateway.getId() + "_to_" +// + childFlow.getTargetRef().getId(); +// +// afb.addType("fact", auxFact); +// afb.addRule("step " + exclusiveGateway.getId() + "_branch" +// + branchCounter + lhs + " => " + auxFact); +// +// branchCounter++; +// +// } +// } +// } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExportUtil.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExportUtil.java new file mode 100644 index 0000000..5d19ac6 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ExportUtil.java @@ -0,0 +1,160 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class contains utility methods that are being used in the XACML export. + * + * + */ +public class ExportUtil { + + private static int permLevel = -1; + + /** + * Generates integer partitions in anti-lexicographic order using the + * algorithm ZS1 as described in Zoghbi, A. and Stojmenovic, I. + * "Fast Algorithms for Generating Integer Partitions", published in 1998. + * For each partition, the parts are provided in descending order. + * + * @param n + * The integer for which the partitions should be generated. + * @return A List containing the integer partitions, each represented as a + * integer Array. + */ + public static List generateIntegerPartitions(int n) { + + List res = new ArrayList(); + + int[] x = new int[n]; + + for (int i = 1; i <= n; i++) { + x[i - 1] = 1; + } + + x[0] = n; + int m = 1; + int h = 1; + + res.add(copySubarray(x, 0, 1)); + + while (x[0] != 1) { + + if (x[h - 1] == 2) { + m = m + 1; + x[h - 1] = 1; + h = h - 1; + } else { + int r = x[h - 1] - 1; + int t = m - h + 1; + x[h - 1] = r; + + while (t >= r) { + h = h + 1; + x[h - 1] = r; + t = t - r; + } + + if (t == 0) { + m = h; + } else { + m = h + 1; + + if (t > 1) { + h = h + 1; + x[h - 1] = t; + } + } + } + res.add(copySubarray(x, 0, m)); + } + + return res; + + } + + /** + * Copies a subarray of a given array and returns it. + * + * @param src + * The source array that should be used. + * @param start + * The start index. + * @param end + * The end index. + * @return A subarray of the source array, including the value at the start + * index and excluding the value at the end index. + */ + private static int[] copySubarray(int[] src, int start, int end) { + + int[] res = new int[end - start]; + int resPos = 0; + + for (int i = start; i < end; i++) { + res[resPos] = src[i]; + resPos++; + } + + return res; + } + + /** + * Generates all permutations of a sequence containing the numbers from 1 to + * n. + * + * @param n + * The upper bound of the permutations. + * @return A List with all permutations of the sequence. + */ + public static List generateLocationPermutations(int n) { + List res = new ArrayList(); + permLevel = -1; + + int[] value = new int[n]; + for (int i = 0; i < value.length; i++) { + value[i] = 0; + } + permVisit(value, n, 0, res); + + return res; + } + + /** + * Helper method for generating the integer sequence permutations. Should + * not be used on its own! + * + */ + private static void permVisit(int[] value, int n, int k, List res) { + permLevel = permLevel + 1; + value[k] = permLevel; + + if (permLevel == n) { + res.add(copySubarray(value, 0, value.length)); + } else { + for (int i = 0; i < n; i++) { + if (value[i] == 0) + permVisit(value, n, i, res); + } + } + permLevel = permLevel - 1; + value[k] = 0; + + } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ParallelGatewayExport.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ParallelGatewayExport.java new file mode 100644 index 0000000..c5075fa --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/ParallelGatewayExport.java @@ -0,0 +1,139 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.bpmn2.EndEvent; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; + +/** + * Creates the ASLan representation for a BPMN 2.0 ParallelGateway element. + * + */ +public class ParallelGatewayExport { +// +// /** +// * Generates the ASLan representation of the provided ParallelGateway +// * element and sends the output to the provided AslanFileBuilder. +// * +// * @param parallelGateway +// * The ParallelGateway for which the representation should be +// * generated. +// * @param afb +// * The AslanFileBuilder the output is sent to. +// */ +// public static void createParallelGatewayElements( +// ParallelGateway parallelGateway, XacmlFileBuilder afb) { +// +// final List incoming = parallelGateway.getIncoming(); +// String rule = "step w_" + parallelGateway.getId(); +// +// if (incoming.size() > 0) { +// +// // AND-join, AND-split +// String ruleDef = " := "; +// +// boolean firstDone = true; +// List natVars = new ArrayList(); +// for (SequenceFlow parentFlow : incoming) { +// +// final FlowElement predecessor = parentFlow.getSourceRef(); +// +// if (predecessor instanceof Task) { +// +// if (firstDone) { +// firstDone = false; +// } else { +// ruleDef += ". "; +// } +// +// String natVar = afb.addNatVar(); +// +// ruleDef += "done(task(" + predecessor.getId() + "," +// + natVar + "))"; +// natVars.add(natVar); +// +// } else if (predecessor instanceof Gateway) { +// +// if (firstDone) { +// firstDone = false; +// } else { +// ruleDef += ". "; +// } +// +// ruleDef += predecessor.getId() + "_to_" +// + parallelGateway.getId(); +// +// } else if (predecessor instanceof StartEvent) { +// +// if (firstDone) { +// firstDone = false; +// } else { +// ruleDef += ". "; +// } +// +// ruleDef += "start_event_" + predecessor.getId(); +// +// } +// } +// +// if (natVars.size() > 0) { +// +// rule += "("; +// +// for (int i = 0; i < natVars.size() - 1; i++) { +// rule += natVars.get(i) + ","; +// } +// rule += natVars.get(natVars.size() - 1) + ")"; +// +// } +// +// rule += ruleDef + " => "; +// +// boolean firstAuxFact = true; +// for (SequenceFlow childFlow : parallelGateway.getOutgoing()) { +// +// final FlowElement successor = childFlow.getTargetRef(); +// +// if (successor instanceof Task || successor instanceof Gateway +// || successor instanceof EndEvent) { +// +// final String auxFact = parallelGateway.getId() + "_to_" +// + successor.getId(); +// afb.addType("fact", auxFact); +// +// if (firstAuxFact) { +// rule += auxFact; +// firstAuxFact = false; +// } else { +// rule += ". " + auxFact; +// } +// } +// } +// +// afb.addRule(rule); +// +// } +// } + +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/SeparationOfDutyExport.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/SeparationOfDutyExport.java new file mode 100644 index 0000000..de83fcb --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/SeparationOfDutyExport.java @@ -0,0 +1,215 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.Permission; +import org.eclipse.securebpmn2.SeparationOfDuty; + +/** + * Creates the XACML representation of a SecureBPMN SeparationOfDuty element. + * + * + */ +public class SeparationOfDutyExport { + + /** + * Generates the XACML representation of the provided SeparationOfDuty element + * and sends the output to the provided XacmlFileBuilder. + * + * @param sod + * The SeparationOfDuty element for which the representation should + * be generated. + * @param afb + * The XacmlFileBuilder the output is sent to. + */ + public static void createSeparationOfDutyElements(SeparationOfDuty sod, XacmlFileBuilder xfb) { + + if (sod.isDynamicEnforcement()) return; + + List assignTasks = new ArrayList(); + List claimTasks = new ArrayList(); + List completeTasks = new ArrayList(); + + for (Permission p : sod.getPermissions()) { + + if (p.getActions().size() == 0) { + System.err.println("[WARNING] The permission with name=\"" + p.getPName() + "\" and id=\"" + p.getId() + "\" has no action. This should never happen! Check your .activiti diagram file."); + continue; + } + + // Permissions only have one Action + if (p.getActions().get(0) instanceof ActivityAction) { + ActivityAction a = (ActivityAction) p.getActions().get(0); + + if (a.getActionName().equals("Complete")) { + + completeTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Claim")) { + + claimTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Assign")) { + + assignTasks.add(a.getActivity().getId()); + + } else if (a.getActionName().equals("Full Access")) { + + assignTasks.add(a.getActivity().getId()); + claimTasks.add(a.getActivity().getId()); + completeTasks.add(a.getActivity().getId()); + + } + + } + } + + if (assignTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (claimTasks.size() > 1) { + // TODO what to check? only executed() is persistent... + } + + if (completeTasks.size() > 1) { + // safe default assumptions + int minUsers = completeTasks.size(); + int maxActions = 1; + + if (sod.getMinimumUsers() == null) { + System.out.println("[SCVM-EXPORT-XACML] minimum users for SoD \"" + sod.getId() + "\" not set, using " + minUsers + "."); + } else { + if (sod.getMinimumUsers() > completeTasks.size() || sod.getMinimumUsers() < 1) { + System.err.println("[SCVM-EXPORT-XACML] invalid input for minimum users at SoD \"" + sod.getId() + "\", using " + minUsers + "."); + } else { + minUsers = sod.getMinimumUsers(); + } + } + + if (sod.getMaxUserActionsPermitted() == null) { + System.out.println("[SCVM-EXPORT-XACML] maximum permitted actions for SoD \"" + sod.getId() + "\" not set, using " + maxActions + "."); + } else { + if (sod.getMaxUserActionsPermitted() < 1) { + System.err.println("[SCVM-EXPORT-XACML] invalid input for maximum permitted actions at SoD \"" + sod.getId() + "\", using " + maxActions + "."); + } else { + maxActions = sod.getMaxUserActionsPermitted(); + } + } + + // calculate numeric partitions + final List allPartitions = ExportUtil.generateIntegerPartitions(completeTasks.size()); + + // select invalid partitions + List selectedPartitions = new ArrayList(); + for (int[] part : allPartitions) { + if (part.length > 0 && (part.length < minUsers + || part[0] > maxActions)) { + selectedPartitions.add(part); + } + } + + // create goals for partitions + String[] tasks = new String[completeTasks.size()]; + for (int i = 0; i < completeTasks.size(); i++) { + tasks[i] = completeTasks.get(i); + } + List permList = ExportUtil.generateLocationPermutations(tasks.length); + + for (int[] part : selectedPartitions) { + // we assume that tasks.lengh equals the sum of each partition + List>> sets = new ArrayList>>(); + + // loop over index permutations + for (int[] perm : permList) { + int indexStart = 0; + // list of sets (parts of the partition) for the current permutation + List> setList = new ArrayList>(); + // create the sets + for (int partLength : part) { + Set partTasks = new HashSet(); + // get the tasks and add them to the set + for (int i = 0; i < partLength; i++) { + partTasks.add(tasks[perm[indexStart + i]-1]); + } + indexStart += partLength; + setList.add(partTasks); + } + // check if partition config already exists + boolean newSet = true; + for (List> presentSetList : sets) { + if (presentSetList.equals(setList)) { + newSet = false; + break; + } + } + // add partition config if new + if (newSet) { + sets.add(setList); + } + + } + + /* + // create goals for this partition + for (List> setArray : sets) { + // generate goal + int numUsers = setArray.size(); + int numTasks = tasks.length; + List natVars = new ArrayList(); + StringBuilder goalString = new StringBuilder(); + goalString.append("("); + + // generate user variables + for (int i = 0; i < numUsers; i++) { + afb.addType("user", "U" + i); + if (i > 0) goalString.append(","); + goalString.append("U" + i); + } + + // generate task nat variables + for (int i = 0; i < numTasks; i++) { + String currentVar = afb.addNatVar(); + natVars.add(currentVar); + goalString.append("," + currentVar); + } + + goalString.append("):="); + + // generate facts + int natVarPos = 0; + for (int i = 0; i < numUsers; i++) { + for (String currentTask : setArray.get(i)) { + goalString.append(" executed(U" + i + ",task(" + currentTask + "," + natVars.get(natVarPos) + "))."); + natVarPos++; + } + } + + // add goal + String finalGoalString = goalString.toString(); + afb.addGoal("sod_" + sod.getId() + "_", finalGoalString.substring(0, finalGoalString.length()-1)); + } + */ + } + } + } +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/TaskExport.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/TaskExport.java new file mode 100644 index 0000000..e861eaa --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/TaskExport.java @@ -0,0 +1,171 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.net.URI; +import java.net.URISyntaxException; + + +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.util.preferences.Preferences; + +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; + +import org.eclipse.securebpmn2.ActivityAction; +import org.eclipse.securebpmn2.Permission; +import org.eclipse.securebpmn2.Role; + +import com.sun.xacml.combine.DenyOverridesRuleAlg; +import com.sun.xacml.combine.RuleCombiningAlgorithm; + +/** + * Creates the RBAC XACML-Rules for each HumanTask in the Diagram + * + */ +public class TaskExport { + + /** + * Gathers information needed for the XACML-Policy rules section. + * + * @param task + * The {@link Task} element for which the information should be + * gathered + * + * @param xfb + * The {@link XacmlFileBuilder} used to create the rules + * + */ + public static void gatherTaskInfo(Task task, XacmlFileBuilder xfb) { + + final String taskID = task.getId(); + + boolean isHumanTask = false; + //boolean isSodTask = false; + + if (task instanceof UserTask + || PreferencesUtil + .getBooleanPreference(Preferences.ALL_TASKS_AS_HUMANTASKS)) + isHumanTask = true; + + if (isHumanTask) { + + /* + UserTask userTask = (UserTask) task; + List candidateGroups = userTask.getCandidateGroups(); + List groups = new ArrayList(); + + for (Iterator iterator = candidateGroups.iterator(); iterator.hasNext();) { + CandidateGroup candidateGroup = (CandidateGroup) iterator.next(); + groups.add(candidateGroup.getGroup()); + } + + for (Iterator iterator = groups.iterator(); iterator.hasNext();) { + String string = (String) iterator.next(); + try { + xfb.createTargetMatch(1, string); + xfb.createTargetMatch(2, taskID); + xfb.createTargetMatch(3, "Full Access"); + + if (task.getIncomingSecurityFlow().isEmpty()) { + xfb.createRule( + URI.create("rule_for_" + taskID), 0, + task.getName(), xfb.createTarget(), + null); + RuleCombiningAlgorithm ruleCombiningAlgorithm = new DenyOverridesRuleAlg(); + xfb.createPolicy( + URI.create("policy_for_" + taskID), + ruleCombiningAlgorithm, + xfb.createTarget(), xfb.getRules()); + } + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + */ + + // SecureBPMN RBAC + for (ActivityAction a : task.getActivityActions()) { + if (a.getActionName() != null + && (a.getActionName().equals("Assign") || a + .getActionName().equals("Full Access"))) { + try { + xfb.createTargetMatch(3, a.getActionName()); + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + for (Permission p : a.getPermissions()) { + for (Role r : p.getRoles()) { + try { + xfb.createTargetMatch(2, taskID); + + xfb.createTargetMatch(1, r.getName().toLowerCase()); + + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // TODO see todo below + /* + if(!task.getIncomingSecurityFlow().isEmpty()) { + isSodTask = task + .getIncomingSecurityFlow().get(0) + .getSourceRefNode().getId() + .startsWith("securitySod"); + }*/ + + + // simple human task + //if (task.getIncomingSecurityFlow().isEmpty()) { + xfb.createRule( + URI.create("rule_for_" + taskID), 0, + task.getName(), xfb.createTarget(), + null); + RuleCombiningAlgorithm ruleCombiningAlgorithm = new DenyOverridesRuleAlg(); + xfb.createPolicy( + URI.create("policy_for_" + taskID), + ruleCombiningAlgorithm, + xfb.createTarget(), xfb.getRules()); + //}// TODO insert condition for SoD-Task + /* + else if (isSodTask) { + + List connectedTasks = new ArrayList(); + for (Iterator it = task + .getIncomingSecurityFlow().iterator(); it + .hasNext();) { + SecurityFlow securityFlow = (SecurityFlow) it + .next(); + Task connectedTask = (Task) securityFlow.getTargetRefNode(); + connectedTasks.add(connectedTask); + + } + + xfb.createRule( + URI.create("rule_for_" + taskID), 0, + task.getName(), xfb.createTarget(), + xfb.createSodCondition(task, connectedTasks)); + }*/ + } + } + } + } + } + } +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlExportMarshaller.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlExportMarshaller.java new file mode 100644 index 0000000..e0a324f --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlExportMarshaller.java @@ -0,0 +1,195 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import java.net.URI; +import java.util.List; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.export.AbstractExportMarshaller; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.Process; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.Task; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.securebpmn2.BindingOfDuty; +import org.eclipse.securebpmn2.SeparationOfDuty; + +import com.sun.xacml.combine.FirstApplicablePolicyAlg; +import com.sun.xacml.combine.PolicyCombiningAlgorithm; + +/** + * Exports an XACML representation of the diagram being saved to the workspace + * as XML-File. + * + */ +public class XacmlExportMarshaller extends AbstractExportMarshaller { + + private static final String FILENAME_PATTERN = ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION + + ".xacml"; + private IProgressMonitor monitor; + private Diagram diagram; + + public XacmlExportMarshaller() { + } + + /** + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * getMarshallerName() + */ + @Override + public String getMarshallerName() { + return ActivitiBPMNDiagramConstants.XACML_MARSHALLER_NAME; + } + + /** + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller#getFormatName() + */ + @Override + public String getFormatName() { + return "SecureBPMN: XACML"; + } + + /** + * + * + * @see org.activiti.designer.eclipse.extension.export.ExportMarshaller# + * marshallDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void marshallDiagram(Diagram diagram, IProgressMonitor monitor) { + + this.monitor = monitor; + this.diagram = diagram; + this.monitor.beginTask("Exporting to XACML", 100); + clearMarkers(getResource(diagram.eResource().getURI())); + this.monitor.worked(10); + String validatorId = ActivitiBPMNDiagramConstants.XACML_VALIDATOR_ID; + boolean validBpmn = invokeValidator(validatorId, diagram, + new SubProgressMonitor(this.monitor, 10)); + + if (validBpmn) { + marshallXacml(); + } else { + addProblemToDiagram( + diagram, + "XACML Export skipped because SecureBPMN validation failed.", + null); + } + this.monitor.worked(80); + this.monitor.done(); + } + + /** + * Controls and executes the XACML file generation. + */ + public void marshallXacml() { + + try { + final List contents = diagram.eResource().getContents(); + Process process = null; + + for (final EObject eObject : contents) { + if (eObject instanceof Process) { + process = (Process) eObject; + } + } + if (process == null) { + addProblemToDiagram(diagram, "Process cannot be null", null); + } + final XacmlFileBuilder xfb = new XacmlFileBuilder(); + // element-specific content generation + for (EObject object : contents) { + if (object instanceof ParallelGateway) { + /* + * ParallelGatewayExport.createParallelGatewayElements( + * (ParallelGateway) object, xfb); + */ + } else if (object instanceof ExclusiveGateway) { + /* + * ExclusiveGatewayExport.createExclusiveGatewayElements( + * (ExclusiveGateway) object, xfb); + */ + } else if (object instanceof StartEvent) { + /* + * final String startEventFact = "start_event_" + + * ((StartEvent) object).getId(); xfb.addType("fact", + * startEventFact); xfb.addInit(startEventFact); + */ + } else if (object instanceof Task) { + + TaskExport.gatherTaskInfo((Task) object, xfb); + + } else if (object instanceof SeparationOfDuty) { + /* + * SeparationOfDutyExport.createSeparationOfDutyElements( + * (SeparationOfDuty) object, xfb); + */ + } else if (object instanceof BindingOfDuty) { + /* + * BindingOfDutyExport.createBindingOfDutyElements( + * (BindingOfDuty) object, xfb); + */ + } + } + // the policy + //URI policyID = URI.create("testPolicy"); + // TODO insert options for the used CombiningAlg + //RuleCombiningAlgorithm ruleCombiningAlg = new DenyOverridesRuleAlg(); + + //xfb.createPolicy(policyID, ruleCombiningAlg, xfb.createTarget(), + // xfb.getRules()); + // the policy Set + URI policySetID = URI.create("testPolicySet"); + // TODO insert options for the used CombiningAlg + PolicyCombiningAlgorithm policyCombiningAlg = new FirstApplicablePolicyAlg(); + + // TODO maybe create deny rule for the PolicySet-Target if no inner + // rules apply + xfb.createPolicySet(policySetID, policyCombiningAlg, + xfb.createTarget(), xfb.getPolicies()); + + // mapping the encoded PolicySet data + final ByteArrayOutputStream baos = (ByteArrayOutputStream) xfb + .encodePolicySet(); + + // write policy to file + final byte[] bytes = baos.toByteArray(); + final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + saveResource(getRelativeURIForDiagram(diagram, FILENAME_PATTERN), + bais, new NullProgressMonitor()); + + //xfb.testPDP(); + + } catch (Exception e) { + e.printStackTrace(); + addProblemToDiagram( + diagram, + "An exception occurred while creating the XACML file: " + + e.getMessage(), null); + } + } +} diff --git a/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlFileBuilder.java b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlFileBuilder.java new file mode 100644 index 0000000..5f3aee4 --- /dev/null +++ b/src/eu.aniketos.securebpmn.export.xacml/src/main/java/eu/aniketos/securebpmn/export/xacml/export/XacmlFileBuilder.java @@ -0,0 +1,329 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.export.xacml.export; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import com.sun.xacml.*; + +import com.sun.xacml.attr.AnyURIAttribute; +import com.sun.xacml.attr.AttributeDesignator; +import com.sun.xacml.attr.AttributeValue; +import com.sun.xacml.attr.StringAttribute; +import com.sun.xacml.attr.TypeIdentifierConstants; + +import com.sun.xacml.combine.PolicyCombiningAlgorithm; +import com.sun.xacml.combine.RuleCombiningAlgorithm; +import com.sun.xacml.cond.Condition; +import com.sun.xacml.cond.EqualFunction; +import com.sun.xacml.cond.Evaluatable; +import com.sun.xacml.cond.Function; + +/** + * Provides the methods to create a complete XACML policy. + * + */ +public class XacmlFileBuilder { + + /** + * output is used in {@link #encodePolicySet()} to provide a source for the + * XML encoded Data + */ + private OutputStream output; + + private PolicySet policySet; + + private List rules; + private List policies; + + private List matches; + private List matchGroups; + private List targetSections; + + public XacmlFileBuilder() throws FileNotFoundException, ParsingException, UnknownIdentifierException { + + // createSodCondition(); + output = new ByteArrayOutputStream(); + policies = new ArrayList(); + rules = new ArrayList(); + matches = new ArrayList(); + matchGroups = new ArrayList(); + targetSections = new ArrayList(); + } + + /** + * Takes the completed {@link PolicySet} and encodes it to XML-format. + * + * @throws RuntimeException + * if encoding fails + * @return {@link XacmlFileBuilder#output} The encoded + * PolicySet in its XML-formatted version. + */ + public OutputStream encodePolicySet() { + + try { + this.policySet.encode(output, "UTF-8"); + + } catch (UnsupportedEncodingException e) { + // e.printStackTrace(); + throw new RuntimeException("error during encoding process", e); + } + return output; + } + + /** + * Creates a new {@link PolicySet}.
    + *
    And clears the {@link #policies}-list for the next + * PolicySet + * + * @param policySetID + * the PolicySet identifier + * @param policyCombiningAlg + * the CombiningAlgorithm used on the policies in + * this set + * @param target + * the Target for this PolicySet (may + * be null) + * @param policies + * a list of the policies in this set + */ + public void createPolicySet(URI policySetID, + PolicyCombiningAlgorithm policyCombiningAlg, Target target, + List policies) { + + policySet = new PolicySet(policySetID, policyCombiningAlg, target, + policies); + this.policies.clear(); + } +//TODO finish sod check if needed after pdp impl + /* + public boolean evalSodCondition(Task currentTask, List connectedTasks) { + // check if user of currentTask has claimed/completed any of the tasks + // in the connectedTasks list + Main_Test main_Test = new Main_Test(); + + TaskService ts = main_Test.getTaskService(); + HistoryService hs = main_Test.getHistoryService(); + + // get the current user of the given sod task + org.activiti.engine.task.Task focusedTask = ts.createTaskQuery() + .processDefinitionKey(currentTask.getId()).singleResult(); + String currentUser = focusedTask.getAssignee(); + + // check if this user has already performed an action on a connected sod + // task + for (Iterator iterator = connectedTasks.iterator(); iterator + .hasNext();) { + Task task = (Task) iterator.next(); + + String taskIdToCheck = task.getId(); + if (hs.createHistoricTaskInstanceQuery().taskAssignee(currentUser) + .count() != 0) { + return false; + } + + } + return true; + + } + */ +//TODO finish sod check if needed after pdp impl + /* + public Condition createSodCondition(Task currentTask, + List connectedTasks) { + + Expression expression = new EqualFunction(EqualFunction.NAME_BOOLEAN_EQUAL); + + Condition condition = new Condition(expression); + + return condition; + + } + */ + /** + * Creates a new {@link Rule}. + * + * @param ruleID + * the identifier of the Rule + * @param effect + * the result if the Rule applies as defined in + * {@link Result} + * @param ruleDescription + * a textual description for the Rule (may be null) + * @param target + * the Target for the Rule, or null if + * it should be inherited from the parent Policy or + * PolicySet + * @param condition + * the Condition for this Rule (may be + * null) + */ + public void createRule(URI ruleID, int effect, String ruleDescription, + Target target, Condition condition) { + + Rule rule = new Rule(ruleID, effect, ruleDescription, target, condition); + + if (!rules.contains(rule)) { + rules.add(rule); + } + } + + /** + * Creates a new {@link Policy}. + * + * @param policyID + * the identifier of the Policy + * @param ruleCombiningAlg + * the CombiningAlgorithm used on the rules in this + * Policy + * @param target + * the Target for the Policy, or null + * if it should be inherited + * @param rules + * a list of the rules in this Policy + */ + public void createPolicy(URI policyID, + RuleCombiningAlgorithm ruleCombiningAlg, Target target, + List rules) { + + Policy policy = new Policy(policyID, ruleCombiningAlg, target, rules); + + if (!policies.contains(policy)) { + policies.add(policy); + } + this.rules.clear(); + } + + /** + * Creates a new {@link TargetMatch}. + * + * @param matchType + * used to determine which match type will be used
  • + * 1:Subject-Role
  • 2:Resource
  • 3:Action
  • + * @param attrValueString + * the name of the target to match + * @throws URISyntaxException + */ + public void createTargetMatch(int matchType, String attrValueString) throws URISyntaxException { + + URI category = null; + URI attrType = null; + URI attrId = null; + Function function = null; + AttributeValue attrValue = null; + + switch (matchType) { + + case 1: + category = Constants.SUBJECT_CAT; + attrType = TypeIdentifierConstants.STRING_URI; + attrId = URI.create("urn:custom:subject:role"); + function = new EqualFunction(EqualFunction.NAME_STRING_EQUAL); + attrValue = new StringAttribute(attrValueString); + break; + + case 2: + category = Constants.RESOURCE_CAT; + attrType = TypeIdentifierConstants.ANYURI_URI; + attrId = Constants.RESOURCE_ID; + function = new EqualFunction(EqualFunction.NAME_ANYURI_EQUAL); + attrValue = new AnyURIAttribute(new URI(attrValueString)); + break; + + case 3: + category = Constants.ACTION_CAT; + attrType = TypeIdentifierConstants.STRING_URI; + attrId = Constants.ACTION_ID; + function = new EqualFunction(EqualFunction.NAME_STRING_EQUAL); + attrValue = new StringAttribute(attrValueString); + break; + + default: + System.out.println("\ncategory error\n"); + break; + + } + Evaluatable eval = new AttributeDesignator(category, attrType, attrId, + false, null); + TargetMatch tm = new TargetMatch(function, eval, attrValue); + matches.add(tm); + } + + /** + * Creates a new {@link TargetMatchGroup}.
    + * And adds it to the local {@link #matchGroups}-list
    + */ + private void createTargetMatchGroup() { + + TargetMatchGroup tmg = new TargetMatchGroup(matches); + matchGroups.add(tmg); + } + + /** + * Creates a new {@link TargetSection}.
    + * And adds it to the local {@link #targetSections}-list
    + */ + private void createTargetSection() { + + TargetSection ts = new TargetSection(matchGroups); + targetSections.add(ts); + } + + /** + * Creates a new {@link Target}.
    + *
    Uses {@link #createTargetMatchGroup()} and + * {@link #createTargetSection()} to create a Target.
    + * It clears the {@link #matches}, {@link #matchGroups}, + * {@link #targetSections}-lists for the next Target.
    + * + * @return target the created Target + */ + public Target createTarget() { + + createTargetMatchGroup(); + createTargetSection(); + Target target = new Target(getTargetSections()); + matches.clear(); + matchGroups.clear(); + targetSections.clear(); + + return target; + } + + /* + * non-javadoc + * + * following are the needed getters for the XacmlExportMarshaller + */ + private List getTargetSections() { + return targetSections; + } + + public List getRules() { + return rules; + } + + public List getPolicies() { + return policies; + } +} diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/META-INF/MANIFEST.MF b/src/eu.aniketos.securebpmn.validation.bpmn20/META-INF/MANIFEST.MF new file mode 100644 index 0000000..1d14a5c --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - SecureBPMN: Validation +Bundle-SymbolicName: eu.aniketos.securebpmn.validation.bpmn20;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: eu.aniketos.securebpmn.validation.bpmn20.bundle.Activator +Bundle-Vendor: SAP SE +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.emf, + org.eclipse.core.resources, + org.eclipse.graphiti.mm, + org.activiti.designer.eclipse, + org.activiti.designer.model +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-ClassPath: ., + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + com.sun.xacml-0.1.jar, + jdi.jar, + jdimodel.jar, + junit.jar diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/build.properties b/src/eu.aniketos.securebpmn.validation.bpmn20/build.properties new file mode 100644 index 0000000..936c481 --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java/ +output.. = target/ +bin.includes = META-INF/,\ + plugin.xml,\ + . \ No newline at end of file diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/plugin.xml b/src/eu.aniketos.securebpmn.validation.bpmn20/plugin.xml new file mode 100644 index 0000000..6c744e1 --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/plugin.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/pom.xml b/src/eu.aniketos.securebpmn.validation.bpmn20/pom.xml new file mode 100644 index 0000000..e2b3ff6 --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + eu.aniketos.securebpmn.validation.bpmn20 + eclipse-plugin + Activiti Designer - SecureBPMN: Validation + diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/bundle/Activator.java b/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/bundle/Activator.java new file mode 100644 index 0000000..f35d100 --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/bundle/Activator.java @@ -0,0 +1,58 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation.bpmn20.bundle; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + * + */ +public class Activator implements BundleActivator { + + // The plug-in ID + public static final String PLUGIN_ID = "eu.aniketos.securebpmn.validation.bpmn20"; //$NON-NLS-1$ + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/validation/BPMN20ProcessValidator.java b/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/validation/BPMN20ProcessValidator.java new file mode 100644 index 0000000..fb49bc5 --- /dev/null +++ b/src/eu.aniketos.securebpmn.validation.bpmn20/src/main/java/eu/aniketos/securebpmn/validation/bpmn20/validation/BPMN20ProcessValidator.java @@ -0,0 +1,165 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation.bpmn20.validation; + +import java.util.List; +import java.util.Map; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.validation.AbstractProcessValidator; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.bpmn2.impl.UserTaskImpl; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.securebpmn2.ActivityAction; + +/** + * Checks if every UserTask has a SecureBPMN Action of the type assign, claim + * and execute, i.e., if the UserTask can be properly executed. + * + * + */ +public class BPMN20ProcessValidator extends AbstractProcessValidator { + + private boolean overallResult; + + public BPMN20ProcessValidator() { + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.validation.ProcessValidator# + * getValidatorId() + */ + @Override + public String getValidatorId() { + return ActivitiBPMNDiagramConstants.ASLAN_VALIDATOR_ID; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.validation.ProcessValidator# + * getValidatorName() + */ + @Override + public String getValidatorName() { + return ActivitiBPMNDiagramConstants.ASLAN_VALIDATOR_NAME; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.validation.ProcessValidator# + * getFormatName() + */ + @Override + public String getFormatName() { + return "SecureBPMN: ASLan"; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.validation.ProcessValidator# + * validateDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public boolean validateDiagram(Diagram diagram, IProgressMonitor monitor) { + + this.overallResult = true; + + monitor.beginTask("Validating Diagram for ASLan export", 5); + + // Clear problems for this diagram first + clearMarkers(getResource(diagram.eResource().getURI())); + + final Map> processNodes = extractProcessConstructs( + getResourceForDiagram(diagram).getContents(), + new SubProgressMonitor(monitor, 2)); + + final List userTasks = processNodes.get(UserTaskImpl.class + .getCanonicalName()); + + for (EObject object : userTasks) { + + UserTask userTask = (UserTask) object; + + boolean assignNotSet = true; + boolean claimNotSet = true; + boolean completeNotSet = true; + + for (ActivityAction a : userTask.getActivityActions()) { + if (a.getActionName() != null) { + if (a.getActionName().equals("Assign")) { + assignNotSet = false; + } else if (a.getActionName().equals("Claim")) { + claimNotSet = false; + } else if (a.getActionName().equals("Complete")) { + completeNotSet = false; + } else if (a.getActionName().equals("Full Access")) { + assignNotSet = false; + claimNotSet = false; + completeNotSet = false; + } + } + } + + if (assignNotSet) { + addProblemToDiagram(diagram, + "[SCVM-VAL-001] Missing Assign Action on UserTask \"" + + userTask.getId() + "\".", userTask.getId()); + } + + if (claimNotSet) { + addProblemToDiagram(diagram, + "[SCVM-VAL-002] Missing Claim Action on UserTask \"" + + userTask.getId() + "\".", userTask.getId()); + } + + if (completeNotSet) { + addProblemToDiagram(diagram, + "[SCVM-VAL-003] Missing Complete Action on UserTask \"" + + userTask.getId() + "\".", userTask.getId()); + } + + } + + monitor.worked(3); + + monitor.done(); + return overallResult; + } + + /* + * (non-Javadoc) + * + * @see org.activiti.designer.eclipse.extension.AbstractDiagramWorker# + * addProblemToDiagram(org.eclipse.graphiti.mm.pictograms.Diagram, + * java.lang.String, java.lang.String) + */ + @Override + protected void addProblemToDiagram(Diagram diagram, String message, + String nodeId) { + super.addProblemToDiagram(diagram, message, nodeId); + overallResult = false; + } + +} diff --git a/src/eu.aniketos.securebpmn/META-INF/MANIFEST.MF b/src/eu.aniketos.securebpmn/META-INF/MANIFEST.MF new file mode 100644 index 0000000..98c1773 --- /dev/null +++ b/src/eu.aniketos.securebpmn/META-INF/MANIFEST.MF @@ -0,0 +1,31 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - SecureBPMN Extension +Bundle-SymbolicName: eu.aniketos.securebpmn;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: eu.aniketos.securebpmn.Activator +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.ui, + org.activiti.designer.model, + org.eclipse.graphiti, + org.eclipse.jdt.core, + org.eclipse.core.resources, + org.activiti.designer.eclipse, + org.activiti.designer.util, + org.antlr.runtime, + org.eclipse.emf.transaction, + org.eclipse.ui.ide +Export-Package: eu.aniketos.securebpmn.features, + eu.aniketos.securebpmn.ntk, + eu.aniketos.securebpmn.util, + eu.aniketos.securebpmn.visualization.rbac +Bundle-ClassPath: ., + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + com.sun.xacml-0.1.jar, + jdi.jar, + jdimodel.jar, + junit.jar diff --git a/src/eu.aniketos.securebpmn/build.properties b/src/eu.aniketos.securebpmn/build.properties new file mode 100644 index 0000000..d3e10c8 --- /dev/null +++ b/src/eu.aniketos.securebpmn/build.properties @@ -0,0 +1,5 @@ +source.. = src/main/java/ +output.. = target/ +bin.includes = META-INF/,\ + plugin.xml,\ + . diff --git a/src/eu.aniketos.securebpmn/plugin.xml b/src/eu.aniketos.securebpmn/plugin.xml new file mode 100644 index 0000000..567b00b --- /dev/null +++ b/src/eu.aniketos.securebpmn/plugin.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/src/eu.aniketos.securebpmn/pom.xml b/src/eu.aniketos.securebpmn/pom.xml new file mode 100644 index 0000000..a358047 --- /dev/null +++ b/src/eu.aniketos.securebpmn/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + eu.aniketos.securebpmn + eclipse-plugin + Activiti Designer - SecureBPMN Extension + diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/Activator.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/Activator.java new file mode 100644 index 0000000..38faedb --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/Activator.java @@ -0,0 +1,56 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + * + * + */ +public class Activator implements BundleActivator { + // The plug-in ID + public static final String PLUGIN_ID = "eu.aniketos.securebpmn"; //$NON-NLS-1$ + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext + * ) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/CheckServiceTaskFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/CheckServiceTaskFeature.java new file mode 100644 index 0000000..0c19852 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/CheckServiceTaskFeature.java @@ -0,0 +1,300 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.activiti.designer.util.eclipse.ActivitiUiUtil; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.impl.ServiceTaskImpl; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; +import org.eclipse.graphiti.features.custom.AbstractCustomFeature; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.ui.IEditorDescriptor; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.part.FileEditorInput; + +import eu.aniketos.securebpmn.util.DialogUtil; +import eu.aniketos.securebpmn.validation.ProcVarCheckASTVisitor; + +/** + * This feature provides a feature that checks a provided ServiceTask Java implementation if + * it accesses a process variable with a provided name and displays the result + * to the user. + * + * + */ +public class CheckServiceTaskFeature extends AbstractCustomFeature { + + public CheckServiceTaskFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.graphiti.features.impl.AbstractFeature#getName() + */ + @Override + public String getName() { + return "Check service task"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#getDescription + * () + */ + @Override + public String getDescription() { + return "Check if service task accesses a specific process variable"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute + * (org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + if (context.getPictogramElements() == null) + return false; + for (PictogramElement pictogramElement : context.getPictogramElements()) { + if (pictogramElement.getLink() == null) + continue; + Object boObject = getBusinessObjectForPictogramElement(pictogramElement); + if (boObject instanceof ServiceTask == false) { + return false; + } + } + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse + * .graphiti.features.context.ICustomContext) + */ + public void execute(ICustomContext context) { + + ServiceTask servicetask = null; + + // get BusinessObject + try { + servicetask = (ServiceTask) ActivitiUiUtil + .getBusinessObjectFromContext(context, + ServiceTaskImpl.class); + } catch (Exception e) { + DialogUtil.openMessageDialog("BO Missing", + "No ServiceTask BusinessObject for Context found", + DialogUtil.ERROR); + } + if (servicetask == null) + return; + + // check if service task has java impl + if (servicetask.getImplementationType() == null + || !(servicetask.getImplementationType().equals("classType"))) { + DialogUtil.openMessageDialog("Wrong Type", + "Type must be \"Java class\" to perform this check.", + DialogUtil.ERROR); + return; + } + + if (servicetask.getImplementation() == null + || servicetask.getImplementation().length() == 0) { + DialogUtil.openMessageDialog("Missing Class definition", + "No Java class specified.", DialogUtil.ERROR); + return; + } + + // prompt user for process variable + String procVar = DialogUtil.openInputDialog("Process Variable", + "Enter the process variable that should not be accessed.", "", + null); + + if (procVar == null) { + // user canceled + return; + } + + // map FQ class name to java file + + // TODO hack, do this nicely + String[] classParts = servicetask.getImplementation().split("\\."); + String implFileName = classParts[classParts.length - 1] + ".java"; + + StringBuilder sb = new StringBuilder(); + sb.append("/"); + sb.append("src"); + sb.append("/"); + sb.append("main"); + sb.append("/"); + sb.append("java"); + sb.append("/"); + for (int i = 0; i < classParts.length - 1; i++) { + sb.append(classParts[i]); + sb.append("/"); + } + sb.append(implFileName); + + IResource resourceToRead = null; + int filesFound = 0; + + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceRoot root = workspace.getRoot(); + IProject[] projects = root.getProjects(); + for (IProject project : projects) { + IResource resourceInRuntimeWorkspace = root.findMember(project + .getName() + sb.toString()); + if (resourceInRuntimeWorkspace != null) { + filesFound++; + if (resourceToRead == null) { + resourceToRead = resourceInRuntimeWorkspace; + } + } + } + + if (filesFound == 0) { + DialogUtil.openMessageDialog("Missing source", + "Implementation source file not found in workspace.", + DialogUtil.ERROR); + return; + } else if (filesFound > 1) { + DialogUtil + .openMessageDialog( + "Multiple files", + "Found " + + filesFound + + " matching source files in workspace, using the following:\n\n" + + resourceToRead.getFullPath(), + DialogUtil.WARNING); + } + + // read file + StringBuffer fileData = new StringBuffer(1000); + try { + BufferedReader reader = new BufferedReader(new FileReader(new File( + resourceToRead.getLocationURI()))); + char[] buf = new char[1024]; + int numRead = 0; + while ((numRead = reader.read(buf)) != -1) { + String readData = String.valueOf(buf, 0, numRead); + fileData.append(readData); + buf = new char[1024]; + } + reader.close(); + } catch (Exception e) { + e.printStackTrace(); + DialogUtil.openMessageDialog("IO Error", + "Error while reading source file: " + e.getMessage(), + DialogUtil.ERROR); + return; + } + + // build AST for Impl + List locationList = new ArrayList(); + ASTParser parser = ASTParser.newParser(AST.JLS3); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setSource(fileData.toString().toCharArray()); + CompilationUnit node = (CompilationUnit) parser.createAST(null); + node.accept(new ProcVarCheckASTVisitor(procVar, locationList)); + + // remove duplicates + List uniqueLocationList = new ArrayList(); + for (Integer i : locationList) { + Integer newLoc = node.getLineNumber(i); + if (!uniqueLocationList.contains(newLoc)) + uniqueLocationList.add(newLoc); + } + + if (uniqueLocationList.size() > 0) { + // notify user + StringBuilder msgSB = new StringBuilder(); + msgSB.append("Process variable access of \"" + procVar + + "\" found in implementation at "); + if (uniqueLocationList.size() > 1) { + msgSB.append("lines "); + for (int i = 0; i < uniqueLocationList.size() - 1; i++) { + msgSB.append(uniqueLocationList.get(i) + ", "); + } + msgSB.append("and " + + uniqueLocationList.get(uniqueLocationList.size() - 1)); + } else { + msgSB.append("line " + uniqueLocationList.get(0)); + } + msgSB.append("."); + + int answer = DialogUtil.openMessageDialog("Violation", + msgSB.toString(), DialogUtil.ERROR, new String[] { "OK", + "Open File" + }, 0); + + if (answer == 1) { + // open source file + IWorkbench wb = PlatformUI.getWorkbench(); + IWorkbenchPage page = wb.getActiveWorkbenchWindow() + .getActivePage(); + IFile file = (IFile) resourceToRead; + IEditorDescriptor desc = wb.getEditorRegistry() + .getDefaultEditor(file.getName()); + HashMap map = new HashMap(); + map.put(IMarker.LINE_NUMBER, uniqueLocationList.get(0)); + try { + IMarker marker = file.createMarker(IMarker.TEXT); + marker.setAttributes(map); + page.openEditor(new FileEditorInput(file), desc.getId()); + IDE.openEditor(page, marker); + marker.delete(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + } else { + DialogUtil.openMessageDialog("No violation", + "No process variable access of \"" + procVar + + "\" found in implementation.", DialogUtil.INFO); + } + + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ListProcessVariablesFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ListProcessVariablesFeature.java new file mode 100644 index 0000000..a9b60b2 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ListProcessVariablesFeature.java @@ -0,0 +1,175 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; +import org.eclipse.graphiti.features.custom.AbstractCustomFeature; + +import eu.aniketos.securebpmn.ntk.NeedToKnowUtil; +import eu.aniketos.securebpmn.util.DialogUtil; +import eu.aniketos.securebpmn.validation.ProcVarAccess; + +/** + * The feature collects a list of all process variables that are accessed in the + * process and the way they are accessed (read, write or both) and displays it + * to the user. + * + * + */ +public class ListProcessVariablesFeature extends AbstractCustomFeature { + + public ListProcessVariablesFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.graphiti.features.impl.AbstractFeature#getName() + */ + @Override + public String getName() { + return "List process variables"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#getDescription + * () + */ + @Override + public String getDescription() { + return "Retrieve all processs variables accessed and display them to the user."; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute + * (org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse + * .graphiti.features.context.ICustomContext) + */ + public void execute(ICustomContext context) { + // fill list + Map accesses = new HashMap(); + + List diagramContents = getDiagram().eResource().getContents(); + + for (EObject object : diagramContents) { + if (object instanceof ServiceTask) { + + ServiceTask sTask = (ServiceTask) object; + + for (ProcVarAccess varAccess : NeedToKnowUtil + .getAccessedProcessVariables(sTask)) { + if (accesses.containsKey(varAccess.getName())) { + // update + String currentAccess = accesses + .get(varAccess.getName()); + if (currentAccess.length() > 1) { + // nothing to do, already rw + continue; + } + + if ((currentAccess.equals("r") && varAccess.isWrite()) + || (currentAccess.equals("w") && !varAccess + .isWrite())) { + accesses.put(varAccess.getName(), "rw"); + } else + continue; + + } else { + accesses.put(varAccess.getName(), + varAccess.isWrite() ? "w" : "r"); + } + } + } else if (object instanceof UserTask) { + + UserTask uTask = (UserTask) object; + + for (ProcVarAccess varAccess : NeedToKnowUtil + .getAccessedProcessVariables(uTask)) { + if (accesses.containsKey(varAccess.getName())) { + // update + String currentAccess = accesses + .get(varAccess.getName()); + if (currentAccess.length() > 1) { + // nothing to do, already rw + continue; + } + + if ((currentAccess.equals("r") && varAccess.isWrite()) + || (currentAccess.equals("w") && !varAccess + .isWrite())) { + accesses.put(varAccess.getName(), "rw"); + } else + continue; + + } else { + accesses.put(varAccess.getName(), + varAccess.isWrite() ? "w" : "r"); + } + } + + } + } + + // notify user + StringBuilder sb = new StringBuilder(); + + Set accessedVars = accesses.keySet(); + + if (accessedVars.size() == 0) { + sb.append("No process variables are accessed in this process."); + } else { + + sb.append("The following process variables are being accessed:\n"); + + for (String s : accessedVars) { + sb.append(s + " (" + accesses.get(s) + ")\n"); + } + + } + + DialogUtil.openMessageDialog("Process variable access", sb.toString(), + DialogUtil.INFO); + + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/PerformNtkAnalysisFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/PerformNtkAnalysisFeature.java new file mode 100644 index 0000000..aa10e7a --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/PerformNtkAnalysisFeature.java @@ -0,0 +1,276 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import java.util.List; + +import org.eclipse.bpmn2.DataInput; +import org.eclipse.bpmn2.DataOutput; +import org.eclipse.bpmn2.InputSet; +import org.eclipse.bpmn2.OutputSet; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; +import org.eclipse.graphiti.features.custom.AbstractCustomFeature; +import org.eclipse.securebpmn2.ActivityAuthorizationConstraint; +import org.eclipse.securebpmn2.AuthorizationConstraint; +import org.eclipse.securebpmn2.CompositeItemAwareElementAction; +import org.eclipse.securebpmn2.ItemAwareElementAction; +import org.eclipse.securebpmn2.NeedToKnow; +import org.eclipse.securebpmn2.Permission; + +import eu.aniketos.securebpmn.ntk.NeedToKnowUtil; +import eu.aniketos.securebpmn.util.DialogUtil; + +/** + * This feature performs an analysis of the need-to-know specification and + * constraints in the process and notifies the user with the result, i.e., if + * violations were found or not. + * + * + */ +public class PerformNtkAnalysisFeature extends AbstractCustomFeature { + + public PerformNtkAnalysisFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.graphiti.features.impl.AbstractFeature#getName() + */ + @Override + public String getName() { + return "Perform NtK analysis"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#getDescription + * () + */ + @Override + public String getDescription() { + return "Perform the analysis of need-to-know specifications"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute + * (org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse + * .graphiti.features.context.ICustomContext) + */ + @Override + public void execute(ICustomContext context) { + + final List diagramElements = getDiagram().eResource() + .getContents(); + + for (EObject obj : diagramElements) { + + if (!(obj instanceof UserTask || obj instanceof ServiceTask)) + continue; + + final Task t = (Task) obj; + + if (t.getIoSpecification() == null) + continue; + + // check read access + for (InputSet inSet : t.getIoSpecification().getInputSets()) { + for (DataInput in : inSet.getDataInputRefs()) { + boolean isValid = false; + for (ItemAwareElementAction iaea : in + .getItemAwareElementActions()) { + if (isValid) + break; + + if (!iaea.getActionName().equals("read")) + continue; + + for (CompositeItemAwareElementAction comp : iaea + .getCompositeItemAwareElementActions()) { + if (comp.getActionName().equals("read/write")) { + // analyze parent composite action from this + // point on + iaea = comp; + break; + } + } + + for (Permission p : iaea.getPermissions()) { + if (isValid) + break; + + if (!(p instanceof NeedToKnow)) + continue; + + for (AuthorizationConstraint ac : p + .getAuthorizationConstraints()) { + + if (!(ac instanceof ActivityAuthorizationConstraint)) + continue; + + ActivityAuthorizationConstraint aac = (ActivityAuthorizationConstraint) ac; + + if (aac.getActivities().contains(t)) { + isValid = true; + break; + } + } + } + } + + if (!isValid) { + String varName = in.getId().substring( + NeedToKnowUtil.ID_PREFIX_INPUT.length()); + + if (t instanceof UserTask) { + // UserTask message + DialogUtil + .openMessageDialog( + "Validation error", + "Read access of process variable \"" + + varName + + "\" is not permitted at Task \"" + + t.getId() + + "\".\n\nRemove the corresponding form field or review your need-to-know specification.", + DialogUtil.ERROR); + } else if (t instanceof ServiceTask) { + // ServiceTask message + DialogUtil + .openMessageDialog( + "Validation error", + "Read access of process variable \"" + + varName + + "\" is not permitted at Task \"" + + t.getId() + + "\".\n\nReview your Java implementation or your need-to-know specification. To see where the access occurs in the implementation, use the \"Check Service Task\" feature available via the context menu.", + DialogUtil.ERROR); + } + return; + } + } + } + + // check write access + for (OutputSet outSet : t.getIoSpecification().getOutputSets()) { + for (DataOutput out : outSet.getDataOutputRefs()) { + boolean isValid = false; + for (ItemAwareElementAction iaea : out + .getItemAwareElementActions()) { + if (isValid) + break; + + if (!iaea.getActionName().equals("write")) + continue; + + for (CompositeItemAwareElementAction comp : iaea + .getCompositeItemAwareElementActions()) { + if (comp.getActionName().equals("read/write")) { + // analyze parent composite action from this + // point on + iaea = comp; + break; + } + } + + for (Permission p : iaea.getPermissions()) { + if (isValid) + break; + + if (!(p instanceof NeedToKnow)) + continue; + + for (AuthorizationConstraint ac : p + .getAuthorizationConstraints()) { + + if (!(ac instanceof ActivityAuthorizationConstraint)) + continue; + + ActivityAuthorizationConstraint aac = (ActivityAuthorizationConstraint) ac; + + if (aac.getActivities().contains(t)) { + isValid = true; + break; + } + } + } + } + + if (!isValid) { + String varName = out.getId().substring( + NeedToKnowUtil.ID_PREFIX_OUTPUT.length()); + + if (t instanceof UserTask) { + // UserTask message + DialogUtil + .openMessageDialog( + "Validation error", + "Write access of process variable \"" + + varName + + "\" is not permitted at Task \"" + + t.getId() + + "\".\n\nRemove the corresponding form field or review your need-to-know specification.", + DialogUtil.ERROR); + } else if (t instanceof ServiceTask) { + // ServiceTask message + DialogUtil + .openMessageDialog( + "Validation error", + "Write access of process variable \"" + + varName + + "\" is not permitted at Task \"" + + t.getId() + + "\".\n\nReview your Java implementation or your need-to-know specification. To see where the access occurs in the implementation, use the \"Check Service Task\" feature available via the context menu.", + DialogUtil.ERROR); + } + return; + } + } + } + + } + + // no errors + DialogUtil + .openMessageDialog( + "No validation errors", + "All process variables are accessed according to the specification.", + DialogUtil.INFO); + + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanFeature.java new file mode 100644 index 0000000..af4ff3f --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanFeature.java @@ -0,0 +1,565 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import org.eclipse.bpmn2.BoundaryEvent; +import org.eclipse.bpmn2.CallActivity; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.FlowNode; +import org.eclipse.bpmn2.InclusiveGateway; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.SubProcess; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; +import org.eclipse.graphiti.features.custom.AbstractCustomFeature; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.IProgressService; + +import eu.aniketos.securebpmn.satmc.SatmcFact; +import eu.aniketos.securebpmn.satmc.SatmcFunction; +import eu.aniketos.securebpmn.satmc.SatmcMessage; +import eu.aniketos.securebpmn.satmc.SatmcTraceStep; +import eu.aniketos.securebpmn.satmc.Summary; +import eu.aniketos.securebpmn.util.DialogUtil; +import eu.aniketos.securebpmn.validation.SCVMValidationConstants; +import eu.aniketos.securebpmn.validation.ValidateAslanRunnable; +import eu.aniketos.securebpmn.visualization.ActionType; +import eu.aniketos.securebpmn.visualization.VisualizationElement; +import eu.aniketos.securebpmn.visualization.rbac.AttackTracePlayer; +import eu.aniketos.securebpmn.visualization.rbac.AttackTraceStep; +import eu.aniketos.securebpmn.visualization.rbac.RbacVisualization; + +/** + * This feature performs an analysis of the access control specification and + * constraints contained in the process and notifies the user, if violations + * were found or not. This feature is not intended for direct use, you should + * use the class ValidateAslanLocalFeature or ValidateAslanWebFeature, depending + * on how you want SATMC to be executed. + * + * + */ +public class ValidateAslanFeature extends AbstractCustomFeature { + + public ValidateAslanFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.graphiti.features.impl.AbstractFeature#getName() + */ + @Override + public String getName() { + return "Validate ASLan"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#getDescription + * () + */ + @Override + public String getDescription() { + return "Validate ASLan using SATMC"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.AbstractCustomFeature#canExecute + * (org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse + * .graphiti.features.context.ICustomContext) + */ + public void execute(ICustomContext context) { + this.execute(true); + } + + /** + * Starts the analysis of the ASLan representation and reacts according to + * the result, either displaying a message to the user or starting the + * attack trace visualization if an attack was found. + * + * @param local + * true if the local SATMC binary should be used, false if the + * SATMC web service should be used. + */ + public void execute(boolean local) { + + // check for unsupported elements. + List unsupportedElements = getUnsupportedElementTypes(); + + if (unsupportedElements.size() > 0) { + // ask user what to do + StringBuilder ueMessage = new StringBuilder(); + ueMessage + .append("The diagram contains the following currently unsupported elements:\n"); + for (String ue : unsupportedElements) { + ueMessage.append(ue.endsWith("Impl") ? ue.substring(0, + ue.length() - 4) : ue); + ueMessage.append("\n"); + } + ueMessage + .append("\nThe analysis result might be incorrect. Continue anyway?"); + String[] ueButtons = { "Continue", "Cancel" }; + + int ueContinue = DialogUtil.openMessageDialog( + "Unsupported elements found!", ueMessage.toString(), + DialogUtil.WARNING, ueButtons, 1); + + if (ueContinue == 1) + return; + } + + // get & parse result + SatmcMessage result = new SatmcMessage(null, null, null, null); + + try { + + final IProgressService progressService = PlatformUI.getWorkbench() + .getProgressService(); + + final ValidateAslanRunnable runnable = new ValidateAslanRunnable( + getDiagram(), result, local); + + progressService.busyCursorWhile(runnable); + + } catch (Exception e) { + e.printStackTrace(); + } + + // check if validation/parsing was successful + if (result.summary == null) { + return; + + } else if (result.summary == Summary.ERROR) { + DialogUtil.openMessageDialog("Error", "SATMC Error", + DialogUtil.ERROR); + return; + + } else if (result.summary == Summary.INCONCLUSIVE) { + DialogUtil.openMessageDialog("Validation inconclusive", + "SATMC analysis was inconclusive.", DialogUtil.INFO); + return; + + } else if (result.summary == Summary.NO_ATTACK_FOUND) { + DialogUtil.openMessageDialog("No attack found", "No attack found!", + DialogUtil.INFO); + return; + + } else if (result.summary == Summary.UNKNOWN) { + DialogUtil.openMessageDialog("Unknown result", + "SATMC result is unknown!", DialogUtil.WARNING); + return; + + } else if (result.summary == Summary.ATTACK_FOUND) { + + List traceList = extractElementIDsAndDescription(result); + + DialogUtil.openMessageDialog("Attack found", + "Attack found!\n\nViolated goal: " + result.goal, + DialogUtil.ERROR); + + // set result in storage + RbacVisualization.getInstance().setResult(result); + + findBusinessObjectsAndPictogramElements(traceList); + + // create & store player + RbacVisualization.getInstance().setPlayer( + new AttackTracePlayer(getDiagram(), traceList)); + + // open view + try { + PlatformUI + .getWorkbench() + .getActiveWorkbenchWindow() + .getActivePage() + .showView( + "eu.aniketos.securebpmn.validation.view"); + } catch (PartInitException e) { + e.printStackTrace(); + } + + } + + } + + /** + * Replaces the task instance IDs with the task IDs in the violated goal of + * the result. Extracts the attack trace steps and for each step the task + * ID, the type of the step (claim, execute or violation) and the + * description of the step. + * + * @param result + * The SATMC result that should be analyzed and modified. + * @return A List of AttackTraceSteps, each step containing the task ID, + * type and description. + */ + private List extractElementIDsAndDescription( + SatmcMessage result) { + + List traceList = new ArrayList(); + + // dummy step for StartEvent + traceList.add(new AttackTraceStep()); + + // get number of tasks in goal + int tasksInGoal = 0; + for (SatmcFact fact : result.goal.args) { + if (fact instanceof SatmcFunction) { + SatmcFunction func = (SatmcFunction) fact; + if (func.name.equals("n") && func.args.size() == 1) { + tasksInGoal++; + } + } + } + int goalTasksStartIndex = result.goal.args.size() - tasksInGoal; + + // Goals: + // name: sod; args: 0. user 1. task1 2. task2 + // name: bod; args: 0. user1 1. user2 2. task1 3. task2 + + // Rules: + // name: h_TaskExecution; args: 0. user 1. role 2. task 3. tInstance + // 4. inData 5. outData + // name: atask_execution; args: 0. task 1. tInstance 2. inData 3. + // outData + // name: authorizeTaskExecution; args: 0. user 1. role 2. task 3. + // tInstance + for (SatmcTraceStep sts : result.trace) { + + AttackTraceStep traceElement = new AttackTraceStep(); + String stepText = ""; + + for (SatmcFunction rule : sts.rules) { + + if (rule.args.size() > 5 + && rule.name + .equals(SCVMValidationConstants.HUMAN_TASK_RULE_NAME)) { + + // UserTask + + // replace taskInstances with taskIDs in goal + if (result.goal.args.size() > 2 + && result.goal.name + .startsWith(SCVMValidationConstants.GOAL_SOD_PREFIX)) { + + for (int i = goalTasksStartIndex; i < result.goal.args + .size(); i++) { + if (rule.args.get(3).toString() + .equals(result.goal.args.get(i).toString())) { + result.goal.args.set(i, rule.args.get(2)); + } + } + } else if (result.goal.args.size() > 3 + && result.goal.name + .startsWith(SCVMValidationConstants.GOAL_BOD_PREFIX)) { + + for (int i = goalTasksStartIndex; i < result.goal.args + .size(); i++) { + if (rule.args.get(3).toString() + .equals(result.goal.args.get(i).toString())) { + result.goal.args.set(i, rule.args.get(2)); + } + } + } + + traceElement.addInvolvedElement(new VisualizationElement( + rule.args.get(2).toString(), ActionType.EXECUTE)); + stepText += "Human task \"" + rule.args.get(2).toString() + + "\" executed by user \"" + + rule.args.get(0).toString() + "\" with role \"" + + rule.args.get(1).toString() + "\".\n"; + + } else if (rule.args.size() > 3 + && rule.name + .equals(SCVMValidationConstants.AUTOMATED_TASK_RULE_NAME)) { + + // any other Task + + traceElement.addInvolvedElement(new VisualizationElement( + rule.args.get(0).toString(), ActionType.EXECUTE)); + stepText += "Automated task \"" + + rule.args.get(0).toString() + "\" executed.\n"; + + } else if (rule.args.size() > 3 + && rule.name + .equals(SCVMValidationConstants.TASK_AUTHORIZATION_RULE_NAME)) { + + // claiming of a Task + + traceElement.addInvolvedElement(new VisualizationElement( + rule.args.get(2).toString(), ActionType.CLAIM)); + stepText += "User \"" + rule.args.get(0).toString() + + "\" claimed task \"" + + rule.args.get(2).toString() + "\" using role \"" + + rule.args.get(1).toString() + "\".\n"; + + } else { + // check for gateway + + String[] ruleNameParts = rule.name.split("_"); + + if (ruleNameParts.length > 1) { + + if (ruleNameParts[0].equals("w") + && ruleNameParts[1].contains("gateway")) { + + // AND-split or AND-join + traceElement + .addInvolvedElement(new VisualizationElement( + ruleNameParts[1], + ActionType.WORKFLOW)); + stepText += "Passing parallel gateway \"" + + ruleNameParts[1] + "\".\n"; + + } else if (ruleNameParts[0].contains("gateway") + && ruleNameParts[1].startsWith("branch")) { + + // XOR-split or XOR-join + traceElement + .addInvolvedElement(new VisualizationElement( + ruleNameParts[0], + ActionType.WORKFLOW)); + stepText += "Passing exclusive gateway \"" + + ruleNameParts[0] + "\".\n"; + + } + + } + + } + } + + if (traceElement.getInvolvedElements().size() > 0) { + traceElement.setDescription(stepText); + traceList.add(traceElement); + } + } + + // step for goal violation highlighting + AttackTraceStep goalStep = new AttackTraceStep(); + goalStep.setDescription("Violation of goal \"" + result.goal.toString() + + "\"."); + + if (result.goal.args.size() > 2 + && result.goal.name + .startsWith(SCVMValidationConstants.GOAL_SOD_PREFIX)) { + // SoD + for (int i = goalTasksStartIndex; i < result.goal.args.size(); i++) { + goalStep.addInvolvedElement(new VisualizationElement( + result.goal.args.get(i).toString(), + ActionType.VIOLATION)); + } + + String sodElementID = result.goal.name.substring( + SCVMValidationConstants.GOAL_SOD_PREFIX.length(), + result.goal.name.lastIndexOf("_")); + goalStep.addInvolvedElement(new VisualizationElement(sodElementID, + ActionType.VIOLATION)); + + } else if (result.goal.args.size() > 3 + && result.goal.name + .startsWith(SCVMValidationConstants.GOAL_BOD_PREFIX)) { + // BoD + for (int i = goalTasksStartIndex; i < result.goal.args.size(); i++) { + goalStep.addInvolvedElement(new VisualizationElement( + result.goal.args.get(i).toString(), + ActionType.VIOLATION)); + } + + String bodElementID = result.goal.name.substring( + SCVMValidationConstants.GOAL_BOD_PREFIX.length(), + result.goal.name.lastIndexOf("_")); + goalStep.addInvolvedElement(new VisualizationElement(bodElementID, + ActionType.VIOLATION)); + } + + traceList.add(goalStep); + + return traceList; + + } + + /** + * Finds the BusinessObjects and PictogramElements for each task ID in the + * provided lists and adds these to the single elements in the list. + * + * @param traceList + * The List of AttackTraceSteps for which the BOs and PEs should + * be found. + */ + private void findBusinessObjectsAndPictogramElements( + List traceList) { + + // get diagram elements + List diagramElements = new ArrayList(); + for (EObject object : getDiagram().eResource().getContents()) { + if (object instanceof FlowElement) + diagramElements.add((FlowElement) object); + } + + for (AttackTraceStep traceStep : traceList) { + for (VisualizationElement element : traceStep.getInvolvedElements()) { + + // find BO + for (FlowElement bo : diagramElements) { + if (bo.getId().equals(element.getId())) { + element.setbObject(bo); + break; + } + } + + if (element.getbObject() == null) { + System.err + .println("[SCVM-RBAC] No FlowElement found for ID \"" + + element.getId() + "\"!"); + } + + // find corresponding PE + List pElements = Graphiti.getLinkService() + .getPictogramElements(getDiagram(), + element.getbObject()); + + for (PictogramElement pElement : pElements) { + + if (pElement instanceof ContainerShape) { + + ContainerShape cs = (ContainerShape) pElement; + + element.setpElement(cs); + + } + } + + if (element.getpElement() == null) { + System.err + .println("[SCVM-RBAC] No PictogramElement found for ID \"" + + element.getId() + "\"!"); + } + + } + } + + // get and add start event + // there should only be one FlowNode after a StartEvent + + StartEvent startEvent = null; + + // find start event + if (traceList.size() > 1) { + + List firstElements = traceList.get(1) + .getInvolvedElements(); + + if (firstElements.size() > 0) { + + FlowNode firstNode = (FlowNode) firstElements.get(0) + .getbObject(); + + if (firstNode.getIncoming().size() > 0) { + FlowNode start = firstNode.getIncoming().get(0) + .getSourceRef(); + + if (start instanceof StartEvent) { + + startEvent = (StartEvent) start; + + } + } + } + + } + + // create entry if we found it + if (startEvent != null) { + + VisualizationElement startElement = new VisualizationElement( + startEvent.getId(), ActionType.WORKFLOW); + startElement.setbObject(startEvent); + + // find corresponding pictogram element + List pElements = Graphiti.getLinkService() + .getPictogramElements(getDiagram(), startEvent); + + for (PictogramElement pElement : pElements) { + + // change element representation + if (pElement instanceof ContainerShape) { + + ContainerShape cs = (ContainerShape) pElement; + startElement.setpElement(cs); + + } + } + + traceList.get(0).addInvolvedElement(startElement); + traceList.get(0).setDescription("The process has been started."); + } + + } + + /** + * Returns a list with the names of the BPMN 2.0 elements that are currently + * not supported by the analysis. + * + * @return A List with the names of the unsupported elements as Strings. + */ + private List getUnsupportedElementTypes() { + List res = new ArrayList(); + + for (EObject object : getDiagram().eResource().getContents()) { + + if (object instanceof SubProcess || object instanceof CallActivity + || object instanceof InclusiveGateway + || object instanceof BoundaryEvent) { + res.add(object.getClass().getSimpleName()); + } + + } + + // remove duplicates + HashSet h = new HashSet(res); + res.clear(); + res.addAll(h); + + return res; + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanLocalFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanLocalFeature.java new file mode 100644 index 0000000..0aa4515 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanLocalFeature.java @@ -0,0 +1,82 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; + +/** + * This feature performs an analysis of the access control specification and + * constraints contained in the process and notifies the user, if violations + * were found or not. For analysis of the ASLan file, the local SATMC binary is + * used. + * + * + */ +public class ValidateAslanLocalFeature extends ValidateAslanFeature { + + public ValidateAslanLocalFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #getName() + */ + @Override + public String getName() { + return "Validate security local"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #getDescription() + */ + @Override + public String getDescription() { + return "Validate security featues using local SATMC binary"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #canExecute(org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #execute(org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public void execute(ICustomContext context) { + super.execute(true); + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanWebFeature.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanWebFeature.java new file mode 100644 index 0000000..d381a93 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/features/ValidateAslanWebFeature.java @@ -0,0 +1,82 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.features; + +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.ICustomContext; + +/** + * This feature performs an analysis of the access control specification and + * constraints contained in the process and notifies the user, if violations + * were found or not. For analysis of the ASLan file, the SATMC web service is + * used. + * + * + */ +public class ValidateAslanWebFeature extends ValidateAslanFeature { + + public ValidateAslanWebFeature(IFeatureProvider fp) { + super(fp); + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #getName() + */ + @Override + public String getName() { + return "Validate security web"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #getDescription() + */ + @Override + public String getDescription() { + return "Validate security featues using SATMC web service"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #canExecute(org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public boolean canExecute(ICustomContext context) { + return true; + } + + /* + * (non-Javadoc) + * + * @see + * eu.aniketos.securebpmn.features.ValidateAslanFeature + * #execute(org.eclipse.graphiti.features.context.ICustomContext) + */ + @Override + public void execute(ICustomContext context) { + super.execute(false); + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/ntk/NeedToKnowUtil.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/ntk/NeedToKnowUtil.java new file mode 100644 index 0000000..9518bb3 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/ntk/NeedToKnowUtil.java @@ -0,0 +1,453 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.ntk; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.bpmn2.Bpmn2Factory; +import org.eclipse.bpmn2.DataInput; +import org.eclipse.bpmn2.DataOutput; +import org.eclipse.bpmn2.FormProperty; +import org.eclipse.bpmn2.InputOutputSpecification; +import org.eclipse.bpmn2.InputSet; +import org.eclipse.bpmn2.OutputSet; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.securebpmn2.AuthorizationConstraint; +import org.eclipse.securebpmn2.ItemAwareElementAction; +import org.eclipse.securebpmn2.NeedToKnow; +import org.eclipse.securebpmn2.Permission; + +import eu.aniketos.securebpmn.validation.ProcVarAccess; +import eu.aniketos.securebpmn.validation.ProcVarListASTVisitor; + +/** + * This class contains utility methods that are being used in the need-to-know + * analysis. + * + * + */ +public class NeedToKnowUtil { + + public static final String ID_PREFIX_IOSPEC = "iospec_"; + public static final String ID_PREFIX_INSET = "inset_ntk_"; + public static final String ID_PREFIX_OUTSET = "outset_ntk_"; + public static final String ID_PREFIX_INPUT = "input_ntk_"; + public static final String ID_PREFIX_OUTPUT = "output_ntk_"; + + /** + * Provides the names of the SecureBPMN ItemAwareElementActions that are + * used. + * + * @return An Array containing the names of the ItemAwareElementActions as + * Strings. + */ + public static String[] getItemAwareElementActionNames() { + + return new String[] { "read", "write", "read/write" }; + } + + /** + * Finds the names of the process variables that are accessed in the + * provided task. Only the HTML forms of a UserTask and the Java + * implementation of a ServiceTask can be analyzed. + * + * @param task + * The task (UserTask or ServiceTask) that should be analyzed. + * @return A List with the names of the accessed process variables as + * Strings. + */ + public static List getAccessedProcessVariableNames(Task task) { + + List result = new ArrayList(); + + List varAccesses = new ArrayList(); + + if (task instanceof UserTask) { + varAccesses = getAccessedProcessVariables((UserTask) task); + } else if (task instanceof ServiceTask) { + varAccesses = getAccessedProcessVariables((ServiceTask) task); + } + + for (ProcVarAccess var : varAccesses) { + final String varName = var.getName(); + if (!result.contains(varName)) + result.add(varName); + } + + return result; + + } + + /** + * Analyzes a UserTask and extracts the process variables that are accesses + * and the type of access (read, write or both). Note that only the Activiti + * built-in HTML forms are analyzed. + * + * @param userTask + * The UserTask that should be analyzed. + * @return A List containing the process variable accesses represented as + * ProcVarAccess. + */ + public static List getAccessedProcessVariables( + UserTask userTask) { + + List result = new ArrayList(); + + for (FormProperty fp : userTask.getFormProperties()) { + + boolean var = false; + String expr = fp.getValue(); + + if (expr.startsWith("${") && expr.endsWith("}")) { + expr = expr.substring(2, expr.length() - 1); + var = true; + } + + if (var) { + // variable access + if (fp.getReadable() != null && fp.getReadable() + && fp.getWriteable() != null && !fp.getWriteable()) { + // read only + result.add(new ProcVarAccess(expr, -1, false)); + } else if (fp.getReadable() != null && !fp.getReadable() + && fp.getWriteable() != null && fp.getWriteable()) { + // write only + result.add(new ProcVarAccess(expr, -1, true)); + } else { + // read/write default assumption + result.add(new ProcVarAccess(expr, -1, false)); + result.add(new ProcVarAccess(expr, -1, true)); + } + } + } + + return result; + + } + + /** + * Analyzes a ServiceTask and extracts the process variables that are + * accesses and the type of access (read, write or both). Note that only + * ServiceTasks with a Java implementation are analyzed. + * + * @param serviceTask + * The ServiceTask that should be analyzed. + * @return A List containing the process variable accesses represented as + * ProcVarAccess. + */ + public static List getAccessedProcessVariables( + ServiceTask serviceTask) { + + List result = new ArrayList(); + + // check if service task has valid java impl + if (serviceTask.getImplementationType() == null + || !(serviceTask.getImplementationType().equals("classType"))) { + return result; + } + + if (serviceTask.getImplementation() == null + || serviceTask.getImplementation().length() == 0) { + return result; + } + + final String canonicalClassName = serviceTask.getImplementation(); + String[] classParts = canonicalClassName.split("\\."); + String implFileName = classParts[classParts.length - 1] + ".java"; + + StringBuilder sb = new StringBuilder(); + sb.append("/"); + sb.append("src"); + sb.append("/"); + sb.append("main"); + sb.append("/"); + sb.append("java"); + sb.append("/"); + for (int i = 0; i < classParts.length - 1; i++) { + sb.append(classParts[i]); + sb.append("/"); + } + sb.append(implFileName); + + IResource resourceToRead = null; + int filesFound = 0; + + IWorkspace workspace = ResourcesPlugin.getWorkspace(); + IWorkspaceRoot root = workspace.getRoot(); + IProject[] projects = root.getProjects(); + for (IProject project : projects) { + IResource resourceInRuntimeWorkspace = root.findMember(project + .getName() + sb.toString()); + if (resourceInRuntimeWorkspace != null) { + filesFound++; + if (resourceToRead == null) { + resourceToRead = resourceInRuntimeWorkspace; + } + } + } + + if (filesFound == 0) { + return result; + } else if (filesFound > 1) { + System.err + .println("[ListProcVar WARNING] Found multiple source files for class: " + + canonicalClassName); + } + + // read file + StringBuffer fileData = new StringBuffer(1000); + try { + BufferedReader reader = new BufferedReader(new FileReader(new File( + resourceToRead.getLocationURI()))); + char[] buf = new char[1024]; + int numRead = 0; + while ((numRead = reader.read(buf)) != -1) { + String readData = String.valueOf(buf, 0, numRead); + fileData.append(readData); + buf = new char[1024]; + } + reader.close(); + } catch (Exception e) { + System.err + .println("[ListProcVar ERROR] Error reading source file for class \"" + + canonicalClassName + "\": " + e.getMessage()); + return result; + } + + // build AST for Impl + ASTParser parser = ASTParser.newParser(AST.JLS3); + parser.setKind(ASTParser.K_COMPILATION_UNIT); + parser.setSource(fileData.toString().toCharArray()); + CompilationUnit node = (CompilationUnit) parser.createAST(null); + node.accept(new ProcVarListASTVisitor(result)); + + return result; + + } + + /** + * Updates the BPMN 2.0 elements that represent the process variable access + * of a given task, in particular, DataInput and DataOutput elements. + * + * @param task + * The task whose elements should be updated. + * @param diagram + * The diagram containing the task. + */ + public static void updateIOSpecification(Task task, Diagram diagram) { + + if (!(task instanceof UserTask || task instanceof ServiceTask)) + return; + + InputOutputSpecification iospec = task.getIoSpecification(); + // create InputOutputSpecification if missing + if (iospec == null) { + iospec = Bpmn2Factory.eINSTANCE.createInputOutputSpecification(); + iospec.setId(ID_PREFIX_IOSPEC + task.getId()); + task.setIoSpecification(iospec); + diagram.eResource().getContents().add(iospec); + } + + // keep InputOutputSpecification ID consistent with Task ID + if (!iospec.getId().equals(ID_PREFIX_IOSPEC + task.getId())) { + task.getIoSpecification().setId(ID_PREFIX_IOSPEC + task.getId()); + } + + // search for NtK InputSet + InputSet inSet = null; + for (InputSet tmpInSet : iospec.getInputSets()) { + if (tmpInSet.getId().equals(ID_PREFIX_INSET + task.getId())) { + inSet = tmpInSet; + break; + } + } + if (inSet == null) { + inSet = Bpmn2Factory.eINSTANCE.createInputSet(); + inSet.setId(ID_PREFIX_INSET + task.getId()); + inSet.setName("Need-to-know DataObjects read by task " + + task.getId()); + iospec.getInputSets().add(inSet); + diagram.eResource().getContents().add(inSet); + } + + // search for NtK OutputSet + OutputSet outSet = null; + for (OutputSet tmpOutSet : iospec.getOutputSets()) { + if (tmpOutSet.getId().equals(ID_PREFIX_OUTSET + task.getId())) { + outSet = tmpOutSet; + break; + } + } + if (outSet == null) { + outSet = Bpmn2Factory.eINSTANCE.createOutputSet(); + outSet.setId(ID_PREFIX_OUTSET + task.getId()); + outSet.setName("Need-to-know DataObjects written by task " + + task.getId()); + iospec.getOutputSets().add(outSet); + diagram.eResource().getContents().add(outSet); + } + + // create DataInput/DataOutput elements + List varAccesses = new ArrayList(); + if (task instanceof UserTask) { + varAccesses = getAccessedProcessVariables((UserTask) task); + } else { + varAccesses = getAccessedProcessVariables((ServiceTask) task); + } + + // add new elements + List diagramElements = diagram.eResource().getContents(); + for (ProcVarAccess varAccess : varAccesses) { + if (varAccess.isWrite()) { + // check if DataOutput element exists in diagram + DataOutput output = null; + for (EObject obj : diagramElements) { + if (obj instanceof DataOutput) { + if (((DataOutput) obj).getId().equals( + ID_PREFIX_OUTPUT + varAccess.getName())) { + output = (DataOutput) obj; + break; + } + } + } + if (output == null) { + // DataOutput does not exist, create + output = Bpmn2Factory.eINSTANCE.createDataOutput(); + output.setId(ID_PREFIX_OUTPUT + varAccess.getName()); + outSet.getDataOutputRefs().add(output); + output.getOutputSetRefs().add(outSet); + diagram.eResource().getContents().add(output); + } else { + // check if DataOutput element exists in OutputSet + if (!outSet.getDataOutputRefs().contains(output)) { + outSet.getDataOutputRefs().add(output); + output.getOutputSetRefs().add(outSet); + } + } + } else { + // check if DataInput exists in diagram + DataInput input = null; + for (EObject obj : diagramElements) { + if (obj instanceof DataInput) { + if (((DataInput) obj).getId().equals( + ID_PREFIX_INPUT + varAccess.getName())) { + input = (DataInput) obj; + break; + } + } + } + if (input == null) { + // DataInput does not exist, create + input = Bpmn2Factory.eINSTANCE.createDataInput(); + input.setId(ID_PREFIX_INPUT + varAccess.getName()); + inSet.getDataInputRefs().add(input); + input.getInputSetRefs().add(inSet); + diagram.eResource().getContents().add(input); + } else { + // check if DataInput element exists in InputSet + if (!inSet.getDataInputRefs().contains(input)) { + inSet.getDataInputRefs().add(input); + input.getInputSetRefs().add(inSet); + } + } + } + } + + // remove elements for missing process variables + for (DataInput in : inSet.getDataInputRefs()) { + boolean varDeleted = true; + for (ProcVarAccess pvar : varAccesses) { + if (in.getId().equals(ID_PREFIX_INPUT + pvar.getName()) + && !pvar.isWrite()) { + varDeleted = false; + break; + } + } + if (varDeleted) { + inSet.getDataInputRefs().remove(in); + in.getInputSetRefs().remove(inSet); + if (in.getInputSetRefs().size() == 0) { + diagram.eResource().getContents().remove(in); + } + for (ItemAwareElementAction iaea : in + .getItemAwareElementActions()) { + for (Permission p : iaea.getPermissions()) { + p.getActions().remove(iaea); + } + } + } + } + + for (DataOutput out : outSet.getDataOutputRefs()) { + boolean varDeleted = true; + for (ProcVarAccess pvar : varAccesses) { + if (out.getId().equals(ID_PREFIX_OUTPUT + pvar.getName()) + && pvar.isWrite()) { + varDeleted = false; + break; + } + } + if (varDeleted) { + outSet.getDataOutputRefs().remove(out); + out.getOutputSetRefs().remove(outSet); + if (out.getOutputSetRefs().size() == 0) { + diagram.eResource().getContents().remove(out); + } + for (ItemAwareElementAction iaea : out + .getItemAwareElementActions()) { + for (Permission p : iaea.getPermissions()) { + p.getActions().remove(iaea); + } + } + } + } + + // remove broken NtK permissions + for (EObject o : diagramElements) { + if (o instanceof NeedToKnow) { + NeedToKnow ntk = (NeedToKnow) o; + + if (ntk.getActions().size() == 0) { + // delete ActivityAC + for (AuthorizationConstraint ac : ntk + .getAuthorizationConstraints()) { + diagram.eResource().getContents().remove(ac); + } + // delete NtK + diagram.eResource().getContents().remove(ntk); + } + } + } + + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDef.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDef.java new file mode 100644 index 0000000..f09d2ee --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDef.java @@ -0,0 +1,71 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.roles; + +import java.util.ArrayList; +import java.util.List; + +/** + * A definition of a role and the containing users in the user/role definition + * file. + * + * + */ +public class RoleDef implements RoleDefLine { + + private String roleName; + private List members; + + /** + * Creates a role definition. + * + * @param roleName + * The name of the role. + */ + public RoleDef(String roleName) { + this.roleName = roleName; + members = new ArrayList(); + } + + /** + * Adds a member to the role. + * + * @param member + * The name of a new member as a String. + */ + public void addMember(String member) { + members.add(member); + } + + /** + * Returns the name of the role. + * + * @return The name of the role as a String. + */ + public String getRoleName() { + return roleName; + } + + /** + * Returns the name of the members of the role. + * + * @return A List containing the names of the members. + */ + public List getMembers() { + return members; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDefLine.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDefLine.java new file mode 100644 index 0000000..4e2769b --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleDefLine.java @@ -0,0 +1,25 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.roles; + +/** + * An Interface that represents a line in the user/role definition file. + * + * + */ +public interface RoleDefLine { + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleRel.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleRel.java new file mode 100644 index 0000000..30dc462 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/roles/RoleRel.java @@ -0,0 +1,60 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.roles; + +/** + * A definition of a relation between two roles in the role hierarchy, used in + * the user/role definition file. + * + * + */ +public class RoleRel implements RoleDefLine { + + private String superRole; + private String subRole; + + /** + * Creates a relation between two roles. + * + * @param superRole + * The name of the higher role. + * @param subRole + * The name of the lower role. + */ + public RoleRel(String superRole, String subRole) { + this.superRole = superRole; + this.subRole = subRole; + } + + /** + * Returns the name of the higher role. + * + * @return The name of the higher role as a String. + */ + public String getSuperRole() { + return superRole; + } + + /** + * Returns the name of the lower role. + * + * @return The Name of the lower role as a String. + */ + public String getSubRole() { + return subRole; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFact.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFact.java new file mode 100644 index 0000000..e08b24b --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFact.java @@ -0,0 +1,25 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +/** + * This Interface represents a fact in the SATMC output. + * + * + */ +public interface SatmcFact { + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFunction.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFunction.java new file mode 100644 index 0000000..f62f63e --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcFunction.java @@ -0,0 +1,53 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +import java.util.List; + +/** + * This Class represents a function in the SATMC output. + * + * + */ +public class SatmcFunction implements SatmcFact { + public String name; + public List args; + + public SatmcFunction(String name, List args) { + this.name = name; + this.args = args; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + String res = name + "("; + boolean first = true; + for (SatmcFact sf : args) { + if (first) { + first = false; + } else { + res += ","; + } + res += sf.toString(); + } + return res + ")"; + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcMessage.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcMessage.java new file mode 100644 index 0000000..38d7318 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcMessage.java @@ -0,0 +1,38 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +import java.util.List; + +/** + * Wrapper class for the parsed SATMC output. + * + * + */ +public class SatmcMessage { + public Summary summary; + public SatmcFunction goal; + public List trace; + public List cfs; + + public SatmcMessage(Summary summary, SatmcFunction goal, + List trace, List cfs) { + this.summary = summary; + this.goal = goal; + this.trace = trace; + this.cfs = cfs; + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcTraceStep.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcTraceStep.java new file mode 100644 index 0000000..3d4afd2 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcTraceStep.java @@ -0,0 +1,33 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +import java.util.List; + +/** + * This Class represents a step in the attack trace of the SATMC output. + * + * + */ +public class SatmcTraceStep { + public List clauses; + public List rules; + + public SatmcTraceStep(List clauses, List rules) { + this.clauses = clauses; + this.rules = rules; + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcVar.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcVar.java new file mode 100644 index 0000000..af6a2f7 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/SatmcVar.java @@ -0,0 +1,39 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +/** + * This Class represents a variable (text/numbers only) in the SATMC output. + * + * + */ +public class SatmcVar implements SatmcFact { + public String name; + + public SatmcVar(String name) { + this.name = name; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return name; + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/Summary.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/Summary.java new file mode 100644 index 0000000..ac29c2f --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/satmc/Summary.java @@ -0,0 +1,25 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.satmc; + +/** + * The different summary types of the SATMC output. + * + * + */ +public enum Summary { + ATTACK_FOUND, NO_ATTACK_FOUND, INCONCLUSIVE, ERROR, UNKNOWN +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/DialogUtil.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/DialogUtil.java new file mode 100644 index 0000000..f3a61ae --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/DialogUtil.java @@ -0,0 +1,134 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.util; + +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +/** + * Creates user notification/input dialogs. + * + */ + +public class DialogUtil { + + public static final int ERROR = 2; + public static final int WARNING = 1; + public static final int INFO = 0; + + /** + * Get the currently active Shell or the first available one if none is + * active. + * + * @return The current Shell. + */ + private static Shell getShell() { + Display display = PlatformUI.getWorkbench().getDisplay(); + + Shell shell = display.getActiveShell(); + + if (shell == null) { + // eclipse window not active, get first shell + Shell[] shells = display.getShells(); + shell = shells.length > 0 ? shells[0] : null; + } + + return shell; + } + + /** + * Opens a dialog window that contains a message and an input field. The + * input is returned as a String. + * + * @param title + * The title of the message window. + * @param message + * The message to be displayed in the window. + * @param initialValue + * The initial value of the input field. + * @param validator + * An InputValidator Class that checks the contents of the input + * field. + * @return The contents of the input field as a String. + */ + public static String openInputDialog(String title, String message, + String initialValue, IInputValidator validator) { + InputDialog id = new InputDialog(getShell(), title, message, + initialValue, validator); + id.open(); + + return id.getValue(); + } + + /** + * Opens a dialog window that contains an image and a message. + * + * @param title + * The title of the message window. + * @param message + * The message to be displayed in the window. + * @param image + * The image that should be displayed in the window. + * @param buttons + * The labels of the Buttons the window should contain. + * @param defaultButton + * The index of the Button that should be selected by default. + * @return The index of the Button that was pressed. + */ + public static int openMessageDialog(String title, String message, + int image, String[] buttons, int defaultButton) { + MessageDialog dialog; + switch (image) { + case INFO: + dialog = new MessageDialog(getShell(), title, null, message, + MessageDialog.INFORMATION, buttons, defaultButton); + break; + case WARNING: + dialog = new MessageDialog(getShell(), title, null, message, + MessageDialog.WARNING, buttons, defaultButton); + break; + case ERROR: + dialog = new MessageDialog(getShell(), title, null, message, + MessageDialog.ERROR, buttons, defaultButton); + break; + default: + dialog = new MessageDialog(getShell(), title, null, message, + MessageDialog.NONE, buttons, defaultButton); + break; + } + return dialog.open(); + } + + /** + * Opens a dialog window that contains an image and a message. + * + * @param title + * The title of the message window. + * @param message + * The message to be displayed in the window. + * @param image + * The image that should be displayed in the window. + * @return The index of the Button that was pressed. + */ + public static int openMessageDialog(String title, String message, int image) { + return openMessageDialog(title, message, image, new String[] { "OK" }, + 0); + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/SecurityUtil.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/SecurityUtil.java new file mode 100644 index 0000000..82cfb3a --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/util/SecurityUtil.java @@ -0,0 +1,360 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.util; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.activiti.designer.util.eclipse.ActivitiUiUtil; +import org.antlr.roledef.RoleDefLexer; +import org.antlr.roledef.RoleDefParser; +import org.antlr.runtime.ANTLRStringStream; +import org.antlr.runtime.CommonTokenStream; +import org.antlr.runtime.RecognitionException; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.securebpmn2.Action; +import org.eclipse.securebpmn2.Role; +import org.eclipse.securebpmn2.Securebpmn2Factory; +import org.eclipse.securebpmn2.Subject; +import org.eclipse.securebpmn2.User; + +import eu.aniketos.securebpmn.roles.RoleDef; +import eu.aniketos.securebpmn.roles.RoleDefLine; +import eu.aniketos.securebpmn.roles.RoleRel; + +/** + * This Class contains utility methods for retrieving Users, Roles and + * ActivityActions. + * + * + */ +public class SecurityUtil { + + private static List roles; + private static List users; + private static List activityActions; + private static String diagramName; + + /** + * Retrieve the roles for a given Diagram. + * + * @param diagram + * The diagram for which the roles should be retrieved. + * @return A List of Roles that are specified for the Diagram. + */ + public static List getRoles(Diagram diagram) { + if (diagram == null || diagram.getName() == null) + return new ArrayList(); + + if (diagramName == null) { + diagramName = diagram.getName(); + } + + if (roles == null || !diagram.getName().equals(diagramName)) { + loadRolesAndUsers(diagram); + } + return roles; + } + + /** + * Retrieve the users for a given Diagram. + * + * @param diagram + * The diagram for which the users should be retrieved. + * @return A List of Users that are specified for the Diagram. + */ + public static List getUsers(Diagram diagram) { + if (diagramName == null) { + diagramName = diagram.getName(); + } + + if (users == null || !diagram.getName().equals(diagramName)) { + loadRolesAndUsers(diagram); + } + return users; + } + + /** + * Retrieve the ActivityActions that are currently available. + * + * @return A List of ActivityActions that are available. + */ + public static List getActivityActions() { + if (activityActions == null) { + activityActions = new ArrayList(); + + Action claimActivityAction = Securebpmn2Factory.eINSTANCE + .createAtomicActivityAction(); + claimActivityAction.setId(UUID.randomUUID().toString()); + claimActivityAction.setActionName("Claim"); + Action assignActivityAction = Securebpmn2Factory.eINSTANCE + .createAtomicActivityAction(); + assignActivityAction.setId(UUID.randomUUID().toString()); + assignActivityAction.setActionName("Assign"); + Action completeActivityAction = Securebpmn2Factory.eINSTANCE + .createAtomicActivityAction(); + completeActivityAction.setActionName("Complete"); + completeActivityAction.setId(UUID.randomUUID().toString()); + Action fullAccess = Securebpmn2Factory.eINSTANCE + .createCompositeActivityAction(); + fullAccess.setActionName("Full Access"); + + activityActions.add(fullAccess); + activityActions.add(claimActivityAction); + activityActions.add(assignActivityAction); + activityActions.add(completeActivityAction); + + } + return activityActions; + } + + /** + * Loads the roles and users from the configuration file. The file must be + * located in the same folder as the Diagram and the filename must be the + * same name as the Diagram file with the extension .roles. + * + * @param diagram + * The Diagram for which the roles and users should be loaded. + */ + private static void loadRolesAndUsers(final Diagram diagram) { + + // clear roles and users that may exist + if (roles == null) { + roles = new ArrayList(); + } else { + roles.clear(); + } + + if (users == null) { + users = new ArrayList(); + } else { + users.clear(); + } + + // parse role file and fill lists + if (diagram != null) { + + // role hierarchy + List hierarchy = new ArrayList(); + + String in = ""; + + // get file location + URI uri = diagram.eResource().getURI(); + URI platformUri = uri.trimFragment(); + platformUri = platformUri.trimFileExtension(); + platformUri = platformUri.appendFileExtension("roles"); + + final IResource fileResource = ResourcesPlugin.getWorkspace() + .getRoot().findMember(platformUri.toPlatformString(true)); + if (fileResource != null && fileResource.exists()) { + final String fileUri = fileResource.getLocation().toString(); + + // read file + try { + in = readFileAsString(fileUri); + } catch (IOException e) { + System.err.println("[SCVM-RBAC] Error while reading file: " + + fileUri.toString()); + e.printStackTrace(); + } + } + + if (in.length() > 0) { + List lines = null; + + try { + RoleDefLexer lex = new RoleDefLexer(new ANTLRStringStream( + in)); + CommonTokenStream tokens = new CommonTokenStream(lex); + + RoleDefParser parser = new RoleDefParser(tokens); + lines = parser.file(); + + } catch (RecognitionException e) { + System.err + .println("[SCVM-RBAC] Error while parsing role/user file."); + e.printStackTrace(); + } + + // generate roles for result + if (lines != null) { + for (RoleDefLine line : lines) { + if (line instanceof RoleDef) { + final RoleDef def = (RoleDef) line; + + // create (if necessary) and add role + Role role = Securebpmn2Factory.eINSTANCE + .createRole(); + role.setName(def.getRoleName()); + role.setId(UUID.randomUUID().toString()); + roles.add(role); + + // create and add users to role + for (String userName : def.getMembers()) { + User user = Securebpmn2Factory.eINSTANCE + .createUser(); + user.setUserName(userName); + user.setId(userName.toLowerCase()); + users.add(user); + + user.getRoles().add(role); + role.getSubjects().add(user); + + } + + } else if (line instanceof RoleRel) { + hierarchy.add((RoleRel) line); + } + } + } + } + + // TODO order hierarchy list + + // assign new roles to users + for (RoleRel rel : hierarchy) { + + // find roles + Role supRole = null; + Role subRole = null; + for (Role r : roles) { + if (r.getName().equals(rel.getSuperRole()) + && supRole == null) + supRole = r; + if (r.getName().equals(rel.getSubRole()) && subRole == null) + subRole = r; + } + + // assign users to subroles + for (Subject s : supRole.getSubjects()) { + if (s instanceof User) { + User u = (User) s; + if (!u.getRoles().contains(subRole)) { + u.getRoles().add(subRole); + subRole.getSubjects().add(u); + } + } + } + } + + } + + if (roles.size() == 0) { + System.out + .println("[SCVM-RBAC] No roles or users provided, generating dummy roles and users."); + Role manager = Securebpmn2Factory.eINSTANCE.createRole(); + manager.setName("Manager"); + manager.setId(UUID.randomUUID().toString()); + Role supervisor = Securebpmn2Factory.eINSTANCE.createRole(); + supervisor.setName("Supervisor"); + supervisor.setId(UUID.randomUUID().toString()); + Role clerk = Securebpmn2Factory.eINSTANCE.createRole(); + clerk.setId(UUID.randomUUID().toString()); + clerk.setName("Clerk"); + roles.add(manager); + roles.add(supervisor); + roles.add(clerk); + } + + if (users.size() == 0) { + for (Role role : roles) { + User user1 = Securebpmn2Factory.eINSTANCE.createUser(); + user1.setUserName("user1_" + role.getName()); + user1.setId("user1_" + role.getName().toLowerCase()); + user1.getRoles().add(role); + User user2 = Securebpmn2Factory.eINSTANCE.createUser(); + user2.setUserName("user2_" + role.getName()); + user2.setId("user2_" + role.getName().toLowerCase()); + user2.getRoles().add(role); + } + } + + + // save users to diagram so that the editor won't crash loading a + // diagram with roles that reference to the users. + // unfortunately, the attributes of roles and users do not get loaded + // correctly when opening a .activiti file. + final List usersToAdd = new ArrayList(); + for (User u : users) { + boolean isInDiagram = false; + for (EObject o : diagram.eResource().getContents()) { + if (o instanceof User) { + User my_user = (User) o; + if (my_user.getId() != null + && my_user.getId().equals(u.getId())) { + isInDiagram = true; + break; + } + + } + } + if (!isInDiagram) { + usersToAdd.add(u); + } + + } + TransactionalEditingDomain editingDomain = TransactionUtil + .getEditingDomain(diagram); + + if (!usersToAdd.isEmpty()) { // should fix aslan generation bug with automated role generation + ActivitiUiUtil.runModelChange(new Runnable() { + public void run() { + for (User u : usersToAdd) { + diagram.eResource().getContents().add(u); + } + } + }, editingDomain, "User management"); + } + + } + /** + * Reads a file from disk and writes its contents to a String. + * + * @param filePath + * The path to the file. + * @return The contents of the file. + * @throws IOException + * Errors that occur accessing the file. + */ + public static String readFileAsString(String filePath) throws IOException { + byte[] buffer = new byte[(int) new File(filePath).length()]; + BufferedInputStream f = null; + try { + f = new BufferedInputStream(new FileInputStream(filePath)); + f.read(buffer); + } finally { + if (f != null) + try { + f.close(); + } catch (IOException ignored) { + } + } + return new String(buffer); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarAccess.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarAccess.java new file mode 100644 index 0000000..a4fbd33 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarAccess.java @@ -0,0 +1,63 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation; + +/** + * A class representing the access of a process variable. + * + * + */ +public class ProcVarAccess { + + private String name; + private int location; + private boolean write; + + public ProcVarAccess(String name, int location, boolean write) { + this.name = name; + this.location = location; + this.write = write; + } + + /** + * Returns the name of the process variable. + * + * @return The name of the process variable. + */ + public String getName() { + return name; + } + + /** + * Returns the location, where the access of the variable occurs. This is + * only applicable for accesses found in Java implementations. + * + * @return The location as the position in the file. + */ + public int getLocation() { + return location; + } + + /** + * Returns if the access is of type read or write + * + * @return true if the type is write, false if it is read. + */ + public boolean isWrite() { + return write; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarCheckASTVisitor.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarCheckASTVisitor.java new file mode 100644 index 0000000..9db4e93 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarCheckASTVisitor.java @@ -0,0 +1,129 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; + +/** + * Eclipse Java AST visitor class for checking if a certain process variable is + * accessed. + * + * + */ +public class ProcVarCheckASTVisitor extends ASTVisitor { + + private List delegateExecVars; + private List locations; + private String procVar; + private boolean importFound; + + /** + * Default constructor. + * + * @param procVar + * The name of the process variable that should be checked. + * @param locations + * A List where the locations of the accesses will be written to. + */ + public ProcVarCheckASTVisitor(String procVar, List locations) { + this.delegateExecVars = new ArrayList(); + this.locations = locations; + this.procVar = procVar; + this.importFound = false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * ImportDeclaration) + */ + @Override + public boolean visit(ImportDeclaration node) { + + String imp = node.getName().toString(); + + if (imp.equals("org.activiti.engine.delegate.DelegateExecution") + || imp.equals("org.activiti.engine.delegate.*") + || imp.equals("org.activiti.engine.*") + || imp.equals("org.activiti.*")) + importFound = true; + + return super.visit(node); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * SingleVariableDeclaration) + */ + @Override + public boolean visit(SingleVariableDeclaration node) { + + if (importFound + && node.getType().toString().equals("DelegateExecution")) { + delegateExecVars.add(node.getName().toString()); + } + + return super.visit(node); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodInvocation) + */ + @Override + public boolean visit(MethodInvocation node) { + + String methodName = node.getName().toString(); + + if (methodName.equals("getVariable") + || methodName.equals("setVariable")) { + // check if expression is of class + // org.activiti.engine.delegate.DelegateExecution + Expression expr = node.getExpression(); + if (expr instanceof SimpleName) { + if (!delegateExecVars.contains(((SimpleName) expr).toString())) + return super.visit(node); + } + + // check if argument matches procVar + if (node.arguments().size() > 0) { + Object arg = node.arguments().get(0); + if (arg instanceof StringLiteral) { + if (arg.toString().equals("\"" + procVar + "\"")) { + locations.add(node.getStartPosition()); + return false; + } + } + } + } + return super.visit(node); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarListASTVisitor.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarListASTVisitor.java new file mode 100644 index 0000000..d6df20c --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ProcVarListASTVisitor.java @@ -0,0 +1,135 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTVisitor; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.StringLiteral; + +/** + * Eclipse Java AST visitor class for listing all process variables that are + * being accessed and the way in which they are accessed (read or write). + * + * + */ +public class ProcVarListASTVisitor extends ASTVisitor { + + private List delegateExecVars; + private List varAccess; + private boolean importFound; + + /** + * Default constructor. + * + * @param varAccess + * The list where the found variable accesses will be saved to. + */ + public ProcVarListASTVisitor(List varAccess) { + this.delegateExecVars = new ArrayList(); + this.varAccess = varAccess; + this.importFound = false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * ImportDeclaration) + */ + @Override + public boolean visit(ImportDeclaration node) { + + String imp = node.getName().toString(); + + if (imp.equals("org.activiti.engine.delegate.DelegateExecution") + || imp.equals("org.activiti.engine.delegate.*") + || imp.equals("org.activiti.engine.*") + || imp.equals("org.activiti.*")) + importFound = true; + + return super.visit(node); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * SingleVariableDeclaration) + */ + @Override + public boolean visit(SingleVariableDeclaration node) { + + if (importFound + && node.getType().toString().equals("DelegateExecution")) { + delegateExecVars.add(node.getName().toString()); + } + + return super.visit(node); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom. + * MethodInvocation) + */ + @Override + public boolean visit(MethodInvocation node) { + + boolean read = false; + boolean write = false; + + String methodName = node.getName().toString(); + + // check if expression is of class + // org.activiti.engine.delegate.DelegateExecution + Expression expr = node.getExpression(); + if (expr instanceof SimpleName) { + if (!delegateExecVars.contains(((SimpleName) expr).toString())) + return super.visit(node); + } + + if (methodName.equals("getVariable")) + read = true; + else if (methodName.equals("setVariable")) + write = true; + + if (read || write) { + // check if argument matches procVar + if (node.arguments().size() > 0) { + Object arg = node.arguments().get(0); + if (arg instanceof StringLiteral) { + if (arg.toString().startsWith("\"") + && arg.toString().endsWith("\"")) { + varAccess.add(new ProcVarAccess(arg.toString() + .substring(1, arg.toString().length() - 1), + node.getStartPosition(), write)); + return false; + } + } + } + } + return super.visit(node); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/SCVMValidationConstants.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/SCVMValidationConstants.java new file mode 100644 index 0000000..87c2024 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/SCVMValidationConstants.java @@ -0,0 +1,53 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation; + +/** + * Contains some values used in the attack trace visualization. + * + * + */ +public final class SCVMValidationConstants { + + // ASLan rule names + public static final String HUMAN_TASK_RULE_NAME = "h_taskExecution"; + public static final String AUTOMATED_TASK_RULE_NAME = "atask_execution"; + public static final String TASK_AUTHORIZATION_RULE_NAME = "authorizeTaskExecution"; + public static final String GOAL_SOD_PREFIX = "sod_"; + public static final String GOAL_BOD_PREFIX = "bod_"; + + // Highlighting colors + public static final int[] COLOR_HL_EXEC_FG = { 0, 255, 255 }; + public static final int[] COLOR_HL_EXEC_BG = { 0, 230, 230 }; + + public static final int[] COLOR_HL_VIOL_FG = { 255, 0, 0 }; + public static final int[] COLOR_HL_VIOL_BG = { 230, 0, 0 }; + + public static final int[] COLOR_HL_CLAIM_FG = { 0, 255, 0 }; + public static final int[] COLOR_HL_CLAIM_BG = { 0, 230, 0 }; + + public static final int[] COLOR_HL_ASSIGN_FG = { 255, 0, 255 }; + public static final int[] COLOR_HL_ASSIGN_BG = { 230, 0, 230 }; + + public static final int[] COLOR_HL_WORK_FG = { 0, 0, 255 }; + public static final int[] COLOR_HL_WORK_BG = { 0, 0, 230 }; + + public static final int[] COLOR_DEF_SEQFLOW = { 0, 0, 0 }; + + private SCVMValidationConstants() { + + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ValidateAslanRunnable.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ValidateAslanRunnable.java new file mode 100644 index 0000000..7a03d55 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/ValidateAslanRunnable.java @@ -0,0 +1,322 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.eclipse.util.ExtensionPointUtil; +import org.activiti.designer.util.preferences.Preferences; +import org.antlr.runtime.ANTLRStringStream; +import org.antlr.runtime.CommonTokenStream; +import org.antlr.runtime.RecognitionException; +import org.antlr.satmc.SatmcLexer; +import org.antlr.satmc.SatmcParser; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.emf.common.util.URI; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.swt.widgets.Display; + +import eu.aniketos.securebpmn.satmc.SatmcMessage; +import eu.aniketos.securebpmn.util.DialogUtil; +import eu.aniketos.securebpmn.util.SecurityUtil; + +import eu.avantssar.satmc.SATMCPortType; +import eu.avantssar.satmc.SATMCService; + +/** + * A Runnable that generates the ASLan file and analyzes it via SATMC for a + * given Diagram. + * + * + */ +public class ValidateAslanRunnable implements IRunnableWithProgress { + + private Diagram diagram; + private boolean localValidation; + + private SatmcMessage result; + + /** + * Default constructor. + * + * @param diagram + * The diagram that should be validated. + * @param result + * The variable where the result is saved to. + * @param localValidation + * true if the local SATMC binary should be used, false for the + * SATMC web service. + */ + public ValidateAslanRunnable(Diagram diagram, SatmcMessage result, + boolean localValidation) { + this.diagram = diagram; + this.localValidation = localValidation; + this.result = result; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core + * .runtime.IProgressMonitor) + */ + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException { + + try { + + monitor.beginTask("Validating security properties", 10); + + // get uri + URI uri = diagram.eResource().getURI(); + URI platformUri = uri.trimFragment(); + platformUri = platformUri.trimFileExtension(); + platformUri = platformUri.appendFileExtension("aslan"); + + monitor.worked(1); + + // generate file + monitor.subTask("Generating ASLan"); + + final ExportMarshaller marshaller = ExtensionPointUtil + .getExportMarshaller(ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME); + if (marshaller == null) { + throw new IllegalArgumentException( + "Unable to invoke ExportMarshaller with name " + + ActivitiBPMNDiagramConstants.ASLAN_MARSHALLER_NAME); + } + final IProgressMonitor subMonitor = new SubProgressMonitor(monitor, + 2); + try { + marshaller.marshallDiagram(diagram, subMonitor); + } finally { + subMonitor.done(); + } + + // check for problem markers + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + + final IFile diagramFile = workspace.getRoot().getFile( + new Path(diagram.eResource().getURI() + .toPlatformString(true))); + + try { + if (diagramFile + .findMarkers(ExportMarshaller.MARKER_ID, true, 3).length > 0) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + DialogUtil + .openMessageDialog( + "Export problems present", + "The diagram contains export problems! This might result in an outdated analysis result, you should fix the problems and run the analysis again.", + DialogUtil.WARNING); + } + }); + } + } catch (CoreException e1) { + e1.printStackTrace(); + } + + // file validation + String res = ""; + final String fileUri = getResource(platformUri).getLocation() + .toString(); + + if (localValidation) { + // call local binary and pass file path + monitor.subTask("Executing local SATMC binary"); + try { + String pathToBinary = PreferencesUtil + .getStringPreference(Preferences.PATH_TO_SATMC_BINARY); + File workingDir = null; + if (pathToBinary.length() == 0) { + pathToBinary = "satmc"; + } else { + int lastIndex = pathToBinary.lastIndexOf(System + .getProperty("file.separator")); + + if (lastIndex > 0) { + workingDir = new File(pathToBinary.substring(0, + lastIndex)); + } + } + String[] cmd = { pathToBinary, fileUri, "--max=80", + "--mutex=0" + }; + res = cmdExec(cmd, workingDir); + } catch (IOException e) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + DialogUtil + .openMessageDialog( + "SATMC Execution Error", + "Could not run SATMC. Try providing the full path to the executable file in the Activiti preferences.", + DialogUtil.ERROR); + } + }); + e.printStackTrace(); + monitor.worked(7); + monitor.done(); + return; + } + } else { + // read file as string and call web service + monitor.subTask("Calling SATMC web service"); + try { + final SATMCService service = new SATMCService(); + final SATMCPortType port = service.getSATMCSOAPPort(); + + res = port.validate(SecurityUtil.readFileAsString(fileUri), + 80, false, true, false, "aslan", ""); + } catch (Exception e) { + Display.getDefault().syncExec(new Runnable() { + public void run() { + DialogUtil + .openMessageDialog( + "SATMC Execution Error", + "Could not reach SATMC web service. Check your internet connection and, if you are behind a firewall, try setting the proxy in Eclipse to \"manual\".", + DialogUtil.ERROR); + } + }); + e.printStackTrace(); + monitor.worked(7); + monitor.done(); + return; + } + } + + monitor.worked(4); + + // save result to file + monitor.subTask("Saving results"); + + InputStream content = new ByteArrayInputStream(res.getBytes()); + + URI platformResultUri = uri.trimFragment(); + platformResultUri = platformResultUri.trimFileExtension(); + platformResultUri = platformResultUri.appendFileExtension("result"); + + final IFile newfile = workspace.getRoot().getFile( + new Path(platformResultUri.toPlatformString(true))); + + try { + if (newfile.exists()) { + newfile.setContents(content, true, true, + new NullProgressMonitor()); + } else { + newfile.create(content, true, new NullProgressMonitor()); + } + newfile.refreshLocal(IResource.DEPTH_INFINITE, null); + } catch (CoreException e) { + e.printStackTrace(); + } + + monitor.worked(1); + + // parse results + monitor.subTask("Parsing results"); + + try { + SatmcLexer lex = new SatmcLexer(new ANTLRStringStream(res)); + CommonTokenStream tokens = new CommonTokenStream(lex); + + SatmcParser parser = new SatmcParser(tokens); + SatmcMessage parserResult = parser.output(); + + // copy result to result variable + result.summary = parserResult.summary; + result.goal = parserResult.goal; + result.trace = parserResult.trace; + result.cfs = parserResult.cfs; + + } catch (RecognitionException e) { + e.printStackTrace(); + } + + monitor.worked(2); + } finally { + monitor.done(); + } + + } + + /** + * Retrieves the Resource for a given URI. + * + * @param resourceURI + * The URI for the Resource. + * @return The found Resource. + */ + private IResource getResource(URI resourceURI) { + + final IResource fileResource = ResourcesPlugin.getWorkspace().getRoot() + .findMember(resourceURI.toPlatformString(true)); + + IResource result = null; + if (fileResource != null && fileResource.exists()) { + result = ResourcesPlugin.getWorkspace().getRoot() + .findMember(resourceURI.toPlatformString(true)); + } + return result; + } + + /** + * Executes a command on the local machine. + * + * @param cmdLine + * The command that should be executed. + * @param dir + * The working directory in which the command should be executed. + * @return The standard output of the command. + * @throws IOException + * Errors that occur during the execution. + */ + private String cmdExec(String[] cmdLine, File dir) throws IOException { + String line; + String output = ""; + + Process p = Runtime.getRuntime().exec(cmdLine, null, dir); + BufferedReader input = new BufferedReader(new InputStreamReader( + p.getInputStream())); + while ((line = input.readLine()) != null) { + output += (line + '\n'); + } + input.close(); + + return output; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/PlayerControlRunnable.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/PlayerControlRunnable.java new file mode 100644 index 0000000..3eb4e39 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/PlayerControlRunnable.java @@ -0,0 +1,64 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation.view; + +import org.eclipse.swt.widgets.Display; + +import eu.aniketos.securebpmn.visualization.rbac.RbacVisualization; + +/** + * Controls the automated playback of the attack trace visualization. + * + * + */ +public class PlayerControlRunnable implements Runnable { + + private ValidationView view; + + /** + * Default constructor. + * + * @param view + * The view that is used. + */ + public PlayerControlRunnable(ValidationView view) { + this.view = view; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + try { + while (RbacVisualization.getInstance().getPlayer().hasNextStep()) { + RbacVisualization.getInstance().getPlayer().nextStep(); + // set status text + Display.getDefault().syncExec(new Runnable() { + public void run() { + view.setStatusText(RbacVisualization.getInstance() + .getPlayer().getStepInfo()); + } + }); + Thread.sleep(2000); + } + } catch (InterruptedException e) { + } + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/ValidationView.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/ValidationView.java new file mode 100644 index 0000000..c2f5540 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/validation/view/ValidationView.java @@ -0,0 +1,233 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.validation.view; + +import java.lang.Thread.State; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.part.ViewPart; + +import eu.aniketos.securebpmn.visualization.rbac.RbacVisualization; + +/** + * The Eclipse view controlling the attack trace visualization. + * + * + */ +public class ValidationView extends ViewPart { + + private Text statusText; + private Thread playerThread; + + /** + * Default constructor. + */ + public ValidationView() { + // beware: gets called before full ui is loaded if view was left open on + // exit! + statusText = null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets + * .Composite) + */ + @Override + public void createPartControl(Composite parent) { + + // check for validation result + if (!RbacVisualization.getInstance().isResultSet()) { + Label error = new Label(parent, SWT.NONE); + error.setText("No validation result present. Please close this view and run the validation via your preferred method."); + return; + } + + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 2; + parent.setLayout(gridLayout); + + RowLayout buttonLayout = new RowLayout(); + buttonLayout.marginLeft = 5; + buttonLayout.marginTop = 5; + buttonLayout.marginRight = 5; + buttonLayout.marginBottom = 5; + Group buttonGroup = new Group(parent, SWT.SHADOW_IN); + buttonGroup.setLayout(buttonLayout); + buttonGroup.setText("visualization controls"); + buttonGroup.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, + false, 1, 1)); + + Button first = new Button(buttonGroup, SWT.PUSH); + first.setText("first step"); + first.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent event) { + RbacVisualization.getInstance().getPlayer().firstStep(); + statusText.setText(RbacVisualization.getInstance().getPlayer() + .getStepInfo()); + if (playerThread != null) { + playerThread.interrupt(); + playerThread = null; + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + } + }); + + Button previous = new Button(buttonGroup, SWT.PUSH); + previous.setText("previous step"); + previous.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent event) { + RbacVisualization.getInstance().getPlayer().previousStep(); + statusText.setText(RbacVisualization.getInstance().getPlayer() + .getStepInfo()); + if (playerThread != null) { + playerThread.interrupt(); + playerThread = null; + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + } + }); + + Button playPause = new Button(buttonGroup, SWT.PUSH); + playPause.setText("play/pause trace"); + playPause.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent event) { + if (playerThread == null + || playerThread.getState() == State.TERMINATED) { + playerThread = new Thread(new PlayerControlRunnable( + ValidationView.this)); + playerThread.start(); + } else { + playerThread.interrupt(); + playerThread = null; + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + } + }); + + Button next = new Button(buttonGroup, SWT.PUSH); + next.setText("next step"); + next.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent event) { + RbacVisualization.getInstance().getPlayer().nextStep(); + statusText.setText(RbacVisualization.getInstance().getPlayer() + .getStepInfo()); + if (playerThread != null) { + playerThread.interrupt(); + playerThread = null; + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + } + }); + + Button last = new Button(buttonGroup, SWT.PUSH); + last.setText("last step"); + last.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent event) { + RbacVisualization.getInstance().getPlayer().lastStep(); + statusText.setText(RbacVisualization.getInstance().getPlayer() + .getStepInfo()); + if (playerThread != null) { + playerThread.interrupt(); + playerThread = null; + } + } + + public void widgetDefaultSelected(SelectionEvent event) { + } + }); + + Group attackGroup = new Group(parent, SWT.SHADOW_IN); + attackGroup.setLayout(new FillLayout()); + attackGroup.setText("attack trace"); + attackGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, + 1, 2)); + Text attackText = new Text(attackGroup, SWT.MULTI | SWT.V_SCROLL + | SWT.H_SCROLL); + // attackText.setText(SatmcVisualization.getInstance().getFilteredAttackTrace()); + attackText.setText(RbacVisualization.getInstance().getAttackTrace()); + attackText.setEditable(false); + + Group statusGroup = new Group(parent, SWT.SHADOW_IN); + statusGroup.setLayout(new FillLayout()); + statusGroup.setText("step information"); + statusGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, + 1, 1)); + statusText = new Text(statusGroup, SWT.MULTI | SWT.V_SCROLL + | SWT.H_SCROLL); + statusText.setText(RbacVisualization.getInstance().getPlayer() + .getStepInfo()); + statusText.setEditable(false); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.WorkbenchPart#setFocus() + */ + @Override + public void setFocus() { + if(statusText != null){ + statusText.setFocus(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.WorkbenchPart#dispose() + */ + @Override + public void dispose() { + RbacVisualization.getInstance().reset(); + super.dispose(); + } + + /** + * Sets the text of the status text field. Note, that you must use + * Display.getDefault().syncExec if you are calling this method from a + * different thread. + * + * @param text + */ + public void setStatusText(String text) { + if (statusText != null) + statusText.setText(text); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/ActionType.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/ActionType.java new file mode 100644 index 0000000..58ede0e --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/ActionType.java @@ -0,0 +1,28 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization; + +/** + * The Different types of actions that can are represented in the attack trace + * visualization. + * + * + */ +public enum ActionType { + + ASSIGN, CLAIM, EXECUTE, VIOLATION, WORKFLOW + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/HighlightVisualizationElementsRunnable.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/HighlightVisualizationElementsRunnable.java new file mode 100644 index 0000000..33f007d --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/HighlightVisualizationElementsRunnable.java @@ -0,0 +1,474 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization; + +import java.util.List; + +import org.eclipse.bpmn2.Event; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.Task; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.algorithms.Ellipse; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.algorithms.Polygon; +import org.eclipse.graphiti.mm.algorithms.Rectangle; +import org.eclipse.graphiti.mm.algorithms.RoundedRectangle; +import org.eclipse.graphiti.mm.pictograms.Anchor; +import org.eclipse.graphiti.mm.pictograms.Connection; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.mm.pictograms.Shape; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.graphiti.services.IGaService; +import org.eclipse.graphiti.services.ILinkService; +import org.eclipse.securebpmn2.BindingOfDuty; +import org.eclipse.securebpmn2.SeparationOfDuty; + +import eu.aniketos.securebpmn.validation.SCVMValidationConstants; + +/** + * A runnable for highlighting the elements in on step of the attack trace. + * + * + */ +public class HighlightVisualizationElementsRunnable implements Runnable { + + private Diagram diagram; + private List elements; + private boolean revert; + private IGaService gaService; + + /** + * Default constructor. + * + * @param diagram + * The diagram in which the visualization takes place. + * @param elements + * The List of elements that should be highlighted. + * @param revert + * true if the reverse visualization should be applied, false if + * not. + */ + public HighlightVisualizationElementsRunnable(Diagram diagram, + List elements, boolean revert) { + this.diagram = diagram; + this.elements = elements; + this.revert = revert; + this.gaService = Graphiti.getGaService(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + + for (VisualizationElement element : elements) { + + if (element.getbObject() instanceof Task) { + highlightTask(element.getpElement(), element.getAction()); + } else if (element.getbObject() instanceof Gateway) { + highlightGateway(element.getpElement(), element.getAction()); + } else if (element.getbObject() instanceof Event) { + highlightEvent(element.getpElement(), element.getAction()); + } else if (element.getbObject() instanceof SeparationOfDuty + || element.getbObject() instanceof BindingOfDuty) { + highlightTaskLikeElement(element.getpElement(), + element.getAction(), false); + } + + } + + } + + /** + * Performs the highlighting for a Task. + * + * @param pElement + * The corresponding PictogramElement. + * @param action + * The action that defines the highlighting. + */ + private void highlightTask(PictogramElement pElement, ActionType action) { + highlightTaskLikeElement(pElement, action, true); + } + + /** + * Performs the highlighting for a Task and the incoming SequenceFlow. + * + * @param pElement + * The corresponding PictogramElement. + * @param action + * The action that defines the highlighting. + * @param withSequenceFlow + * true if the incoming SequenceFlow should be highlighted, false + * if not. + */ + private void highlightTaskLikeElement(PictogramElement pElement, + ActionType action, boolean withSequenceFlow) { + // highlighting for tasks + ContainerShape cs = (ContainerShape) pElement; + Shape removeShape = null; + + int overlayWidth = 105; + int overlayHeight = 55; + + if (cs.getGraphicsAlgorithm() instanceof Rectangle) { + Rectangle rect = (Rectangle) cs.getGraphicsAlgorithm(); + overlayWidth = rect.getWidth(); + overlayHeight = rect.getHeight(); + } + + for (Shape shape : cs.getChildren()) { + + final GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); + + if (ga instanceof RoundedRectangle) { + // overlay already exists, remove it + removeShape = shape; + } + } + + if (removeShape != null) + // finally remove overlay + cs.getChildren().remove(removeShape); + + if (!revert) { + // create overlay + final Shape s = Graphiti.getPeCreateService() + .createShape(cs, false); + final RoundedRectangle rr = gaService.createRoundedRectangle(s, 20, + 20); + rr.setLineVisible(true); + rr.setFilled(true); + rr.setLineWidth(2); + rr.setTransparency(0.7); + if (action == ActionType.VIOLATION) { + rr.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_FG[0], + SCVMValidationConstants.COLOR_HL_VIOL_FG[1], + SCVMValidationConstants.COLOR_HL_VIOL_FG[2])); + rr.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_BG[0], + SCVMValidationConstants.COLOR_HL_VIOL_BG[1], + SCVMValidationConstants.COLOR_HL_VIOL_BG[2])); + + } else if (action == ActionType.EXECUTE) { + rr.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_FG[0], + SCVMValidationConstants.COLOR_HL_EXEC_FG[1], + SCVMValidationConstants.COLOR_HL_EXEC_FG[2])); + rr.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_BG[0], + SCVMValidationConstants.COLOR_HL_EXEC_BG[1], + SCVMValidationConstants.COLOR_HL_EXEC_BG[2])); + + } else if (action == ActionType.CLAIM) { + rr.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_FG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[2])); + rr.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_BG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[2])); + + } else if (action == ActionType.ASSIGN) { + rr.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[2])); + rr.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[2])); + + } else if (action == ActionType.WORKFLOW) { + rr.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_FG[0], + SCVMValidationConstants.COLOR_HL_WORK_FG[1], + SCVMValidationConstants.COLOR_HL_WORK_FG[2])); + rr.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_BG[0], + SCVMValidationConstants.COLOR_HL_WORK_BG[1], + SCVMValidationConstants.COLOR_HL_WORK_BG[2])); + } + gaService.setLocationAndSize(rr, 0, 0, overlayWidth, overlayHeight); + } + if (withSequenceFlow) + highlightIncomingSequenceFlow(cs); + } + + /** + * Performs the highlighting for a Gateway. + * + * @param pElement + * The corresponding PictogramElement. + * @param action + * The action that defines the highlighting. + */ + private void highlightGateway(PictogramElement pElement, ActionType action) { + // highlighting for gateways + ContainerShape cs = (ContainerShape) pElement; + Shape removeShape = null; + + for (Shape shape : cs.getChildren()) { + + final GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); + + if (ga instanceof Polygon) { + // overlay already exists, remove it + removeShape = shape; + } + } + + if (removeShape != null) + // finally remove overlay + cs.getChildren().remove(removeShape); + + if (!revert) { + // create overlay + final Shape s = Graphiti.getPeCreateService() + .createShape(cs, false); + int xy[] = new int[] { 0, 20, 20, 0, 40, 20, 20, 40, 0, 20 }; + final Polygon p = gaService.createPolygon(s, xy); + + p.setLineVisible(true); + p.setFilled(true); + p.setLineWidth(2); + p.setTransparency(0.7); + if (action == ActionType.VIOLATION) { + p.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_FG[0], + SCVMValidationConstants.COLOR_HL_VIOL_FG[1], + SCVMValidationConstants.COLOR_HL_VIOL_FG[2])); + p.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_BG[0], + SCVMValidationConstants.COLOR_HL_VIOL_BG[1], + SCVMValidationConstants.COLOR_HL_VIOL_BG[2])); + + } else if (action == ActionType.EXECUTE) { + p.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_FG[0], + SCVMValidationConstants.COLOR_HL_EXEC_FG[1], + SCVMValidationConstants.COLOR_HL_EXEC_FG[2])); + p.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_BG[0], + SCVMValidationConstants.COLOR_HL_EXEC_BG[1], + SCVMValidationConstants.COLOR_HL_EXEC_BG[2])); + + } else if (action == ActionType.CLAIM) { + p.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_FG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[2])); + p.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_BG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[2])); + + } else if (action == ActionType.ASSIGN) { + p.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[2])); + p.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[2])); + + } else if (action == ActionType.WORKFLOW) { + p.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_FG[0], + SCVMValidationConstants.COLOR_HL_WORK_FG[1], + SCVMValidationConstants.COLOR_HL_WORK_FG[2])); + p.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_BG[0], + SCVMValidationConstants.COLOR_HL_WORK_BG[1], + SCVMValidationConstants.COLOR_HL_WORK_BG[2])); + } + gaService.setLocationAndSize(p, 0, 0, 40, 40); + } + highlightIncomingSequenceFlow(cs); + } + + /** + * Performs the highlighting for an Event. + * + * @param pElement + * The corresponding PictogramElement. + * @param action + * The action that defines the highlighting. + */ + private void highlightEvent(PictogramElement pElement, ActionType action) { + // highlighting for events + ContainerShape cs = (ContainerShape) pElement; + Shape removeShape = null; + + for (Shape shape : cs.getChildren()) { + + final GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); + + if (ga instanceof Ellipse) { + // overlay already exists, remove it + removeShape = shape; + } + } + + if (removeShape != null) + // finally remove overlay + cs.getChildren().remove(removeShape); + + if (!revert) { + // create overlay + final Shape s = Graphiti.getPeCreateService() + .createShape(cs, false); + final Ellipse e = gaService.createEllipse(s); + e.setLineVisible(true); + e.setFilled(true); + e.setLineWidth(4); + e.setTransparency(0.7); + if (action == ActionType.VIOLATION) { + e.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_FG[0], + SCVMValidationConstants.COLOR_HL_VIOL_FG[1], + SCVMValidationConstants.COLOR_HL_VIOL_FG[2])); + e.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_VIOL_BG[0], + SCVMValidationConstants.COLOR_HL_VIOL_BG[1], + SCVMValidationConstants.COLOR_HL_VIOL_BG[2])); + + } else if (action == ActionType.EXECUTE) { + e.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_FG[0], + SCVMValidationConstants.COLOR_HL_EXEC_FG[1], + SCVMValidationConstants.COLOR_HL_EXEC_FG[2])); + e.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_EXEC_BG[0], + SCVMValidationConstants.COLOR_HL_EXEC_BG[1], + SCVMValidationConstants.COLOR_HL_EXEC_BG[2])); + + } else if (action == ActionType.CLAIM) { + e.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_FG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_FG[2])); + e.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_CLAIM_BG[0], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[1], + SCVMValidationConstants.COLOR_HL_CLAIM_BG[2])); + + } else if (action == ActionType.ASSIGN) { + e.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_FG[2])); + e.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[0], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[1], + SCVMValidationConstants.COLOR_HL_ASSIGN_BG[2])); + + } else if (action == ActionType.WORKFLOW) { + e.setForeground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_FG[0], + SCVMValidationConstants.COLOR_HL_WORK_FG[1], + SCVMValidationConstants.COLOR_HL_WORK_FG[2])); + e.setBackground(gaService.manageColor(diagram, + SCVMValidationConstants.COLOR_HL_WORK_BG[0], + SCVMValidationConstants.COLOR_HL_WORK_BG[1], + SCVMValidationConstants.COLOR_HL_WORK_BG[2])); + } + gaService.setLocationAndSize(e, 0, 0, 35, 35); + } + highlightIncomingSequenceFlow(cs); + } + + /** + * Performs the highlighting for a SequenceFlow. + * + * @param cs + * The corresponding ContainerShape. + */ + private void highlightIncomingSequenceFlow(ContainerShape cs) { + // highlighting of incoming sequence flow + ILinkService linkService = Graphiti.getLinkService(); + + // loop over incoming connections + for (Anchor anchor : cs.getAnchors()) { + for (Connection connection : anchor.getIncomingConnections()) { + + EObject linkedObject = linkService + .getBusinessObjectForLinkedPictogramElement(connection); + + if (!(linkedObject instanceof SequenceFlow)) { + continue; + } + + // determine if connection comes from highlighted element + boolean sourceIsHighlighted = false; + + PictogramElement sourcePictogramElement = connection.getStart() + .getParent().getGraphicsAlgorithm() + .getPictogramElement(); + + if (sourcePictogramElement instanceof ContainerShape) { + for (Shape shape : ((ContainerShape) sourcePictogramElement) + .getChildren()) { + + final GraphicsAlgorithm ga = shape + .getGraphicsAlgorithm(); + + if (ga instanceof RoundedRectangle + || ga instanceof Ellipse + || ga instanceof Polygon) { + sourceIsHighlighted = true; + break; + } + } + } + + if (sourceIsHighlighted) { + + GraphicsAlgorithm connectionGA = connection + .getGraphicsAlgorithm(); + + if (revert) { + // remove highlighting of sequenceFlow + connectionGA.setLineWidth(1); + connectionGA.setForeground(gaService.manageColor( + diagram, + SCVMValidationConstants.COLOR_DEF_SEQFLOW[0], + SCVMValidationConstants.COLOR_DEF_SEQFLOW[1], + SCVMValidationConstants.COLOR_DEF_SEQFLOW[2])); + } else { + // highlight sequenceFlow + // TODO make highlighting more beautiful (overlay?) + connectionGA.setLineWidth(2); + connectionGA.setForeground(gaService.manageColor( + diagram, + SCVMValidationConstants.COLOR_HL_WORK_FG[0], + SCVMValidationConstants.COLOR_HL_WORK_FG[1], + SCVMValidationConstants.COLOR_HL_WORK_FG[2])); + } + } + } + } + } +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/VisualizationElement.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/VisualizationElement.java new file mode 100644 index 0000000..38a5505 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/VisualizationElement.java @@ -0,0 +1,126 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization; + +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; + +/** + * A Class representing an element for visualization. + * + * + */ +public class VisualizationElement { + + private String id; + private FlowElement bObject; + private PictogramElement pElement; + private ActionType action; + + /** + * Default constructor. + * + * @param id + * The ID of the element. + * @param action + * The type of action the element is involved in. Used for + * determining the type of highlighting. + */ + public VisualizationElement(String id, ActionType action) { + this.id = id; + this.action = action; + this.bObject = null; + this.pElement = null; + } + + /** + * Default constructor. + * + * @param id + * The ID of the element. + * @param bObject + * The BO of the element. + * @param pElement + * The PE of the element. + * @param action + * The type of action the element is involved in. Used for + * determining the type of highlighting. + */ + public VisualizationElement(String id, FlowElement bObject, + PictogramElement pElement, ActionType action) { + this.id = id; + this.bObject = bObject; + this.pElement = pElement; + this.action = action; + } + + /** + * Retrieves the BusinessObject of the element. + * + * @return The corresponding BO. + */ + public FlowElement getbObject() { + return bObject; + } + + /** + * Sets the BusinessObject of the element. + * + * @param bObject + * The BO to be set. + */ + public void setbObject(FlowElement bObject) { + this.bObject = bObject; + } + + /** + * Retrieves the PictogramElement of the element. + * + * @return The corresponding PE. + */ + public PictogramElement getpElement() { + return pElement; + } + + /** + * Sets the PictogramElement of the element. + * + * @param pElement + * The PE to be set. + */ + public void setpElement(PictogramElement pElement) { + this.pElement = pElement; + } + + /** + * Retrieves the ID of the element. + * + * @return The corresponding ID. + */ + public String getId() { + return id; + } + + /** + * Retrieves the type of action the element is involved in. + * + * @return The corresponding ActionType. + */ + public ActionType getAction() { + return action; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTracePlayer.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTracePlayer.java new file mode 100644 index 0000000..c61eed5 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTracePlayer.java @@ -0,0 +1,199 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization.rbac; + +import java.util.ArrayList; +import java.util.List; + +import org.activiti.designer.util.eclipse.ActivitiUiUtil; +import org.eclipse.bpmn2.Task; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +import eu.aniketos.securebpmn.visualization.ActionType; +import eu.aniketos.securebpmn.visualization.HighlightVisualizationElementsRunnable; +import eu.aniketos.securebpmn.visualization.VisualizationElement; + +/** + * Player class that controls the attack trace visualization. + * + * + */ +public class AttackTracePlayer { + + private Diagram diagram; + private TransactionalEditingDomain domain; + private List traceList; + private int pos; + + /** + * Default constructor. + * + * @param diagram + * The diagram in which the visualization takes place. + * @param traceList + * The conditioned List of steps in the attack trace. + */ + public AttackTracePlayer(Diagram diagram, List traceList) { + this.diagram = diagram; + this.traceList = traceList; + pos = 0; + domain = TransactionUtil.getEditingDomain(diagram); + + highlightShapes(traceList.get(0).getInvolvedElements(), false); + } + + /** + * Returns if the attack trace has a previous step. + * + * @return true if it has a previous step, false if not. + */ + public boolean hasPreviousStep() { + return pos > 0; + } + + /** + * Returns if the attack trace has a next step. + * + * @return true if it has a next step, false if not. + */ + public boolean hasNextStep() { + return pos < traceList.size() - 1; + } + + /** + * Advances the visualization to the first step in the attack trace. + */ + public void firstStep() { + // revert all shapes from current to first element + while (hasPreviousStep()) { + previousStep(); + } + } + + /** + * Rewinds the visualization to the last step in the attack trace. + */ + public void lastStep() { + // change all shapes from current to last element + while (hasNextStep()) { + nextStep(); + } + } + + /** + * Advances the visualization to the next step. + * + * @return The new position in the attack trace. + */ + public int nextStep() { + // highlight shapes in next step + if (hasNextStep()) { + pos++; + highlightShapes(traceList.get(pos).getInvolvedElements(), false); + } + return pos; + } + + /** + * Rewinds the visualization to the previous step. Notice that this + * implementation does not support the visualization of assign/claim attacks + * at the moment. + * + * @return The new position in the attack trace. + */ + public int previousStep() { + // revert shapes of current step + if (hasPreviousStep()) { + // revert changes done in current step + final List currentElements = traceList.get( + pos).getInvolvedElements(); + highlightShapes(currentElements, true); + pos--; + + // check if previous step was violation & highlight again + final List previousElements = traceList.get( + pos).getInvolvedElements(); + + List tasksToHighlight = new ArrayList(); + + for (VisualizationElement element : currentElements) { + // no violation + if (!(element.getAction() == ActionType.VIOLATION)) + continue; + + if (element.getbObject() instanceof Task) { + tasksToHighlight.add(new VisualizationElement(element + .getId(), element.getbObject(), element + .getpElement(), ActionType.EXECUTE)); + } + + } + + // check if previos step was claim & highlight again + boolean previousClaim = false; + for (VisualizationElement element : previousElements) { + if (element.getAction() == ActionType.CLAIM) { + previousClaim = true; + break; + } + } + + if (previousClaim) { + highlightShapes(previousElements, false); + } + if (tasksToHighlight.size() > 0) { + highlightShapes(tasksToHighlight, false); + } + } + return pos; + } + + /** + * Retrieves the information text of the current step in the attack trace. + * + * @return The information text of the current step. + */ + public String getStepInfo() { + return traceList.get(pos).getDescription(); + } + + /** + * Performs the highlighting of the elements provided. + * + * @param elements + * The elements to be highlighted. + * @param revert + * true if the highlighting should be reversed, false if not. + */ + private void highlightShapes(List elements, + boolean revert) { + ActivitiUiUtil.runModelChange( + new HighlightVisualizationElementsRunnable(diagram, elements, + revert), domain, "SCVM RBAC Visualization"); + } + + /** + * Method that must be called before the visualization view is disposed. + * Resets the Diagram colors. + */ + public void prepareDisposal() { + firstStep(); + highlightShapes(traceList.get(0).getInvolvedElements(), true); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTraceStep.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTraceStep.java new file mode 100644 index 0000000..45a9eec --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/AttackTraceStep.java @@ -0,0 +1,79 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization.rbac; + +import java.util.ArrayList; +import java.util.List; + +import eu.aniketos.securebpmn.visualization.VisualizationElement; + +/** + * Represents a step in the attack trace visualization. + * + * + */ +public class AttackTraceStep { + + private List involvedElements; + private String description; + + /** + * Default constructor. + */ + public AttackTraceStep() { + this.involvedElements = new ArrayList(); + this.description = ""; + } + + /** + * Retrieves the description text of the step. + * + * @return The description text. + */ + public String getDescription() { + return description; + } + + /** + * Sets the description text of the step. + * + * @param description + * The new description to be set. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Retrieves the VisualizationElements involved in the step. + * + * @return The List of involved VisualizationElements. + */ + public List getInvolvedElements() { + return involvedElements; + } + + /** + * Adds a new VisualizationElement to the involved elements in the step. + * + * @param element + * The new VisualizationElement to be added. + */ + public void addInvolvedElement(VisualizationElement element) { + this.involvedElements.add(element); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/RbacVisualization.java b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/RbacVisualization.java new file mode 100644 index 0000000..acc27f9 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/aniketos/securebpmn/visualization/rbac/RbacVisualization.java @@ -0,0 +1,199 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.aniketos.securebpmn.visualization.rbac; + +import eu.aniketos.securebpmn.satmc.SatmcFunction; +import eu.aniketos.securebpmn.satmc.SatmcMessage; +import eu.aniketos.securebpmn.satmc.SatmcTraceStep; +import eu.aniketos.securebpmn.satmc.Summary; +import eu.aniketos.securebpmn.validation.SCVMValidationConstants; + +/** + * Singleton Class that holds the parsed SATMC result and the player class for + * automated attack trace visualization playback. + * + * + */ +public class RbacVisualization { + + private static RbacVisualization _instance; + + private SatmcMessage parsedResult; + private AttackTracePlayer player; + + /** + * Default constructor. + */ + private RbacVisualization() { + parsedResult = null; + player = null; + } + + /** + * Retrieves the singleton instance. + * + * @return The class instance. + */ + public static synchronized RbacVisualization getInstance() { + if (_instance == null) { + _instance = new RbacVisualization(); + } + return _instance; + } + + /** + * Returns if the parsed result is set. + * + * @return true if it is set, false if not. + */ + public boolean isResultSet() { + return parsedResult == null ? false : true; + } + + /** + * Sets the parsed result. + * + * @param result + * The new result to be set. + */ + public void setResult(SatmcMessage result) { + parsedResult = result; + } + + /** + * Returns if the visualization is currently running. + * + * @return true if it is running, false if not. + */ + public boolean isVisualizationRunning() { + return player == null ? false : true; + } + + /** + * Sets the player for automated playback. + * + * @param player + * The new player to be set. + */ + public void setPlayer(AttackTracePlayer player) { + this.player = player; + } + + /** + * Retrieves the current player. + * + * @return The current player. + */ + public AttackTracePlayer getPlayer() { + return this.player; + } + + /** + * Retrieves the rules of the attack trace as a String. + * + * @return The attack trace as a String. + */ + public String getAttackTrace() { + if (parsedResult == null) + return "No result present!"; + + String result = ""; + + int stepCount = 1; + for (SatmcTraceStep sts : parsedResult.trace) { + + if (sts.rules.toString().length() < 3) + continue; + + result += stepCount + ": " + sts.rules.toString() + "\n"; + stepCount++; + } + + return result; + } + + /** + * Retrieves a filtered attack trace of the parsed result as a String. Only + * rules for taks claiming and execution are included. + * + * @return The filtered attack trace as a String. + */ + public String getFilteredAttackTrace() { + if (parsedResult == null) + return "No result present!"; + + String result = ""; + + int stepCount = 1; + for (SatmcTraceStep sts : parsedResult.trace) { + + boolean first = true; + String resultLine = ""; + + for (SatmcFunction rule : sts.rules) { + if (rule.name + .equals(SCVMValidationConstants.HUMAN_TASK_RULE_NAME) + || rule.name + .equals(SCVMValidationConstants.AUTOMATED_TASK_RULE_NAME) + || rule.name + .equals(SCVMValidationConstants.TASK_AUTHORIZATION_RULE_NAME)) { + + if (first) { + resultLine += stepCount + ": "; + first = false; + } else { + resultLine += ", "; + } + + resultLine += rule.toString(); + + } + } + if (resultLine.length() > 0) { + result += resultLine + "\n"; + stepCount++; + } + } + + return result; + } + + /** + * Retrieves the violated goal as a String. + * + * @return The violated goal as a string. + */ + public String getViolatedGoal() { + if (parsedResult == null + || parsedResult.summary != Summary.ATTACK_FOUND) { + return ""; + } else { + return parsedResult.goal.toString(); + } + + } + + /** + * Resets the class: Disposes the player and deletes the result. + */ + public void reset() { + if (player != null) + player.prepareDisposal(); + player = null; + parsedResult = null; + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCPortType.java b/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCPortType.java new file mode 100644 index 0000000..6541a1f --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCPortType.java @@ -0,0 +1,64 @@ + +package eu.avantssar.satmc; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.1.6 in JDK 6 + * Generated source version: 2.1 + * + */ +@WebService(name = "SATMCPortType", targetNamespace = "http://avantssar.eu/satmc/") +@SOAPBinding(style = SOAPBinding.Style.RPC) +public interface SATMCPortType { + + + /** + * + * @param stepCompression + * @param mutex + * @param asLanSpec + * @param max + * @param outputFormat + * @param otherOptions + * @param exec + * @return + * returns java.lang.String + */ + @WebMethod(action = "http://avantssar.eu/satmc/validate") + @WebResult(name = "counterexample", partName = "counterexample") + public String validate( + @WebParam(name = "ASLanSpec", partName = "ASLanSpec") + String asLanSpec, + @WebParam(name = "max", partName = "max") + int max, + @WebParam(name = "mutex", partName = "mutex") + boolean mutex, + @WebParam(name = "stepCompression", partName = "stepCompression") + boolean stepCompression, + @WebParam(name = "exec", partName = "exec") + boolean exec, + @WebParam(name = "outputFormat", partName = "outputFormat") + String outputFormat, + @WebParam(name = "otherOptions", partName = "otherOptions") + String otherOptions); + + /** + * + * @param request + * @return + * returns java.lang.String + */ + @WebMethod(action = "http://avantssar.eu/satmc/version") + @WebResult(name = "info", partName = "info") + public String version( + @WebParam(name = "request", partName = "request") + String request); + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCService.java b/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCService.java new file mode 100644 index 0000000..e91f966 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/eu/avantssar/satmc/SATMCService.java @@ -0,0 +1,71 @@ + +package eu.avantssar.satmc; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.logging.Logger; +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.1.6 in JDK 6 + * Generated source version: 2.1 + * + */ +@WebServiceClient(name = "SATMCService", targetNamespace = "http://avantssar.eu/satmc/", wsdlLocation = "http://satmc.ai.dist.unige.it/avantssar/service/satmc/?wsdl") +public class SATMCService + extends Service +{ + + private final static URL SATMCSERVICE_WSDL_LOCATION; + private final static Logger logger = Logger.getLogger(eu.avantssar.satmc.SATMCService.class.getName()); + + static { + URL url = null; + try { + URL baseUrl; + baseUrl = eu.avantssar.satmc.SATMCService.class.getResource("."); + url = new URL(baseUrl, "http://satmc.ai.dist.unige.it/avantssar/service/satmc/?wsdl"); + } catch (MalformedURLException e) { + logger.warning("Failed to create URL for the wsdl Location: 'http://satmc.ai.dist.unige.it/avantssar/service/satmc/?wsdl', retrying as a local file"); + logger.warning(e.getMessage()); + } + SATMCSERVICE_WSDL_LOCATION = url; + } + + public SATMCService(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public SATMCService() { + super(SATMCSERVICE_WSDL_LOCATION, new QName("http://avantssar.eu/satmc/", "SATMCService")); + } + + /** + * + * @return + * returns SATMCPortType + */ + @WebEndpoint(name = "SATMCSOAPPort") + public SATMCPortType getSATMCSOAPPort() { + return super.getPort(new QName("http://avantssar.eu/satmc/", "SATMCSOAPPort"), SATMCPortType.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the features parameter will have their default values. + * @return + * returns SATMCPortType + */ + @WebEndpoint(name = "SATMCSOAPPort") + public SATMCPortType getSATMCSOAPPort(WebServiceFeature... features) { + return super.getPort(new QName("http://avantssar.eu/satmc/", "SATMCSOAPPort"), SATMCPortType.class, features); + } + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/org/antlr/RoleDef.g b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/RoleDef.g new file mode 100644 index 0000000..f442301 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/RoleDef.g @@ -0,0 +1,64 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +grammar RoleDef; + +tokens { + COLON=':'; + COMMA=','; + GEQ='>'; +} + +@header { +package org.antlr.roledef; + +import com.sap.research.st.aniketos.securebpmn.roles.*; +} + +@lexer::header {package org.antlr.roledef;} + +file returns [List lines] + : {$lines = new ArrayList();} + (ldef=line_def {$lines.add($ldef.def);} | lrel=line_rel {$lines.add($lrel.rel);} )* EOF + ; + +line_def returns [RoleDef def] + : name=string {$def = new RoleDef($name.text);} COLON fm=string {$def.addMember($fm.text);} (COMMA mm=string {$def.addMember($mm.text);} )* + ; + +line_rel returns [RoleRel rel] + : sup=string GEQ sub=string {$rel = new RoleRel($sup.text, $sub.text);} + ; + +string + : STR + ; + +STR + : ( 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '-' )+ + ; + +COMMENT + : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;} + | '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} + ; + +WS : ( ' ' + | '\t' + | '\r' + | '\n' + ) {$channel=HIDDEN;} + ; + diff --git a/src/eu.aniketos.securebpmn/src/main/java/org/antlr/Satmc.g b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/Satmc.g new file mode 100644 index 0000000..3242329 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/Satmc.g @@ -0,0 +1,214 @@ +/* Copyright 2012-2015 SAP SE + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +grammar Satmc; + +// This grammar supports only SATMC output of version 3.2.8 or higher. + +tokens { + WARNING='% WARNING:'; + ERROR='% ERROR:'; + INPUT='INPUT'; + SUMMARY='SUMMARY'; + GOAL='GOAL:'; + DETAILS='DETAILS'; + VERSION='BACKEND SATMC VERSION'; + COMMENTS='COMMENTS'; + STAT='STATISTICS'; + TRACE='TRACE:'; + CLAUSES='CLAUSES:'; + RULES='RULES:'; + CFS='CLOSED_FINAL_STATE:'; + O_PARENTHESIS='('; + C_PARENTHESIS=')'; + O_BRACKET='['; + C_BRACKET=']'; + O_BRACES='{'; + C_BRACES='}'; + COMMA=','; + PERCENT='% '; +} + +@header { +package org.antlr.satmc; + +import com.sap.research.st.aniketos.securebpmn.satmc.*; +} + +@lexer::header {package org.antlr.satmc;} + +output returns [SatmcMessage message] + : NEWLINE* ( NEWLINE section_warning )* ( error {$message = new SatmcMessage(Summary.ERROR, null, null, null);} + | s=result {$message = $s.message;} + ) NEWLINE* EOF + | + ; + +error + : NEWLINE section_error + ; + +result returns [SatmcMessage message] + : line_input NEWLINE ls=line_summary NEWLINE NEWLINE? ( lg=line_goal NEWLINE NEWLINE )? section_details NEWLINE NEWLINE line_version NEWLINE NEWLINE section_comments? section_stat st=section_trace? lc=line_cfs? + {$message = new SatmcMessage($ls.res, $lg.res, $st.res, $lc.res);} + ; + +section_warning + : WARNING ( ( ~NEWLINE )+ NEWLINE )* NEWLINE + ; + +section_error + : ERROR ( ( ~NEWLINE )+ NEWLINE )* NEWLINE NEWLINE ( PERCENT ( ( ~NEWLINE )+ NEWLINE )* NEWLINE )? + ; + +line_input + : INPUT WS target WS? + ; + +line_summary returns [Summary res] + : SUMMARY WS sr=summary_result WS? {if ("ATTACK_FOUND".equals($sr.text)) { + $res = Summary.ATTACK_FOUND; + } else if ("NO_ATTACK_FOUND".equals($sr.text)) { + $res = Summary.NO_ATTACK_FOUND; + } else if ("INCONCLUSIVE".equals($sr.text)) { + $res = Summary.INCONCLUSIVE; + } else { + $res = Summary.UNKNOWN; + } + } + ; + +line_goal returns [SatmcFunction res] + : WS? GOAL WS f=function {$res = $f.res;} WS? + ; + +section_details + : line_details ( NEWLINE line_detail )* + ; + +line_details + : DETAILS WS? + ; + +line_detail + : WS? CONSTANT WS? + ; + +line_version + : VERSION WS VERSION_NR + ; + +section_comments + : COMMENTS WS? NEWLINE ( ( ~NEWLINE )+ NEWLINE )* NEWLINE + ; + +section_stat + : STAT WS ( ( ~NEWLINE )+ NEWLINE )* NEWLINE + ; + +section_trace returns [List res] + : TRACE { $res = new ArrayList(); } NEWLINE + ( NUMBER {boolean rulesPresent = false;} + NEWLINE lc=line_clauses NEWLINE ( lr=line_rules {rulesPresent=true;} + NEWLINE )? + {if (rulesPresent) + $res.add(new SatmcTraceStep($lc.res, $lr.res)); + else + $res.add(new SatmcTraceStep($lc.res, new ArrayList()));} + )+ + ; + +line_clauses returns [List res] + : WS? CLAUSES fs=function_set { $res = $fs.res; } + ; + +line_rules returns [List res] + : WS? RULES WS ( f=function { $res = new ArrayList(); $res.add($f.res);} + | fs=function_set { $res = $fs.res; } + | fn=fname { $res = new ArrayList(); + $res.add(new SatmcFunction($fn.text, new ArrayList()));}) + ; + +line_cfs returns [List res] + : CFS NEWLINE fs=function_set { $res = $fs.res; } + ; + +target + : FILE + ; + +summary_result + : CONSTANT + ; + +function_set returns [List res] + : O_BRACES WS { $res = new ArrayList(); + } + ( f1=function { $res.add($f1.res); + } + ( COMMA fn=function { $res.add($fn.res); } )* )? WS? C_BRACES + ; + +function returns [SatmcFunction res] + : fn=fname { $res = new SatmcFunction($fn.text, new ArrayList()); + } + O_PARENTHESIS fv=fvar { $res.args.add($fv.res); + } + ( COMMA fvl=fvar { $res.args.add($fvl.res); + } + )* C_PARENTHESIS + ; + +var + : FTEXT + | NUMBER + ; + +fname + : FTEXT + ; + +fvar returns [SatmcFact res] + : r1=var {$res = new SatmcVar($r1.text);} + | r2=function {$res = $r2.res;} + ; + +VERSION_NR + : '0'..'9' '.' '0'..'9' '.' '0'..'9' ( 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | O_PARENTHESIS | C_PARENTHESIS )* + ; + +CONSTANT + : ( 'A'..'Z' | '_' )+ + ; + +NUMBER + : ( '0'..'9' )+ + ; + +FTEXT + : ( 'a'..'z' | 'A'..'Z' | NUMBER |'_' )+ + ; + +FILE + : ( 'a'..'z' | 'A'..'Z' | NUMBER | '.' )+ + ; + +NEWLINE + : '\r'? '\n' + ; + +WS + : ( ' ' | '\t' )+ + ; diff --git a/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefLexer.java b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefLexer.java new file mode 100644 index 0000000..b360686 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefLexer.java @@ -0,0 +1,515 @@ +// $ANTLR 3.4 RoleDef.g 2012-03-27 12:55:40 +package org.antlr.roledef; + +import org.antlr.runtime.*; +import java.util.Stack; +import java.util.List; +import java.util.ArrayList; + +@SuppressWarnings({"all", "warnings", "unchecked"}) +public class RoleDefLexer extends Lexer { + public static final int EOF=-1; + public static final int COLON=4; + public static final int COMMA=5; + public static final int COMMENT=6; + public static final int GEQ=7; + public static final int STR=8; + public static final int WS=9; + + // delegates + // delegators + public Lexer[] getDelegates() { + return new Lexer[] {}; + } + + public RoleDefLexer() {} + public RoleDefLexer(CharStream input) { + this(input, new RecognizerSharedState()); + } + public RoleDefLexer(CharStream input, RecognizerSharedState state) { + super(input,state); + } + public String getGrammarFileName() { return "RoleDef.g"; } + + // $ANTLR start "COLON" + public final void mCOLON() throws RecognitionException { + try { + int _type = COLON; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:4:7: ( ':' ) + // RoleDef.g:4:9: ':' + { + match(':'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "COLON" + + // $ANTLR start "COMMA" + public final void mCOMMA() throws RecognitionException { + try { + int _type = COMMA; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:5:7: ( ',' ) + // RoleDef.g:5:9: ',' + { + match(','); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "COMMA" + + // $ANTLR start "GEQ" + public final void mGEQ() throws RecognitionException { + try { + int _type = GEQ; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:6:5: ( '>' ) + // RoleDef.g:6:7: '>' + { + match('>'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "GEQ" + + // $ANTLR start "STR" + public final void mSTR() throws RecognitionException { + try { + int _type = STR; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:35:5: ( ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | '-' )+ ) + // RoleDef.g:35:7: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | '-' )+ + { + // RoleDef.g:35:7: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | '-' )+ + int cnt1=0; + loop1: + do { + int alt1=2; + int LA1_0 = input.LA(1); + + if ( (LA1_0=='-'||(LA1_0 >= '0' && LA1_0 <= '9')||(LA1_0 >= 'A' && LA1_0 <= 'Z')||LA1_0=='_'||(LA1_0 >= 'a' && LA1_0 <= 'z')) ) { + alt1=1; + } + + + switch (alt1) { + case 1 : + // RoleDef.g: + { + if ( input.LA(1)=='-'||(input.LA(1) >= '0' && input.LA(1) <= '9')||(input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_'||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + if ( cnt1 >= 1 ) break loop1; + EarlyExitException eee = + new EarlyExitException(1, input); + throw eee; + } + cnt1++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "STR" + + // $ANTLR start "COMMENT" + public final void mCOMMENT() throws RecognitionException { + try { + int _type = COMMENT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:39:5: ( '//' (~ ( '\\n' | '\\r' ) )* ( '\\r' )? '\\n' | '/*' ( options {greedy=false; } : . )* '*/' ) + int alt5=2; + int LA5_0 = input.LA(1); + + if ( (LA5_0=='/') ) { + int LA5_1 = input.LA(2); + + if ( (LA5_1=='/') ) { + alt5=1; + } + else if ( (LA5_1=='*') ) { + alt5=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 5, 1, input); + + throw nvae; + + } + } + else { + NoViableAltException nvae = + new NoViableAltException("", 5, 0, input); + + throw nvae; + + } + switch (alt5) { + case 1 : + // RoleDef.g:39:9: '//' (~ ( '\\n' | '\\r' ) )* ( '\\r' )? '\\n' + { + match("//"); + + + + // RoleDef.g:39:14: (~ ( '\\n' | '\\r' ) )* + loop2: + do { + int alt2=2; + int LA2_0 = input.LA(1); + + if ( ((LA2_0 >= '\u0000' && LA2_0 <= '\t')||(LA2_0 >= '\u000B' && LA2_0 <= '\f')||(LA2_0 >= '\u000E' && LA2_0 <= '\uFFFF')) ) { + alt2=1; + } + + + switch (alt2) { + case 1 : + // RoleDef.g: + { + if ( (input.LA(1) >= '\u0000' && input.LA(1) <= '\t')||(input.LA(1) >= '\u000B' && input.LA(1) <= '\f')||(input.LA(1) >= '\u000E' && input.LA(1) <= '\uFFFF') ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + break loop2; + } + } while (true); + + + // RoleDef.g:39:28: ( '\\r' )? + int alt3=2; + int LA3_0 = input.LA(1); + + if ( (LA3_0=='\r') ) { + alt3=1; + } + switch (alt3) { + case 1 : + // RoleDef.g:39:28: '\\r' + { + match('\r'); + + } + break; + + } + + + match('\n'); + + _channel=HIDDEN; + + } + break; + case 2 : + // RoleDef.g:40:9: '/*' ( options {greedy=false; } : . )* '*/' + { + match("/*"); + + + + // RoleDef.g:40:14: ( options {greedy=false; } : . )* + loop4: + do { + int alt4=2; + int LA4_0 = input.LA(1); + + if ( (LA4_0=='*') ) { + int LA4_1 = input.LA(2); + + if ( (LA4_1=='/') ) { + alt4=2; + } + else if ( ((LA4_1 >= '\u0000' && LA4_1 <= '.')||(LA4_1 >= '0' && LA4_1 <= '\uFFFF')) ) { + alt4=1; + } + + + } + else if ( ((LA4_0 >= '\u0000' && LA4_0 <= ')')||(LA4_0 >= '+' && LA4_0 <= '\uFFFF')) ) { + alt4=1; + } + + + switch (alt4) { + case 1 : + // RoleDef.g:40:42: . + { + matchAny(); + + } + break; + + default : + break loop4; + } + } while (true); + + + match("*/"); + + + + _channel=HIDDEN; + + } + break; + + } + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "COMMENT" + + // $ANTLR start "WS" + public final void mWS() throws RecognitionException { + try { + int _type = WS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // RoleDef.g:43:5: ( ( ' ' | '\\t' | '\\r' | '\\n' ) ) + // RoleDef.g:43:9: ( ' ' | '\\t' | '\\r' | '\\n' ) + { + if ( (input.LA(1) >= '\t' && input.LA(1) <= '\n')||input.LA(1)=='\r'||input.LA(1)==' ' ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + _channel=HIDDEN; + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "WS" + + public void mTokens() throws RecognitionException { + // RoleDef.g:1:8: ( COLON | COMMA | GEQ | STR | COMMENT | WS ) + int alt6=6; + switch ( input.LA(1) ) { + case ':': + { + alt6=1; + } + break; + case ',': + { + alt6=2; + } + break; + case '>': + { + alt6=3; + } + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '_': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + alt6=4; + } + break; + case '/': + { + alt6=5; + } + break; + case '\t': + case '\n': + case '\r': + case ' ': + { + alt6=6; + } + break; + default: + NoViableAltException nvae = + new NoViableAltException("", 6, 0, input); + + throw nvae; + + } + + switch (alt6) { + case 1 : + // RoleDef.g:1:10: COLON + { + mCOLON(); + + + } + break; + case 2 : + // RoleDef.g:1:16: COMMA + { + mCOMMA(); + + + } + break; + case 3 : + // RoleDef.g:1:22: GEQ + { + mGEQ(); + + + } + break; + case 4 : + // RoleDef.g:1:26: STR + { + mSTR(); + + + } + break; + case 5 : + // RoleDef.g:1:30: COMMENT + { + mCOMMENT(); + + + } + break; + case 6 : + // RoleDef.g:1:38: WS + { + mWS(); + + + } + break; + + } + + } + + + + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefParser.java b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefParser.java new file mode 100644 index 0000000..65a2e1b --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/roledef/RoleDefParser.java @@ -0,0 +1,323 @@ +// $ANTLR 3.4 RoleDef.g 2012-03-27 12:55:40 + +package org.antlr.roledef; + +import eu.aniketos.securebpmn.roles.*; + + +import org.antlr.runtime.*; +import java.util.Stack; +import java.util.List; +import java.util.ArrayList; + +@SuppressWarnings({"all", "warnings", "unchecked"}) +public class RoleDefParser extends Parser { + public static final String[] tokenNames = new String[] { + "", "", "", "", "COLON", "COMMA", "COMMENT", "GEQ", "STR", "WS" + }; + + public static final int EOF=-1; + public static final int COLON=4; + public static final int COMMA=5; + public static final int COMMENT=6; + public static final int GEQ=7; + public static final int STR=8; + public static final int WS=9; + + // delegates + public Parser[] getDelegates() { + return new Parser[] {}; + } + + // delegators + + + public RoleDefParser(TokenStream input) { + this(input, new RecognizerSharedState()); + } + public RoleDefParser(TokenStream input, RecognizerSharedState state) { + super(input, state); + } + + public String[] getTokenNames() { return RoleDefParser.tokenNames; } + public String getGrammarFileName() { return "RoleDef.g"; } + + + + // $ANTLR start "file" + // RoleDef.g:17:1: file returns [List lines] : (ldef= line_def |lrel= line_rel )* EOF ; + public final List file() throws RecognitionException { + List lines = null; + + + RoleDef ldef =null; + + RoleRel lrel =null; + + + try { + // RoleDef.g:18:5: ( (ldef= line_def |lrel= line_rel )* EOF ) + // RoleDef.g:18:7: (ldef= line_def |lrel= line_rel )* EOF + { + lines = new ArrayList(); + + // RoleDef.g:19:7: (ldef= line_def |lrel= line_rel )* + loop1: + do { + int alt1=3; + int LA1_0 = input.LA(1); + + if ( (LA1_0==STR) ) { + int LA1_2 = input.LA(2); + + if ( (LA1_2==COLON) ) { + alt1=1; + } + else if ( (LA1_2==GEQ) ) { + alt1=2; + } + + + } + + + switch (alt1) { + case 1 : + // RoleDef.g:19:8: ldef= line_def + { + pushFollow(FOLLOW_line_def_in_file68); + ldef=line_def(); + + state._fsp--; + + + lines.add(ldef); + + } + break; + case 2 : + // RoleDef.g:19:49: lrel= line_rel + { + pushFollow(FOLLOW_line_rel_in_file76); + lrel=line_rel(); + + state._fsp--; + + + lines.add(lrel); + + } + break; + + default : + break loop1; + } + } while (true); + + + match(input,EOF,FOLLOW_EOF_in_file83); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return lines; + } + // $ANTLR end "file" + + + + // $ANTLR start "line_def" + // RoleDef.g:22:1: line_def returns [RoleDef def] : name= string COLON fm= string ( COMMA mm= string )* ; + public final RoleDef line_def() throws RecognitionException { + RoleDef def = null; + + + RoleDefParser.string_return name =null; + + RoleDefParser.string_return fm =null; + + RoleDefParser.string_return mm =null; + + + try { + // RoleDef.g:23:5: (name= string COLON fm= string ( COMMA mm= string )* ) + // RoleDef.g:23:7: name= string COLON fm= string ( COMMA mm= string )* + { + pushFollow(FOLLOW_string_in_line_def106); + name=string(); + + state._fsp--; + + + def = new RoleDef((name!=null?input.toString(name.start,name.stop):null)); + + match(input,COLON,FOLLOW_COLON_in_line_def110); + + pushFollow(FOLLOW_string_in_line_def114); + fm=string(); + + state._fsp--; + + + def.addMember((fm!=null?input.toString(fm.start,fm.stop):null)); + + // RoleDef.g:23:97: ( COMMA mm= string )* + loop2: + do { + int alt2=2; + int LA2_0 = input.LA(1); + + if ( (LA2_0==COMMA) ) { + alt2=1; + } + + + switch (alt2) { + case 1 : + // RoleDef.g:23:98: COMMA mm= string + { + match(input,COMMA,FOLLOW_COMMA_in_line_def119); + + pushFollow(FOLLOW_string_in_line_def123); + mm=string(); + + state._fsp--; + + + def.addMember((mm!=null?input.toString(mm.start,mm.stop):null)); + + } + break; + + default : + break loop2; + } + } while (true); + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return def; + } + // $ANTLR end "line_def" + + + + // $ANTLR start "line_rel" + // RoleDef.g:26:1: line_rel returns [RoleRel rel] : sup= string GEQ sub= string ; + public final RoleRel line_rel() throws RecognitionException { + RoleRel rel = null; + + + RoleDefParser.string_return sup =null; + + RoleDefParser.string_return sub =null; + + + try { + // RoleDef.g:27:5: (sup= string GEQ sub= string ) + // RoleDef.g:27:7: sup= string GEQ sub= string + { + pushFollow(FOLLOW_string_in_line_rel152); + sup=string(); + + state._fsp--; + + + match(input,GEQ,FOLLOW_GEQ_in_line_rel154); + + pushFollow(FOLLOW_string_in_line_rel158); + sub=string(); + + state._fsp--; + + + rel = new RoleRel((sup!=null?input.toString(sup.start,sup.stop):null), (sub!=null?input.toString(sub.start,sub.stop):null)); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return rel; + } + // $ANTLR end "line_rel" + + + public static class string_return extends ParserRuleReturnScope { + }; + + + // $ANTLR start "string" + // RoleDef.g:30:1: string : STR ; + public final RoleDefParser.string_return string() throws RecognitionException { + RoleDefParser.string_return retval = new RoleDefParser.string_return(); + retval.start = input.LT(1); + + + try { + // RoleDef.g:31:5: ( STR ) + // RoleDef.g:31:7: STR + { + match(input,STR,FOLLOW_STR_in_string181); + + } + + retval.stop = input.LT(-1); + + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return retval; + } + // $ANTLR end "string" + + // Delegated rules + + + + + public static final BitSet FOLLOW_line_def_in_file68 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_line_rel_in_file76 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_EOF_in_file83 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_string_in_line_def106 = new BitSet(new long[]{0x0000000000000010L}); + public static final BitSet FOLLOW_COLON_in_line_def110 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_string_in_line_def114 = new BitSet(new long[]{0x0000000000000022L}); + public static final BitSet FOLLOW_COMMA_in_line_def119 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_string_in_line_def123 = new BitSet(new long[]{0x0000000000000022L}); + public static final BitSet FOLLOW_string_in_line_rel152 = new BitSet(new long[]{0x0000000000000080L}); + public static final BitSet FOLLOW_GEQ_in_line_rel154 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_string_in_line_rel158 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_STR_in_string181 = new BitSet(new long[]{0x0000000000000002L}); + +} diff --git a/src/eu.aniketos.securebpmn/src/main/java/org/antlr/satmc/SatmcLexer.java b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/satmc/SatmcLexer.java new file mode 100644 index 0000000..10ea429 --- /dev/null +++ b/src/eu.aniketos.securebpmn/src/main/java/org/antlr/satmc/SatmcLexer.java @@ -0,0 +1,1592 @@ +// $ANTLR 3.4 Satmc.g 2012-01-23 13:53:58 +package org.antlr.satmc; + +import org.antlr.runtime.*; +import java.util.Stack; +import java.util.List; +import java.util.ArrayList; + +@SuppressWarnings({"all", "warnings", "unchecked"}) +public class SatmcLexer extends Lexer { + public static final int EOF=-1; + public static final int CFS=4; + public static final int CLAUSES=5; + public static final int COMMA=6; + public static final int COMMENTS=7; + public static final int CONSTANT=8; + public static final int C_BRACES=9; + public static final int C_BRACKET=10; + public static final int C_PARENTHESIS=11; + public static final int DETAILS=12; + public static final int ERROR=13; + public static final int FILE=14; + public static final int FTEXT=15; + public static final int GOAL=16; + public static final int INPUT=17; + public static final int NEWLINE=18; + public static final int NUMBER=19; + public static final int O_BRACES=20; + public static final int O_BRACKET=21; + public static final int O_PARENTHESIS=22; + public static final int PERCENT=23; + public static final int RULES=24; + public static final int STAT=25; + public static final int SUMMARY=26; + public static final int TRACE=27; + public static final int VERSION=28; + public static final int VERSION_NR=29; + public static final int WARNING=30; + public static final int WS=31; + + // delegates + // delegators + public Lexer[] getDelegates() { + return new Lexer[] {}; + } + + public SatmcLexer() {} + public SatmcLexer(CharStream input) { + this(input, new RecognizerSharedState()); + } + public SatmcLexer(CharStream input, RecognizerSharedState state) { + super(input,state); + } + public String getGrammarFileName() { return "Satmc.g"; } + + // $ANTLR start "CFS" + public final void mCFS() throws RecognitionException { + try { + int _type = CFS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:4:5: ( 'CLOSED_FINAL_STATE:' ) + // Satmc.g:4:7: 'CLOSED_FINAL_STATE:' + { + match("CLOSED_FINAL_STATE:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "CFS" + + // $ANTLR start "CLAUSES" + public final void mCLAUSES() throws RecognitionException { + try { + int _type = CLAUSES; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:5:9: ( 'CLAUSES:' ) + // Satmc.g:5:11: 'CLAUSES:' + { + match("CLAUSES:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "CLAUSES" + + // $ANTLR start "COMMA" + public final void mCOMMA() throws RecognitionException { + try { + int _type = COMMA; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:6:7: ( ',' ) + // Satmc.g:6:9: ',' + { + match(','); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "COMMA" + + // $ANTLR start "COMMENTS" + public final void mCOMMENTS() throws RecognitionException { + try { + int _type = COMMENTS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:7:10: ( 'COMMENTS' ) + // Satmc.g:7:12: 'COMMENTS' + { + match("COMMENTS"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "COMMENTS" + + // $ANTLR start "C_BRACES" + public final void mC_BRACES() throws RecognitionException { + try { + int _type = C_BRACES; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:8:10: ( '}' ) + // Satmc.g:8:12: '}' + { + match('}'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "C_BRACES" + + // $ANTLR start "C_BRACKET" + public final void mC_BRACKET() throws RecognitionException { + try { + int _type = C_BRACKET; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:9:11: ( ']' ) + // Satmc.g:9:13: ']' + { + match(']'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "C_BRACKET" + + // $ANTLR start "C_PARENTHESIS" + public final void mC_PARENTHESIS() throws RecognitionException { + try { + int _type = C_PARENTHESIS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:10:15: ( ')' ) + // Satmc.g:10:17: ')' + { + match(')'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "C_PARENTHESIS" + + // $ANTLR start "DETAILS" + public final void mDETAILS() throws RecognitionException { + try { + int _type = DETAILS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:11:9: ( 'DETAILS' ) + // Satmc.g:11:11: 'DETAILS' + { + match("DETAILS"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "DETAILS" + + // $ANTLR start "ERROR" + public final void mERROR() throws RecognitionException { + try { + int _type = ERROR; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:12:7: ( '% ERROR:' ) + // Satmc.g:12:9: '% ERROR:' + { + match("% ERROR:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "ERROR" + + // $ANTLR start "GOAL" + public final void mGOAL() throws RecognitionException { + try { + int _type = GOAL; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:13:6: ( 'GOAL:' ) + // Satmc.g:13:8: 'GOAL:' + { + match("GOAL:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "GOAL" + + // $ANTLR start "INPUT" + public final void mINPUT() throws RecognitionException { + try { + int _type = INPUT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:14:7: ( 'INPUT' ) + // Satmc.g:14:9: 'INPUT' + { + match("INPUT"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "INPUT" + + // $ANTLR start "O_BRACES" + public final void mO_BRACES() throws RecognitionException { + try { + int _type = O_BRACES; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:15:10: ( '{' ) + // Satmc.g:15:12: '{' + { + match('{'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "O_BRACES" + + // $ANTLR start "O_BRACKET" + public final void mO_BRACKET() throws RecognitionException { + try { + int _type = O_BRACKET; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:16:11: ( '[' ) + // Satmc.g:16:13: '[' + { + match('['); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "O_BRACKET" + + // $ANTLR start "O_PARENTHESIS" + public final void mO_PARENTHESIS() throws RecognitionException { + try { + int _type = O_PARENTHESIS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:17:15: ( '(' ) + // Satmc.g:17:17: '(' + { + match('('); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "O_PARENTHESIS" + + // $ANTLR start "PERCENT" + public final void mPERCENT() throws RecognitionException { + try { + int _type = PERCENT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:18:9: ( '% ' ) + // Satmc.g:18:11: '% ' + { + match("% "); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "PERCENT" + + // $ANTLR start "RULES" + public final void mRULES() throws RecognitionException { + try { + int _type = RULES; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:19:7: ( 'RULES:' ) + // Satmc.g:19:9: 'RULES:' + { + match("RULES:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "RULES" + + // $ANTLR start "STAT" + public final void mSTAT() throws RecognitionException { + try { + int _type = STAT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:20:6: ( 'STATISTICS' ) + // Satmc.g:20:8: 'STATISTICS' + { + match("STATISTICS"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "STAT" + + // $ANTLR start "SUMMARY" + public final void mSUMMARY() throws RecognitionException { + try { + int _type = SUMMARY; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:21:9: ( 'SUMMARY' ) + // Satmc.g:21:11: 'SUMMARY' + { + match("SUMMARY"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "SUMMARY" + + // $ANTLR start "TRACE" + public final void mTRACE() throws RecognitionException { + try { + int _type = TRACE; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:22:7: ( 'TRACE:' ) + // Satmc.g:22:9: 'TRACE:' + { + match("TRACE:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "TRACE" + + // $ANTLR start "VERSION" + public final void mVERSION() throws RecognitionException { + try { + int _type = VERSION; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:23:9: ( 'BACKEND SATMC VERSION' ) + // Satmc.g:23:11: 'BACKEND SATMC VERSION' + { + match("BACKEND SATMC VERSION"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "VERSION" + + // $ANTLR start "WARNING" + public final void mWARNING() throws RecognitionException { + try { + int _type = WARNING; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:24:9: ( '% WARNING:' ) + // Satmc.g:24:11: '% WARNING:' + { + match("% WARNING:"); + + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "WARNING" + + // $ANTLR start "VERSION_NR" + public final void mVERSION_NR() throws RecognitionException { + try { + int _type = VERSION_NR; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:174:5: ( '0' .. '9' '.' '0' .. '9' '.' '0' .. '9' ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | O_PARENTHESIS | C_PARENTHESIS )* ) + // Satmc.g:174:7: '0' .. '9' '.' '0' .. '9' '.' '0' .. '9' ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | O_PARENTHESIS | C_PARENTHESIS )* + { + matchRange('0','9'); + + match('.'); + + matchRange('0','9'); + + match('.'); + + matchRange('0','9'); + + // Satmc.g:174:42: ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | O_PARENTHESIS | C_PARENTHESIS )* + loop1: + do { + int alt1=2; + int LA1_0 = input.LA(1); + + if ( ((LA1_0 >= '(' && LA1_0 <= ')')||(LA1_0 >= '0' && LA1_0 <= '9')||(LA1_0 >= 'A' && LA1_0 <= 'Z')||LA1_0=='_'||(LA1_0 >= 'a' && LA1_0 <= 'z')) ) { + alt1=1; + } + + + switch (alt1) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= '(' && input.LA(1) <= ')')||(input.LA(1) >= '0' && input.LA(1) <= '9')||(input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_'||(input.LA(1) >= 'a' && input.LA(1) <= 'z') ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + break loop1; + } + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "VERSION_NR" + + // $ANTLR start "CONSTANT" + public final void mCONSTANT() throws RecognitionException { + try { + int _type = CONSTANT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:178:5: ( ( 'A' .. 'Z' | '_' )+ ) + // Satmc.g:178:7: ( 'A' .. 'Z' | '_' )+ + { + // Satmc.g:178:7: ( 'A' .. 'Z' | '_' )+ + int cnt2=0; + loop2: + do { + int alt2=2; + int LA2_0 = input.LA(1); + + if ( ((LA2_0 >= 'A' && LA2_0 <= 'Z')||LA2_0=='_') ) { + alt2=1; + } + + + switch (alt2) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= 'A' && input.LA(1) <= 'Z')||input.LA(1)=='_' ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + if ( cnt2 >= 1 ) break loop2; + EarlyExitException eee = + new EarlyExitException(2, input); + throw eee; + } + cnt2++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "CONSTANT" + + // $ANTLR start "NUMBER" + public final void mNUMBER() throws RecognitionException { + try { + int _type = NUMBER; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:182:4: ( ( '0' .. '9' )+ ) + // Satmc.g:182:6: ( '0' .. '9' )+ + { + // Satmc.g:182:6: ( '0' .. '9' )+ + int cnt3=0; + loop3: + do { + int alt3=2; + int LA3_0 = input.LA(1); + + if ( ((LA3_0 >= '0' && LA3_0 <= '9')) ) { + alt3=1; + } + + + switch (alt3) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + if ( cnt3 >= 1 ) break loop3; + EarlyExitException eee = + new EarlyExitException(3, input); + throw eee; + } + cnt3++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "NUMBER" + + // $ANTLR start "FTEXT" + public final void mFTEXT() throws RecognitionException { + try { + int _type = FTEXT; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:186:5: ( ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '_' )+ ) + // Satmc.g:186:7: ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '_' )+ + { + // Satmc.g:186:7: ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '_' )+ + int cnt4=0; + loop4: + do { + int alt4=5; + switch ( input.LA(1) ) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + alt4=1; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + { + alt4=2; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + alt4=3; + } + break; + case '_': + { + alt4=4; + } + break; + + } + + switch (alt4) { + case 1 : + // Satmc.g:186:9: 'a' .. 'z' + { + matchRange('a','z'); + + } + break; + case 2 : + // Satmc.g:186:20: 'A' .. 'Z' + { + matchRange('A','Z'); + + } + break; + case 3 : + // Satmc.g:186:31: NUMBER + { + mNUMBER(); + + + } + break; + case 4 : + // Satmc.g:186:39: '_' + { + match('_'); + + } + break; + + default : + if ( cnt4 >= 1 ) break loop4; + EarlyExitException eee = + new EarlyExitException(4, input); + throw eee; + } + cnt4++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "FTEXT" + + // $ANTLR start "FILE" + public final void mFILE() throws RecognitionException { + try { + int _type = FILE; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:190:5: ( ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '.' )+ ) + // Satmc.g:190:7: ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '.' )+ + { + // Satmc.g:190:7: ( 'a' .. 'z' | 'A' .. 'Z' | NUMBER | '.' )+ + int cnt5=0; + loop5: + do { + int alt5=5; + switch ( input.LA(1) ) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + { + alt5=1; + } + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + { + alt5=2; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + alt5=3; + } + break; + case '.': + { + alt5=4; + } + break; + + } + + switch (alt5) { + case 1 : + // Satmc.g:190:9: 'a' .. 'z' + { + matchRange('a','z'); + + } + break; + case 2 : + // Satmc.g:190:20: 'A' .. 'Z' + { + matchRange('A','Z'); + + } + break; + case 3 : + // Satmc.g:190:31: NUMBER + { + mNUMBER(); + + + } + break; + case 4 : + // Satmc.g:190:40: '.' + { + match('.'); + + } + break; + + default : + if ( cnt5 >= 1 ) break loop5; + EarlyExitException eee = + new EarlyExitException(5, input); + throw eee; + } + cnt5++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "FILE" + + // $ANTLR start "NEWLINE" + public final void mNEWLINE() throws RecognitionException { + try { + int _type = NEWLINE; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:194:5: ( ( '\\r' )? '\\n' ) + // Satmc.g:194:7: ( '\\r' )? '\\n' + { + // Satmc.g:194:7: ( '\\r' )? + int alt6=2; + int LA6_0 = input.LA(1); + + if ( (LA6_0=='\r') ) { + alt6=1; + } + switch (alt6) { + case 1 : + // Satmc.g:194:7: '\\r' + { + match('\r'); + + } + break; + + } + + + match('\n'); + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "NEWLINE" + + // $ANTLR start "WS" + public final void mWS() throws RecognitionException { + try { + int _type = WS; + int _channel = DEFAULT_TOKEN_CHANNEL; + // Satmc.g:198:5: ( ( ' ' | '\\t' )+ ) + // Satmc.g:198:7: ( ' ' | '\\t' )+ + { + // Satmc.g:198:7: ( ' ' | '\\t' )+ + int cnt7=0; + loop7: + do { + int alt7=2; + int LA7_0 = input.LA(1); + + if ( (LA7_0=='\t'||LA7_0==' ') ) { + alt7=1; + } + + + switch (alt7) { + case 1 : + // Satmc.g: + { + if ( input.LA(1)=='\t'||input.LA(1)==' ' ) { + input.consume(); + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + recover(mse); + throw mse; + } + + + } + break; + + default : + if ( cnt7 >= 1 ) break loop7; + EarlyExitException eee = + new EarlyExitException(7, input); + throw eee; + } + cnt7++; + } while (true); + + + } + + state.type = _type; + state.channel = _channel; + } + finally { + // do for sure before leaving + } + } + // $ANTLR end "WS" + + public void mTokens() throws RecognitionException { + // Satmc.g:1:8: ( CFS | CLAUSES | COMMA | COMMENTS | C_BRACES | C_BRACKET | C_PARENTHESIS | DETAILS | ERROR | GOAL | INPUT | O_BRACES | O_BRACKET | O_PARENTHESIS | PERCENT | RULES | STAT | SUMMARY | TRACE | VERSION | WARNING | VERSION_NR | CONSTANT | NUMBER | FTEXT | FILE | NEWLINE | WS ) + int alt8=28; + alt8 = dfa8.predict(input); + switch (alt8) { + case 1 : + // Satmc.g:1:10: CFS + { + mCFS(); + + + } + break; + case 2 : + // Satmc.g:1:14: CLAUSES + { + mCLAUSES(); + + + } + break; + case 3 : + // Satmc.g:1:22: COMMA + { + mCOMMA(); + + + } + break; + case 4 : + // Satmc.g:1:28: COMMENTS + { + mCOMMENTS(); + + + } + break; + case 5 : + // Satmc.g:1:37: C_BRACES + { + mC_BRACES(); + + + } + break; + case 6 : + // Satmc.g:1:46: C_BRACKET + { + mC_BRACKET(); + + + } + break; + case 7 : + // Satmc.g:1:56: C_PARENTHESIS + { + mC_PARENTHESIS(); + + + } + break; + case 8 : + // Satmc.g:1:70: DETAILS + { + mDETAILS(); + + + } + break; + case 9 : + // Satmc.g:1:78: ERROR + { + mERROR(); + + + } + break; + case 10 : + // Satmc.g:1:84: GOAL + { + mGOAL(); + + + } + break; + case 11 : + // Satmc.g:1:89: INPUT + { + mINPUT(); + + + } + break; + case 12 : + // Satmc.g:1:95: O_BRACES + { + mO_BRACES(); + + + } + break; + case 13 : + // Satmc.g:1:104: O_BRACKET + { + mO_BRACKET(); + + + } + break; + case 14 : + // Satmc.g:1:114: O_PARENTHESIS + { + mO_PARENTHESIS(); + + + } + break; + case 15 : + // Satmc.g:1:128: PERCENT + { + mPERCENT(); + + + } + break; + case 16 : + // Satmc.g:1:136: RULES + { + mRULES(); + + + } + break; + case 17 : + // Satmc.g:1:142: STAT + { + mSTAT(); + + + } + break; + case 18 : + // Satmc.g:1:147: SUMMARY + { + mSUMMARY(); + + + } + break; + case 19 : + // Satmc.g:1:155: TRACE + { + mTRACE(); + + + } + break; + case 20 : + // Satmc.g:1:161: VERSION + { + mVERSION(); + + + } + break; + case 21 : + // Satmc.g:1:169: WARNING + { + mWARNING(); + + + } + break; + case 22 : + // Satmc.g:1:177: VERSION_NR + { + mVERSION_NR(); + + + } + break; + case 23 : + // Satmc.g:1:188: CONSTANT + { + mCONSTANT(); + + + } + break; + case 24 : + // Satmc.g:1:197: NUMBER + { + mNUMBER(); + + + } + break; + case 25 : + // Satmc.g:1:204: FTEXT + { + mFTEXT(); + + + } + break; + case 26 : + // Satmc.g:1:210: FILE + { + mFILE(); + + + } + break; + case 27 : + // Satmc.g:1:215: NEWLINE + { + mNEWLINE(); + + + } + break; + case 28 : + // Satmc.g:1:223: WS + { + mWS(); + + + } + break; + + } + + } + + + protected DFA8 dfa8 = new DFA8(this); + static final String DFA8_eotS = + "\1\uffff\1\32\4\uffff\1\32\1\uffff\2\32\3\uffff\4\32\1\46\1\32\1"+ + "\51\1\32\3\uffff\2\32\1\uffff\1\51\1\32\1\61\7\32\1\25\1\uffff\1"+ + "\46\1\51\1\uffff\5\32\3\uffff\7\32\1\25\13\32\1\25\4\32\1\uffff"+ + "\1\126\5\32\1\135\4\32\2\uffff\2\32\1\uffff\1\32\1\135\1\uffff\2"+ + "\135\3\32\1\152\1\32\1\154\2\32\1\uffff\1\157\1\uffff\1\32\2\uffff"+ + "\1\32\1\uffff\2\32\1\164\1\32\1\uffff\7\32\1\uffff"; + static final String DFA8_eofS = + "\175\uffff"; + static final String DFA8_minS = + "\1\11\1\56\4\uffff\1\56\1\40\2\56\3\uffff\7\56\1\60\3\uffff\2\56"+ + "\1\uffff\2\56\1\105\7\56\1\60\1\uffff\2\56\1\uffff\1\60\4\56\3\uffff"+ + "\23\56\1\60\4\56\1\uffff\13\56\2\uffff\2\56\1\uffff\2\56\1\uffff"+ + "\2\56\1\60\5\56\1\40\1\60\1\uffff\1\56\1\uffff\1\56\2\uffff\1\60"+ + "\1\uffff\1\56\1\60\1\56\1\60\1\uffff\7\60\1\uffff"; + static final String DFA8_maxS = + "\1\175\1\172\4\uffff\1\172\1\40\2\172\3\uffff\10\172\3\uffff\2\172"+ + "\1\uffff\2\172\1\127\7\172\1\71\1\uffff\2\172\1\uffff\5\172\3\uffff"+ + "\7\172\1\56\13\172\1\71\4\172\1\uffff\13\172\2\uffff\2\172\1\uffff"+ + "\2\172\1\uffff\12\172\1\uffff\1\172\1\uffff\1\172\2\uffff\1\172"+ + "\1\uffff\4\172\1\uffff\7\172\1\uffff"; + static final String DFA8_acceptS = + "\2\uffff\1\3\1\5\1\6\1\7\4\uffff\1\14\1\15\1\16\10\uffff\1\32\1"+ + "\33\1\34\2\uffff\1\27\13\uffff\1\30\2\uffff\1\31\5\uffff\1\11\1"+ + "\25\1\17\30\uffff\1\12\13\uffff\1\13\1\20\2\uffff\1\23\2\uffff\1"+ + "\26\12\uffff\1\2\1\uffff\1\10\1\uffff\1\22\1\24\1\uffff\1\4\4\uffff"+ + "\1\21\7\uffff\1\1"; + static final String DFA8_specialS = + "\175\uffff}>"; + static final String[] DFA8_transitionS = { + "\1\27\1\26\2\uffff\1\26\22\uffff\1\27\4\uffff\1\7\2\uffff\1"+ + "\14\1\5\2\uffff\1\2\1\uffff\1\25\1\uffff\12\21\7\uffff\1\22"+ + "\1\20\1\1\1\6\2\22\1\10\1\22\1\11\10\22\1\15\1\16\1\17\6\22"+ + "\1\13\1\uffff\1\4\1\uffff\1\24\1\uffff\32\23\1\12\1\uffff\1"+ + "\3", + "\1\25\1\uffff\12\33\7\uffff\13\22\1\30\2\22\1\31\13\22\4\uffff"+ + "\1\24\1\uffff\32\23", + "", + "", + "", + "", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\34\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\35", + "\1\25\1\uffff\12\33\7\uffff\16\22\1\36\13\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\15\22\1\37\14\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "", + "", + "", + "\1\25\1\uffff\12\33\7\uffff\24\22\1\40\5\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\41\1\42\5\22\4\uffff\1"+ + "\24\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\21\22\1\43\10\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\1\44\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\45\1\uffff\12\47\7\uffff\32\50\4\uffff\1\51\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\32\50\6\uffff\32\23", + "\12\51\7\uffff\32\52\4\uffff\1\24\1\uffff\32\51", + "", + "", + "", + "\1\25\1\uffff\12\33\7\uffff\1\54\15\22\1\53\13\22\4\uffff\1"+ + "\24\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\14\22\1\55\15\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "", + "\1\25\1\uffff\12\33\7\uffff\32\50\6\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\56\6\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\57\21\uffff\1\60", + "\1\25\1\uffff\12\33\7\uffff\1\62\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\17\22\1\63\12\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\13\22\1\64\16\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\1\65\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\14\22\1\66\15\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\1\67\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\2\22\1\70\27\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\12\71", + "", + "\1\25\1\uffff\12\47\7\uffff\32\50\4\uffff\1\51\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\32\50\6\uffff\32\23", + "", + "\12\51\7\uffff\32\52\4\uffff\1\24\1\uffff\32\51", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\72\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\24\22\1\73\5\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\14\22\1\74\15\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\1\75\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "", + "", + "", + "\1\25\1\uffff\12\33\7\uffff\13\22\1\76\16\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\24\22\1\77\5\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\100\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\101\6\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\14\22\1\102\15\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\2\22\1\103\27\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\12\22\1\104\17\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\105", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\106\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\107\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\110\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\10\22\1\111\21\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\1\112\6\uffff\32\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\113\6\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\114\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\10\22\1\115\21\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\1\116\31\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\117\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\120\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\12\121", + "\1\25\1\uffff\12\33\7\uffff\3\22\1\122\26\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\4\22\1\123\25\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\15\22\1\124\14\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\13\22\1\125\16\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "\1\25\1\uffff\12\33\1\127\6\uffff\32\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\130\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\21\22\1\131\10\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\1\132\6\uffff\32\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\15\22\1\133\14\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\137\7\uffff\32\136\6\uffff\32\134", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\140\1\uffff\32"+ + "\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\141\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\142\6\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\143\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "", + "", + "\1\25\1\uffff\12\33\7\uffff\23\22\1\144\6\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\30\22\1\145\1\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "", + "\1\25\1\uffff\12\33\7\uffff\3\22\1\146\26\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\137\7\uffff\32\136\6\uffff\32\134", + "", + "\1\25\1\uffff\12\137\7\uffff\32\136\6\uffff\32\134", + "\1\25\1\uffff\12\137\7\uffff\32\136\6\uffff\32\134", + "\12\51\7\uffff\5\52\1\147\24\52\4\uffff\1\24\1\uffff\32\51", + "\1\25\1\uffff\12\33\1\150\6\uffff\32\22\4\uffff\1\24\1\uffff"+ + "\32\23", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\151\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\10\22\1\153\21\22\4\uffff\1\24"+ + "\1\uffff\32\23", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "\1\155\15\uffff\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1"+ + "\24\1\uffff\32\23", + "\12\51\7\uffff\10\52\1\156\21\52\4\uffff\1\24\1\uffff\32\51", + "", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "", + "\1\25\1\uffff\12\33\7\uffff\2\22\1\160\27\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "", + "", + "\12\51\7\uffff\15\52\1\161\14\52\4\uffff\1\24\1\uffff\32\51", + "", + "\1\25\1\uffff\12\33\7\uffff\22\22\1\162\7\22\4\uffff\1\24\1"+ + "\uffff\32\23", + "\12\51\7\uffff\1\163\31\52\4\uffff\1\24\1\uffff\32\51", + "\1\25\1\uffff\12\33\7\uffff\32\22\4\uffff\1\24\1\uffff\32\23", + "\12\51\7\uffff\13\52\1\165\16\52\4\uffff\1\24\1\uffff\32\51", + "", + "\12\51\7\uffff\32\52\4\uffff\1\166\1\uffff\32\51", + "\12\51\7\uffff\22\52\1\167\7\52\4\uffff\1\24\1\uffff\32\51", + "\12\51\7\uffff\23\52\1\170\6\52\4\uffff\1\24\1\uffff\32\51", + "\12\51\7\uffff\1\171\31\52\4\uffff\1\24\1\uffff\32\51", + "\12\51\7\uffff\23\52\1\172\6\52\4\uffff\1\24\1\uffff\32\51", + "\12\51\7\uffff\4\52\1\173\25\52\4\uffff\1\24\1\uffff\32\51", + "\12\51\1\174\6\uffff\32\52\4\uffff\1\24\1\uffff\32\51", + "" + }; + + static final short[] DFA8_eot = DFA.unpackEncodedString(DFA8_eotS); + static final short[] DFA8_eof = DFA.unpackEncodedString(DFA8_eofS); + static final char[] DFA8_min = DFA.unpackEncodedStringToUnsignedChars(DFA8_minS); + static final char[] DFA8_max = DFA.unpackEncodedStringToUnsignedChars(DFA8_maxS); + static final short[] DFA8_accept = DFA.unpackEncodedString(DFA8_acceptS); + static final short[] DFA8_special = DFA.unpackEncodedString(DFA8_specialS); + static final short[][] DFA8_transition; + + static { + int numStates = DFA8_transitionS.length; + DFA8_transition = new short[numStates][]; + for (int i=0; i", "", "", "", "CFS", "CLAUSES", "COMMA", "COMMENTS", "CONSTANT", "C_BRACES", "C_BRACKET", "C_PARENTHESIS", "DETAILS", "ERROR", "FILE", "FTEXT", "GOAL", "INPUT", "NEWLINE", "NUMBER", "O_BRACES", "O_BRACKET", "O_PARENTHESIS", "PERCENT", "RULES", "STAT", "SUMMARY", "TRACE", "VERSION", "VERSION_NR", "WARNING", "WS" + }; + + public static final int EOF=-1; + public static final int CFS=4; + public static final int CLAUSES=5; + public static final int COMMA=6; + public static final int COMMENTS=7; + public static final int CONSTANT=8; + public static final int C_BRACES=9; + public static final int C_BRACKET=10; + public static final int C_PARENTHESIS=11; + public static final int DETAILS=12; + public static final int ERROR=13; + public static final int FILE=14; + public static final int FTEXT=15; + public static final int GOAL=16; + public static final int INPUT=17; + public static final int NEWLINE=18; + public static final int NUMBER=19; + public static final int O_BRACES=20; + public static final int O_BRACKET=21; + public static final int O_PARENTHESIS=22; + public static final int PERCENT=23; + public static final int RULES=24; + public static final int STAT=25; + public static final int SUMMARY=26; + public static final int TRACE=27; + public static final int VERSION=28; + public static final int VERSION_NR=29; + public static final int WARNING=30; + public static final int WS=31; + + // delegates + public Parser[] getDelegates() { + return new Parser[] {}; + } + + // delegators + + + public SatmcParser(TokenStream input) { + this(input, new RecognizerSharedState()); + } + public SatmcParser(TokenStream input, RecognizerSharedState state) { + super(input, state); + } + + public String[] getTokenNames() { return SatmcParser.tokenNames; } + public String getGrammarFileName() { return "Satmc.g"; } + + + + // $ANTLR start "output" + // Satmc.g:37:1: output returns [SatmcMessage message] : ( ( NEWLINE )* ( NEWLINE section_warning )* ( error |s= result ) ( NEWLINE )* EOF |); + public final SatmcMessage output() throws RecognitionException { + SatmcMessage message = null; + + + SatmcMessage s =null; + + + try { + // Satmc.g:38:5: ( ( NEWLINE )* ( NEWLINE section_warning )* ( error |s= result ) ( NEWLINE )* EOF |) + int alt5=2; + int LA5_0 = input.LA(1); + + if ( ((LA5_0 >= INPUT && LA5_0 <= NEWLINE)) ) { + alt5=1; + } + else if ( (LA5_0==EOF) ) { + alt5=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 5, 0, input); + + throw nvae; + + } + switch (alt5) { + case 1 : + // Satmc.g:38:8: ( NEWLINE )* ( NEWLINE section_warning )* ( error |s= result ) ( NEWLINE )* EOF + { + // Satmc.g:38:8: ( NEWLINE )* + loop1: + do { + int alt1=2; + int LA1_0 = input.LA(1); + + if ( (LA1_0==NEWLINE) ) { + int LA1_1 = input.LA(2); + + if ( ((LA1_1 >= INPUT && LA1_1 <= NEWLINE)) ) { + alt1=1; + } + + + } + + + switch (alt1) { + case 1 : + // Satmc.g:38:8: NEWLINE + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_output168); + + } + break; + + default : + break loop1; + } + } while (true); + + + // Satmc.g:38:17: ( NEWLINE section_warning )* + loop2: + do { + int alt2=2; + int LA2_0 = input.LA(1); + + if ( (LA2_0==NEWLINE) ) { + int LA2_1 = input.LA(2); + + if ( (LA2_1==WARNING) ) { + alt2=1; + } + + + } + + + switch (alt2) { + case 1 : + // Satmc.g:38:19: NEWLINE section_warning + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_output173); + + pushFollow(FOLLOW_section_warning_in_output175); + section_warning(); + + state._fsp--; + + + } + break; + + default : + break loop2; + } + } while (true); + + + // Satmc.g:38:46: ( error |s= result ) + int alt3=2; + int LA3_0 = input.LA(1); + + if ( (LA3_0==NEWLINE) ) { + alt3=1; + } + else if ( (LA3_0==INPUT) ) { + alt3=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 3, 0, input); + + throw nvae; + + } + switch (alt3) { + case 1 : + // Satmc.g:38:48: error + { + pushFollow(FOLLOW_error_in_output182); + error(); + + state._fsp--; + + + message = new SatmcMessage(Summary.ERROR, null, null, null); + + } + break; + case 2 : + // Satmc.g:39:18: s= result + { + pushFollow(FOLLOW_result_in_output206); + s=result(); + + state._fsp--; + + + message = s; + + } + break; + + } + + + // Satmc.g:40:19: ( NEWLINE )* + loop4: + do { + int alt4=2; + int LA4_0 = input.LA(1); + + if ( (LA4_0==NEWLINE) ) { + alt4=1; + } + + + switch (alt4) { + case 1 : + // Satmc.g:40:19: NEWLINE + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_output228); + + } + break; + + default : + break loop4; + } + } while (true); + + + match(input,EOF,FOLLOW_EOF_in_output231); + + } + break; + case 2 : + // Satmc.g:42:5: + { + } + break; + + } + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return message; + } + // $ANTLR end "output" + + + + // $ANTLR start "error" + // Satmc.g:44:1: error : NEWLINE section_error ; + public final void error() throws RecognitionException { + try { + // Satmc.g:45:5: ( NEWLINE section_error ) + // Satmc.g:45:7: NEWLINE section_error + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_error258); + + pushFollow(FOLLOW_section_error_in_error260); + section_error(); + + state._fsp--; + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "error" + + + + // $ANTLR start "result" + // Satmc.g:48:1: result returns [SatmcMessage message] : line_input NEWLINE ls= line_summary NEWLINE ( NEWLINE )? (lg= line_goal NEWLINE NEWLINE )? section_details NEWLINE NEWLINE line_version NEWLINE NEWLINE ( section_comments )? section_stat (st= section_trace )? (lc= line_cfs )? ; + public final SatmcMessage result() throws RecognitionException { + SatmcMessage message = null; + + + Summary ls =null; + + SatmcFunction lg =null; + + List st =null; + + List lc =null; + + + try { + // Satmc.g:49:5: ( line_input NEWLINE ls= line_summary NEWLINE ( NEWLINE )? (lg= line_goal NEWLINE NEWLINE )? section_details NEWLINE NEWLINE line_version NEWLINE NEWLINE ( section_comments )? section_stat (st= section_trace )? (lc= line_cfs )? ) + // Satmc.g:49:7: line_input NEWLINE ls= line_summary NEWLINE ( NEWLINE )? (lg= line_goal NEWLINE NEWLINE )? section_details NEWLINE NEWLINE line_version NEWLINE NEWLINE ( section_comments )? section_stat (st= section_trace )? (lc= line_cfs )? + { + pushFollow(FOLLOW_line_input_in_result285); + line_input(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result287); + + pushFollow(FOLLOW_line_summary_in_result291); + ls=line_summary(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result293); + + // Satmc.g:49:50: ( NEWLINE )? + int alt6=2; + int LA6_0 = input.LA(1); + + if ( (LA6_0==NEWLINE) ) { + alt6=1; + } + switch (alt6) { + case 1 : + // Satmc.g:49:50: NEWLINE + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_result295); + + } + break; + + } + + + // Satmc.g:49:59: (lg= line_goal NEWLINE NEWLINE )? + int alt7=2; + int LA7_0 = input.LA(1); + + if ( (LA7_0==GOAL||LA7_0==WS) ) { + alt7=1; + } + switch (alt7) { + case 1 : + // Satmc.g:49:61: lg= line_goal NEWLINE NEWLINE + { + pushFollow(FOLLOW_line_goal_in_result302); + lg=line_goal(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result304); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result306); + + } + break; + + } + + + pushFollow(FOLLOW_section_details_in_result311); + section_details(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result313); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result315); + + pushFollow(FOLLOW_line_version_in_result317); + line_version(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result319); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_result321); + + // Satmc.g:49:154: ( section_comments )? + int alt8=2; + int LA8_0 = input.LA(1); + + if ( (LA8_0==COMMENTS) ) { + alt8=1; + } + switch (alt8) { + case 1 : + // Satmc.g:49:154: section_comments + { + pushFollow(FOLLOW_section_comments_in_result323); + section_comments(); + + state._fsp--; + + + } + break; + + } + + + pushFollow(FOLLOW_section_stat_in_result326); + section_stat(); + + state._fsp--; + + + // Satmc.g:49:187: (st= section_trace )? + int alt9=2; + int LA9_0 = input.LA(1); + + if ( (LA9_0==TRACE) ) { + alt9=1; + } + switch (alt9) { + case 1 : + // Satmc.g:49:187: st= section_trace + { + pushFollow(FOLLOW_section_trace_in_result330); + st=section_trace(); + + state._fsp--; + + + } + break; + + } + + + // Satmc.g:49:205: (lc= line_cfs )? + int alt10=2; + int LA10_0 = input.LA(1); + + if ( (LA10_0==CFS) ) { + alt10=1; + } + switch (alt10) { + case 1 : + // Satmc.g:49:205: lc= line_cfs + { + pushFollow(FOLLOW_line_cfs_in_result335); + lc=line_cfs(); + + state._fsp--; + + + } + break; + + } + + + message = new SatmcMessage(ls, lg, st, lc); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return message; + } + // $ANTLR end "result" + + + + // $ANTLR start "section_warning" + // Satmc.g:53:1: section_warning : WARNING ( (~ NEWLINE )+ NEWLINE )* NEWLINE ; + public final void section_warning() throws RecognitionException { + try { + // Satmc.g:54:5: ( WARNING ( (~ NEWLINE )+ NEWLINE )* NEWLINE ) + // Satmc.g:54:7: WARNING ( (~ NEWLINE )+ NEWLINE )* NEWLINE + { + match(input,WARNING,FOLLOW_WARNING_in_section_warning363); + + // Satmc.g:54:15: ( (~ NEWLINE )+ NEWLINE )* + loop12: + do { + int alt12=2; + int LA12_0 = input.LA(1); + + if ( ((LA12_0 >= CFS && LA12_0 <= INPUT)||(LA12_0 >= NUMBER && LA12_0 <= WS)) ) { + alt12=1; + } + + + switch (alt12) { + case 1 : + // Satmc.g:54:17: (~ NEWLINE )+ NEWLINE + { + // Satmc.g:54:17: (~ NEWLINE )+ + int cnt11=0; + loop11: + do { + int alt11=2; + int LA11_0 = input.LA(1); + + if ( ((LA11_0 >= CFS && LA11_0 <= INPUT)||(LA11_0 >= NUMBER && LA11_0 <= WS)) ) { + alt11=1; + } + + + switch (alt11) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= CFS && input.LA(1) <= INPUT)||(input.LA(1) >= NUMBER && input.LA(1) <= WS) ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + break; + + default : + if ( cnt11 >= 1 ) break loop11; + EarlyExitException eee = + new EarlyExitException(11, input); + throw eee; + } + cnt11++; + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_warning375); + + } + break; + + default : + break loop12; + } + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_warning380); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "section_warning" + + + + // $ANTLR start "section_error" + // Satmc.g:57:1: section_error : ERROR ( (~ NEWLINE )+ NEWLINE )* NEWLINE NEWLINE ( PERCENT ( (~ NEWLINE )+ NEWLINE )* NEWLINE )? ; + public final void section_error() throws RecognitionException { + try { + // Satmc.g:58:5: ( ERROR ( (~ NEWLINE )+ NEWLINE )* NEWLINE NEWLINE ( PERCENT ( (~ NEWLINE )+ NEWLINE )* NEWLINE )? ) + // Satmc.g:58:7: ERROR ( (~ NEWLINE )+ NEWLINE )* NEWLINE NEWLINE ( PERCENT ( (~ NEWLINE )+ NEWLINE )* NEWLINE )? + { + match(input,ERROR,FOLLOW_ERROR_in_section_error401); + + // Satmc.g:58:13: ( (~ NEWLINE )+ NEWLINE )* + loop14: + do { + int alt14=2; + int LA14_0 = input.LA(1); + + if ( ((LA14_0 >= CFS && LA14_0 <= INPUT)||(LA14_0 >= NUMBER && LA14_0 <= WS)) ) { + alt14=1; + } + + + switch (alt14) { + case 1 : + // Satmc.g:58:15: (~ NEWLINE )+ NEWLINE + { + // Satmc.g:58:15: (~ NEWLINE )+ + int cnt13=0; + loop13: + do { + int alt13=2; + int LA13_0 = input.LA(1); + + if ( ((LA13_0 >= CFS && LA13_0 <= INPUT)||(LA13_0 >= NUMBER && LA13_0 <= WS)) ) { + alt13=1; + } + + + switch (alt13) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= CFS && input.LA(1) <= INPUT)||(input.LA(1) >= NUMBER && input.LA(1) <= WS) ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + break; + + default : + if ( cnt13 >= 1 ) break loop13; + EarlyExitException eee = + new EarlyExitException(13, input); + throw eee; + } + cnt13++; + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_error413); + + } + break; + + default : + break loop14; + } + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_error418); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_error420); + + // Satmc.g:58:56: ( PERCENT ( (~ NEWLINE )+ NEWLINE )* NEWLINE )? + int alt17=2; + int LA17_0 = input.LA(1); + + if ( (LA17_0==PERCENT) ) { + alt17=1; + } + switch (alt17) { + case 1 : + // Satmc.g:58:58: PERCENT ( (~ NEWLINE )+ NEWLINE )* NEWLINE + { + match(input,PERCENT,FOLLOW_PERCENT_in_section_error424); + + // Satmc.g:58:66: ( (~ NEWLINE )+ NEWLINE )* + loop16: + do { + int alt16=2; + int LA16_0 = input.LA(1); + + if ( ((LA16_0 >= CFS && LA16_0 <= INPUT)||(LA16_0 >= NUMBER && LA16_0 <= WS)) ) { + alt16=1; + } + + + switch (alt16) { + case 1 : + // Satmc.g:58:68: (~ NEWLINE )+ NEWLINE + { + // Satmc.g:58:68: (~ NEWLINE )+ + int cnt15=0; + loop15: + do { + int alt15=2; + int LA15_0 = input.LA(1); + + if ( ((LA15_0 >= CFS && LA15_0 <= INPUT)||(LA15_0 >= NUMBER && LA15_0 <= WS)) ) { + alt15=1; + } + + + switch (alt15) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= CFS && input.LA(1) <= INPUT)||(input.LA(1) >= NUMBER && input.LA(1) <= WS) ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + break; + + default : + if ( cnt15 >= 1 ) break loop15; + EarlyExitException eee = + new EarlyExitException(15, input); + throw eee; + } + cnt15++; + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_error436); + + } + break; + + default : + break loop16; + } + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_error441); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "section_error" + + + + // $ANTLR start "line_input" + // Satmc.g:61:1: line_input : INPUT WS target ( WS )? ; + public final void line_input() throws RecognitionException { + try { + // Satmc.g:62:5: ( INPUT WS target ( WS )? ) + // Satmc.g:62:7: INPUT WS target ( WS )? + { + match(input,INPUT,FOLLOW_INPUT_in_line_input461); + + match(input,WS,FOLLOW_WS_in_line_input463); + + pushFollow(FOLLOW_target_in_line_input465); + target(); + + state._fsp--; + + + // Satmc.g:62:23: ( WS )? + int alt18=2; + int LA18_0 = input.LA(1); + + if ( (LA18_0==WS) ) { + alt18=1; + } + switch (alt18) { + case 1 : + // Satmc.g:62:23: WS + { + match(input,WS,FOLLOW_WS_in_line_input467); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "line_input" + + + + // $ANTLR start "line_summary" + // Satmc.g:65:1: line_summary returns [Summary res] : SUMMARY WS sr= summary_result ( WS )? ; + public final Summary line_summary() throws RecognitionException { + Summary res = null; + + + SatmcParser.summary_result_return sr =null; + + + try { + // Satmc.g:66:5: ( SUMMARY WS sr= summary_result ( WS )? ) + // Satmc.g:66:7: SUMMARY WS sr= summary_result ( WS )? + { + match(input,SUMMARY,FOLLOW_SUMMARY_in_line_summary493); + + match(input,WS,FOLLOW_WS_in_line_summary495); + + pushFollow(FOLLOW_summary_result_in_line_summary499); + sr=summary_result(); + + state._fsp--; + + + // Satmc.g:66:36: ( WS )? + int alt19=2; + int LA19_0 = input.LA(1); + + if ( (LA19_0==WS) ) { + alt19=1; + } + switch (alt19) { + case 1 : + // Satmc.g:66:36: WS + { + match(input,WS,FOLLOW_WS_in_line_summary501); + + } + break; + + } + + + if ("ATTACK_FOUND".equals((sr!=null?input.toString(sr.start,sr.stop):null))) { + res = Summary.ATTACK_FOUND; + } else if ("NO_ATTACK_FOUND".equals((sr!=null?input.toString(sr.start,sr.stop):null))) { + res = Summary.NO_ATTACK_FOUND; + } else if ("INCONCLUSIVE".equals((sr!=null?input.toString(sr.start,sr.stop):null))) { + res = Summary.INCONCLUSIVE; + } else { + res = Summary.UNKNOWN; + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "line_summary" + + + + // $ANTLR start "line_goal" + // Satmc.g:78:1: line_goal returns [SatmcFunction res] : ( WS )? GOAL WS f= function ( WS )? ; + public final SatmcFunction line_goal() throws RecognitionException { + SatmcFunction res = null; + + + SatmcFunction f =null; + + + try { + // Satmc.g:79:5: ( ( WS )? GOAL WS f= function ( WS )? ) + // Satmc.g:79:7: ( WS )? GOAL WS f= function ( WS )? + { + // Satmc.g:79:7: ( WS )? + int alt20=2; + int LA20_0 = input.LA(1); + + if ( (LA20_0==WS) ) { + alt20=1; + } + switch (alt20) { + case 1 : + // Satmc.g:79:7: WS + { + match(input,WS,FOLLOW_WS_in_line_goal529); + + } + break; + + } + + + match(input,GOAL,FOLLOW_GOAL_in_line_goal532); + + match(input,WS,FOLLOW_WS_in_line_goal534); + + pushFollow(FOLLOW_function_in_line_goal538); + f=function(); + + state._fsp--; + + + res = f; + + // Satmc.g:79:47: ( WS )? + int alt21=2; + int LA21_0 = input.LA(1); + + if ( (LA21_0==WS) ) { + alt21=1; + } + switch (alt21) { + case 1 : + // Satmc.g:79:47: WS + { + match(input,WS,FOLLOW_WS_in_line_goal542); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "line_goal" + + + + // $ANTLR start "section_details" + // Satmc.g:82:1: section_details : line_details ( NEWLINE line_detail )* ; + public final void section_details() throws RecognitionException { + try { + // Satmc.g:83:5: ( line_details ( NEWLINE line_detail )* ) + // Satmc.g:83:7: line_details ( NEWLINE line_detail )* + { + pushFollow(FOLLOW_line_details_in_section_details560); + line_details(); + + state._fsp--; + + + // Satmc.g:83:20: ( NEWLINE line_detail )* + loop22: + do { + int alt22=2; + int LA22_0 = input.LA(1); + + if ( (LA22_0==NEWLINE) ) { + int LA22_1 = input.LA(2); + + if ( (LA22_1==CONSTANT||LA22_1==WS) ) { + alt22=1; + } + + + } + + + switch (alt22) { + case 1 : + // Satmc.g:83:22: NEWLINE line_detail + { + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_details564); + + pushFollow(FOLLOW_line_detail_in_section_details566); + line_detail(); + + state._fsp--; + + + } + break; + + default : + break loop22; + } + } while (true); + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "section_details" + + + + // $ANTLR start "line_details" + // Satmc.g:86:1: line_details : DETAILS ( WS )? ; + public final void line_details() throws RecognitionException { + try { + // Satmc.g:87:5: ( DETAILS ( WS )? ) + // Satmc.g:87:7: DETAILS ( WS )? + { + match(input,DETAILS,FOLLOW_DETAILS_in_line_details586); + + // Satmc.g:87:15: ( WS )? + int alt23=2; + int LA23_0 = input.LA(1); + + if ( (LA23_0==WS) ) { + alt23=1; + } + switch (alt23) { + case 1 : + // Satmc.g:87:15: WS + { + match(input,WS,FOLLOW_WS_in_line_details588); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "line_details" + + + + // $ANTLR start "line_detail" + // Satmc.g:90:1: line_detail : ( WS )? CONSTANT ( WS )? ; + public final void line_detail() throws RecognitionException { + try { + // Satmc.g:91:5: ( ( WS )? CONSTANT ( WS )? ) + // Satmc.g:91:7: ( WS )? CONSTANT ( WS )? + { + // Satmc.g:91:7: ( WS )? + int alt24=2; + int LA24_0 = input.LA(1); + + if ( (LA24_0==WS) ) { + alt24=1; + } + switch (alt24) { + case 1 : + // Satmc.g:91:7: WS + { + match(input,WS,FOLLOW_WS_in_line_detail606); + + } + break; + + } + + + match(input,CONSTANT,FOLLOW_CONSTANT_in_line_detail609); + + // Satmc.g:91:20: ( WS )? + int alt25=2; + int LA25_0 = input.LA(1); + + if ( (LA25_0==WS) ) { + alt25=1; + } + switch (alt25) { + case 1 : + // Satmc.g:91:20: WS + { + match(input,WS,FOLLOW_WS_in_line_detail611); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "line_detail" + + + + // $ANTLR start "line_version" + // Satmc.g:94:1: line_version : VERSION WS VERSION_NR ; + public final void line_version() throws RecognitionException { + try { + // Satmc.g:95:5: ( VERSION WS VERSION_NR ) + // Satmc.g:95:7: VERSION WS VERSION_NR + { + match(input,VERSION,FOLLOW_VERSION_in_line_version629); + + match(input,WS,FOLLOW_WS_in_line_version631); + + match(input,VERSION_NR,FOLLOW_VERSION_NR_in_line_version633); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "line_version" + + + + // $ANTLR start "section_comments" + // Satmc.g:98:1: section_comments : COMMENTS ( WS )? NEWLINE ( (~ NEWLINE )+ NEWLINE )* NEWLINE ; + public final void section_comments() throws RecognitionException { + try { + // Satmc.g:99:5: ( COMMENTS ( WS )? NEWLINE ( (~ NEWLINE )+ NEWLINE )* NEWLINE ) + // Satmc.g:99:7: COMMENTS ( WS )? NEWLINE ( (~ NEWLINE )+ NEWLINE )* NEWLINE + { + match(input,COMMENTS,FOLLOW_COMMENTS_in_section_comments654); + + // Satmc.g:99:16: ( WS )? + int alt26=2; + int LA26_0 = input.LA(1); + + if ( (LA26_0==WS) ) { + alt26=1; + } + switch (alt26) { + case 1 : + // Satmc.g:99:16: WS + { + match(input,WS,FOLLOW_WS_in_section_comments656); + + } + break; + + } + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_comments659); + + // Satmc.g:99:28: ( (~ NEWLINE )+ NEWLINE )* + loop28: + do { + int alt28=2; + int LA28_0 = input.LA(1); + + if ( ((LA28_0 >= CFS && LA28_0 <= INPUT)||(LA28_0 >= NUMBER && LA28_0 <= WS)) ) { + alt28=1; + } + + + switch (alt28) { + case 1 : + // Satmc.g:99:30: (~ NEWLINE )+ NEWLINE + { + // Satmc.g:99:30: (~ NEWLINE )+ + int cnt27=0; + loop27: + do { + int alt27=2; + int LA27_0 = input.LA(1); + + if ( ((LA27_0 >= CFS && LA27_0 <= INPUT)||(LA27_0 >= NUMBER && LA27_0 <= WS)) ) { + alt27=1; + } + + + switch (alt27) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= CFS && input.LA(1) <= INPUT)||(input.LA(1) >= NUMBER && input.LA(1) <= WS) ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + break; + + default : + if ( cnt27 >= 1 ) break loop27; + EarlyExitException eee = + new EarlyExitException(27, input); + throw eee; + } + cnt27++; + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_comments671); + + } + break; + + default : + break loop28; + } + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_comments676); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "section_comments" + + + + // $ANTLR start "section_stat" + // Satmc.g:102:1: section_stat : STAT WS ( (~ NEWLINE )+ NEWLINE )* NEWLINE ; + public final void section_stat() throws RecognitionException { + try { + // Satmc.g:103:5: ( STAT WS ( (~ NEWLINE )+ NEWLINE )* NEWLINE ) + // Satmc.g:103:7: STAT WS ( (~ NEWLINE )+ NEWLINE )* NEWLINE + { + match(input,STAT,FOLLOW_STAT_in_section_stat697); + + match(input,WS,FOLLOW_WS_in_section_stat699); + + // Satmc.g:103:15: ( (~ NEWLINE )+ NEWLINE )* + loop30: + do { + int alt30=2; + int LA30_0 = input.LA(1); + + if ( ((LA30_0 >= CFS && LA30_0 <= INPUT)||(LA30_0 >= NUMBER && LA30_0 <= WS)) ) { + alt30=1; + } + + + switch (alt30) { + case 1 : + // Satmc.g:103:17: (~ NEWLINE )+ NEWLINE + { + // Satmc.g:103:17: (~ NEWLINE )+ + int cnt29=0; + loop29: + do { + int alt29=2; + int LA29_0 = input.LA(1); + + if ( ((LA29_0 >= CFS && LA29_0 <= INPUT)||(LA29_0 >= NUMBER && LA29_0 <= WS)) ) { + alt29=1; + } + + + switch (alt29) { + case 1 : + // Satmc.g: + { + if ( (input.LA(1) >= CFS && input.LA(1) <= INPUT)||(input.LA(1) >= NUMBER && input.LA(1) <= WS) ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + break; + + default : + if ( cnt29 >= 1 ) break loop29; + EarlyExitException eee = + new EarlyExitException(29, input); + throw eee; + } + cnt29++; + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_stat711); + + } + break; + + default : + break loop30; + } + } while (true); + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_stat716); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "section_stat" + + + + // $ANTLR start "section_trace" + // Satmc.g:106:1: section_trace returns [List res] : TRACE NEWLINE ( NUMBER NEWLINE lc= line_clauses NEWLINE (lr= line_rules NEWLINE )? )+ ; + public final List section_trace() throws RecognitionException { + List res = null; + + + List lc =null; + + List lr =null; + + + try { + // Satmc.g:107:5: ( TRACE NEWLINE ( NUMBER NEWLINE lc= line_clauses NEWLINE (lr= line_rules NEWLINE )? )+ ) + // Satmc.g:107:7: TRACE NEWLINE ( NUMBER NEWLINE lc= line_clauses NEWLINE (lr= line_rules NEWLINE )? )+ + { + match(input,TRACE,FOLLOW_TRACE_in_section_trace741); + + res = new ArrayList(); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_trace745); + + // Satmc.g:108:7: ( NUMBER NEWLINE lc= line_clauses NEWLINE (lr= line_rules NEWLINE )? )+ + int cnt32=0; + loop32: + do { + int alt32=2; + int LA32_0 = input.LA(1); + + if ( (LA32_0==NUMBER) ) { + alt32=1; + } + + + switch (alt32) { + case 1 : + // Satmc.g:108:9: NUMBER NEWLINE lc= line_clauses NEWLINE (lr= line_rules NEWLINE )? + { + match(input,NUMBER,FOLLOW_NUMBER_in_section_trace756); + + boolean rulesPresent = false; + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_trace769); + + pushFollow(FOLLOW_line_clauses_in_section_trace773); + lc=line_clauses(); + + state._fsp--; + + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_trace775); + + // Satmc.g:109:41: (lr= line_rules NEWLINE )? + int alt31=2; + int LA31_0 = input.LA(1); + + if ( (LA31_0==RULES||LA31_0==WS) ) { + alt31=1; + } + switch (alt31) { + case 1 : + // Satmc.g:109:43: lr= line_rules NEWLINE + { + pushFollow(FOLLOW_line_rules_in_section_trace781); + lr=line_rules(); + + state._fsp--; + + + rulesPresent=true; + + match(input,NEWLINE,FOLLOW_NEWLINE_in_section_trace794); + + } + break; + + } + + + if (rulesPresent) + res.add(new SatmcTraceStep(lc, lr)); + else + res.add(new SatmcTraceStep(lc, new ArrayList())); + + } + break; + + default : + if ( cnt32 >= 1 ) break loop32; + EarlyExitException eee = + new EarlyExitException(32, input); + throw eee; + } + cnt32++; + } while (true); + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "section_trace" + + + + // $ANTLR start "line_clauses" + // Satmc.g:118:1: line_clauses returns [List res] : ( WS )? CLAUSES fs= function_set ; + public final List line_clauses() throws RecognitionException { + List res = null; + + + List fs =null; + + + try { + // Satmc.g:119:5: ( ( WS )? CLAUSES fs= function_set ) + // Satmc.g:119:7: ( WS )? CLAUSES fs= function_set + { + // Satmc.g:119:7: ( WS )? + int alt33=2; + int LA33_0 = input.LA(1); + + if ( (LA33_0==WS) ) { + alt33=1; + } + switch (alt33) { + case 1 : + // Satmc.g:119:7: WS + { + match(input,WS,FOLLOW_WS_in_line_clauses841); + + } + break; + + } + + + match(input,CLAUSES,FOLLOW_CLAUSES_in_line_clauses844); + + pushFollow(FOLLOW_function_set_in_line_clauses848); + fs=function_set(); + + state._fsp--; + + + res = fs; + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "line_clauses" + + + + // $ANTLR start "line_rules" + // Satmc.g:122:1: line_rules returns [List res] : ( WS )? RULES WS (f= function |fs= function_set |fn= fname ) ; + public final List line_rules() throws RecognitionException { + List res = null; + + + SatmcFunction f =null; + + List fs =null; + + SatmcParser.fname_return fn =null; + + + try { + // Satmc.g:123:5: ( ( WS )? RULES WS (f= function |fs= function_set |fn= fname ) ) + // Satmc.g:123:7: ( WS )? RULES WS (f= function |fs= function_set |fn= fname ) + { + // Satmc.g:123:7: ( WS )? + int alt34=2; + int LA34_0 = input.LA(1); + + if ( (LA34_0==WS) ) { + alt34=1; + } + switch (alt34) { + case 1 : + // Satmc.g:123:7: WS + { + match(input,WS,FOLLOW_WS_in_line_rules875); + + } + break; + + } + + + match(input,RULES,FOLLOW_RULES_in_line_rules878); + + match(input,WS,FOLLOW_WS_in_line_rules880); + + // Satmc.g:123:20: (f= function |fs= function_set |fn= fname ) + int alt35=3; + int LA35_0 = input.LA(1); + + if ( (LA35_0==FTEXT) ) { + int LA35_1 = input.LA(2); + + if ( (LA35_1==O_PARENTHESIS) ) { + alt35=1; + } + else if ( (LA35_1==NEWLINE) ) { + alt35=3; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 35, 1, input); + + throw nvae; + + } + } + else if ( (LA35_0==O_BRACES) ) { + alt35=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 35, 0, input); + + throw nvae; + + } + switch (alt35) { + case 1 : + // Satmc.g:123:22: f= function + { + pushFollow(FOLLOW_function_in_line_rules886); + f=function(); + + state._fsp--; + + + res = new ArrayList(); res.add(f); + + } + break; + case 2 : + // Satmc.g:124:14: fs= function_set + { + pushFollow(FOLLOW_function_set_in_line_rules905); + fs=function_set(); + + state._fsp--; + + + res = fs; + + } + break; + case 3 : + // Satmc.g:125:14: fn= fname + { + pushFollow(FOLLOW_fname_in_line_rules924); + fn=fname(); + + state._fsp--; + + + res = new ArrayList(); + res.add(new SatmcFunction((fn!=null?input.toString(fn.start,fn.stop):null), new ArrayList())); + + } + break; + + } + + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "line_rules" + + + + // $ANTLR start "line_cfs" + // Satmc.g:129:1: line_cfs returns [List res] : CFS NEWLINE fs= function_set ; + public final List line_cfs() throws RecognitionException { + List res = null; + + + List fs =null; + + + try { + // Satmc.g:130:5: ( CFS NEWLINE fs= function_set ) + // Satmc.g:130:7: CFS NEWLINE fs= function_set + { + match(input,CFS,FOLLOW_CFS_in_line_cfs952); + + match(input,NEWLINE,FOLLOW_NEWLINE_in_line_cfs954); + + pushFollow(FOLLOW_function_set_in_line_cfs958); + fs=function_set(); + + state._fsp--; + + + res = fs; + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "line_cfs" + + + + // $ANTLR start "target" + // Satmc.g:133:1: target : FILE ; + public final void target() throws RecognitionException { + try { + // Satmc.g:134:5: ( FILE ) + // Satmc.g:134:7: FILE + { + match(input,FILE,FOLLOW_FILE_in_target977); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return ; + } + // $ANTLR end "target" + + + public static class summary_result_return extends ParserRuleReturnScope { + }; + + + // $ANTLR start "summary_result" + // Satmc.g:137:1: summary_result : CONSTANT ; + public final SatmcParser.summary_result_return summary_result() throws RecognitionException { + SatmcParser.summary_result_return retval = new SatmcParser.summary_result_return(); + retval.start = input.LT(1); + + + try { + // Satmc.g:138:5: ( CONSTANT ) + // Satmc.g:138:7: CONSTANT + { + match(input,CONSTANT,FOLLOW_CONSTANT_in_summary_result994); + + } + + retval.stop = input.LT(-1); + + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return retval; + } + // $ANTLR end "summary_result" + + + + // $ANTLR start "function_set" + // Satmc.g:141:1: function_set returns [List res] : O_BRACES WS (f1= function ( COMMA fn= function )* )? ( WS )? C_BRACES ; + public final List function_set() throws RecognitionException { + List res = null; + + + SatmcFunction f1 =null; + + SatmcFunction fn =null; + + + try { + // Satmc.g:142:5: ( O_BRACES WS (f1= function ( COMMA fn= function )* )? ( WS )? C_BRACES ) + // Satmc.g:142:7: O_BRACES WS (f1= function ( COMMA fn= function )* )? ( WS )? C_BRACES + { + match(input,O_BRACES,FOLLOW_O_BRACES_in_function_set1019); + + match(input,WS,FOLLOW_WS_in_function_set1021); + + res = new ArrayList(); + + + // Satmc.g:144:11: (f1= function ( COMMA fn= function )* )? + int alt37=2; + int LA37_0 = input.LA(1); + + if ( (LA37_0==FTEXT) ) { + alt37=1; + } + switch (alt37) { + case 1 : + // Satmc.g:144:13: f1= function ( COMMA fn= function )* + { + pushFollow(FOLLOW_function_in_function_set1040); + f1=function(); + + state._fsp--; + + + res.add(f1); + + + // Satmc.g:146:20: ( COMMA fn= function )* + loop36: + do { + int alt36=2; + int LA36_0 = input.LA(1); + + if ( (LA36_0==COMMA) ) { + alt36=1; + } + + + switch (alt36) { + case 1 : + // Satmc.g:146:22: COMMA fn= function + { + match(input,COMMA,FOLLOW_COMMA_in_function_set1065); + + pushFollow(FOLLOW_function_in_function_set1069); + fn=function(); + + state._fsp--; + + + res.add(fn); + + } + break; + + default : + break loop36; + } + } while (true); + + + } + break; + + } + + + // Satmc.g:146:69: ( WS )? + int alt38=2; + int LA38_0 = input.LA(1); + + if ( (LA38_0==WS) ) { + alt38=1; + } + switch (alt38) { + case 1 : + // Satmc.g:146:69: WS + { + match(input,WS,FOLLOW_WS_in_function_set1079); + + } + break; + + } + + + match(input,C_BRACES,FOLLOW_C_BRACES_in_function_set1082); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "function_set" + + + + // $ANTLR start "function" + // Satmc.g:149:1: function returns [SatmcFunction res] : fn= fname O_PARENTHESIS fv= fvar ( COMMA fvl= fvar )* C_PARENTHESIS ; + public final SatmcFunction function() throws RecognitionException { + SatmcFunction res = null; + + + SatmcParser.fname_return fn =null; + + SatmcFact fv =null; + + SatmcFact fvl =null; + + + try { + // Satmc.g:150:5: (fn= fname O_PARENTHESIS fv= fvar ( COMMA fvl= fvar )* C_PARENTHESIS ) + // Satmc.g:150:7: fn= fname O_PARENTHESIS fv= fvar ( COMMA fvl= fvar )* C_PARENTHESIS + { + pushFollow(FOLLOW_fname_in_function1109); + fn=fname(); + + state._fsp--; + + + res = new SatmcFunction((fn!=null?input.toString(fn.start,fn.stop):null), new ArrayList()); + + + match(input,O_PARENTHESIS,FOLLOW_O_PARENTHESIS_in_function1120); + + pushFollow(FOLLOW_fvar_in_function1125); + fv=fvar(); + + state._fsp--; + + + res.args.add(fv); + + + // Satmc.g:154:11: ( COMMA fvl= fvar )* + loop39: + do { + int alt39=2; + int LA39_0 = input.LA(1); + + if ( (LA39_0==COMMA) ) { + alt39=1; + } + + + switch (alt39) { + case 1 : + // Satmc.g:154:13: COMMA fvl= fvar + { + match(input,COMMA,FOLLOW_COMMA_in_function1141); + + pushFollow(FOLLOW_fvar_in_function1145); + fvl=fvar(); + + state._fsp--; + + + res.args.add(fvl); + + + } + break; + + default : + break loop39; + } + } while (true); + + + match(input,C_PARENTHESIS,FOLLOW_C_PARENTHESIS_in_function1167); + + } + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "function" + + + public static class var_return extends ParserRuleReturnScope { + }; + + + // $ANTLR start "var" + // Satmc.g:159:1: var : ( FTEXT | NUMBER ); + public final SatmcParser.var_return var() throws RecognitionException { + SatmcParser.var_return retval = new SatmcParser.var_return(); + retval.start = input.LT(1); + + + try { + // Satmc.g:160:5: ( FTEXT | NUMBER ) + // Satmc.g: + { + if ( input.LA(1)==FTEXT||input.LA(1)==NUMBER ) { + input.consume(); + state.errorRecovery=false; + } + else { + MismatchedSetException mse = new MismatchedSetException(null,input); + throw mse; + } + + + } + + retval.stop = input.LT(-1); + + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return retval; + } + // $ANTLR end "var" + + + public static class fname_return extends ParserRuleReturnScope { + }; + + + // $ANTLR start "fname" + // Satmc.g:164:1: fname : FTEXT ; + public final SatmcParser.fname_return fname() throws RecognitionException { + SatmcParser.fname_return retval = new SatmcParser.fname_return(); + retval.start = input.LT(1); + + + try { + // Satmc.g:165:5: ( FTEXT ) + // Satmc.g:165:7: FTEXT + { + match(input,FTEXT,FOLLOW_FTEXT_in_fname1217); + + } + + retval.stop = input.LT(-1); + + + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return retval; + } + // $ANTLR end "fname" + + + + // $ANTLR start "fvar" + // Satmc.g:168:1: fvar returns [SatmcFact res] : (r1= var |r2= function ); + public final SatmcFact fvar() throws RecognitionException { + SatmcFact res = null; + + + SatmcParser.var_return r1 =null; + + SatmcFunction r2 =null; + + + try { + // Satmc.g:169:5: (r1= var |r2= function ) + int alt40=2; + int LA40_0 = input.LA(1); + + if ( (LA40_0==FTEXT) ) { + int LA40_1 = input.LA(2); + + if ( (LA40_1==COMMA||LA40_1==C_PARENTHESIS) ) { + alt40=1; + } + else if ( (LA40_1==O_PARENTHESIS) ) { + alt40=2; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 40, 1, input); + + throw nvae; + + } + } + else if ( (LA40_0==NUMBER) ) { + alt40=1; + } + else { + NoViableAltException nvae = + new NoViableAltException("", 40, 0, input); + + throw nvae; + + } + switch (alt40) { + case 1 : + // Satmc.g:169:7: r1= var + { + pushFollow(FOLLOW_var_in_fvar1244); + r1=var(); + + state._fsp--; + + + res = new SatmcVar((r1!=null?input.toString(r1.start,r1.stop):null)); + + } + break; + case 2 : + // Satmc.g:170:7: r2= function + { + pushFollow(FOLLOW_function_in_fvar1256); + r2=function(); + + state._fsp--; + + + res = r2; + + } + break; + + } + } + catch (RecognitionException re) { + reportError(re); + recover(input,re); + } + + finally { + // do for sure before leaving + } + return res; + } + // $ANTLR end "fvar" + + // Delegated rules + + + + + public static final BitSet FOLLOW_NEWLINE_in_output168 = new BitSet(new long[]{0x0000000000060000L}); + public static final BitSet FOLLOW_NEWLINE_in_output173 = new BitSet(new long[]{0x0000000040000000L}); + public static final BitSet FOLLOW_section_warning_in_output175 = new BitSet(new long[]{0x0000000000060000L}); + public static final BitSet FOLLOW_error_in_output182 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_result_in_output206 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_output228 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_EOF_in_output231 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_NEWLINE_in_error258 = new BitSet(new long[]{0x0000000000002000L}); + public static final BitSet FOLLOW_section_error_in_error260 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_line_input_in_result285 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result287 = new BitSet(new long[]{0x0000000004000000L}); + public static final BitSet FOLLOW_line_summary_in_result291 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result293 = new BitSet(new long[]{0x0000000080051000L}); + public static final BitSet FOLLOW_NEWLINE_in_result295 = new BitSet(new long[]{0x0000000080011000L}); + public static final BitSet FOLLOW_line_goal_in_result302 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result304 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result306 = new BitSet(new long[]{0x0000000000001000L}); + public static final BitSet FOLLOW_section_details_in_result311 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result313 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result315 = new BitSet(new long[]{0x0000000010000000L}); + public static final BitSet FOLLOW_line_version_in_result317 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result319 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_result321 = new BitSet(new long[]{0x0000000002000080L}); + public static final BitSet FOLLOW_section_comments_in_result323 = new BitSet(new long[]{0x0000000002000000L}); + public static final BitSet FOLLOW_section_stat_in_result326 = new BitSet(new long[]{0x0000000008000012L}); + public static final BitSet FOLLOW_section_trace_in_result330 = new BitSet(new long[]{0x0000000000000012L}); + public static final BitSet FOLLOW_line_cfs_in_result335 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_WARNING_in_section_warning363 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_warning375 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_warning380 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_ERROR_in_section_error401 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_error413 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_error418 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_error420 = new BitSet(new long[]{0x0000000000800002L}); + public static final BitSet FOLLOW_PERCENT_in_section_error424 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_error436 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_error441 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_INPUT_in_line_input461 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_line_input463 = new BitSet(new long[]{0x0000000000004000L}); + public static final BitSet FOLLOW_target_in_line_input465 = new BitSet(new long[]{0x0000000080000002L}); + public static final BitSet FOLLOW_WS_in_line_input467 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_SUMMARY_in_line_summary493 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_line_summary495 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_summary_result_in_line_summary499 = new BitSet(new long[]{0x0000000080000002L}); + public static final BitSet FOLLOW_WS_in_line_summary501 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_WS_in_line_goal529 = new BitSet(new long[]{0x0000000000010000L}); + public static final BitSet FOLLOW_GOAL_in_line_goal532 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_line_goal534 = new BitSet(new long[]{0x0000000000008000L}); + public static final BitSet FOLLOW_function_in_line_goal538 = new BitSet(new long[]{0x0000000080000002L}); + public static final BitSet FOLLOW_WS_in_line_goal542 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_line_details_in_section_details560 = new BitSet(new long[]{0x0000000000040002L}); + public static final BitSet FOLLOW_NEWLINE_in_section_details564 = new BitSet(new long[]{0x0000000080000100L}); + public static final BitSet FOLLOW_line_detail_in_section_details566 = new BitSet(new long[]{0x0000000000040002L}); + public static final BitSet FOLLOW_DETAILS_in_line_details586 = new BitSet(new long[]{0x0000000080000002L}); + public static final BitSet FOLLOW_WS_in_line_details588 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_WS_in_line_detail606 = new BitSet(new long[]{0x0000000000000100L}); + public static final BitSet FOLLOW_CONSTANT_in_line_detail609 = new BitSet(new long[]{0x0000000080000002L}); + public static final BitSet FOLLOW_WS_in_line_detail611 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_VERSION_in_line_version629 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_line_version631 = new BitSet(new long[]{0x0000000020000000L}); + public static final BitSet FOLLOW_VERSION_NR_in_line_version633 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_COMMENTS_in_section_comments654 = new BitSet(new long[]{0x0000000080040000L}); + public static final BitSet FOLLOW_WS_in_section_comments656 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_comments659 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_comments671 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_comments676 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_STAT_in_section_stat697 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_section_stat699 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_stat711 = new BitSet(new long[]{0x00000000FFFFFFF0L}); + public static final BitSet FOLLOW_NEWLINE_in_section_stat716 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_TRACE_in_section_trace741 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_trace745 = new BitSet(new long[]{0x0000000000080000L}); + public static final BitSet FOLLOW_NUMBER_in_section_trace756 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_trace769 = new BitSet(new long[]{0x0000000080000020L}); + public static final BitSet FOLLOW_line_clauses_in_section_trace773 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_trace775 = new BitSet(new long[]{0x0000000081080002L}); + public static final BitSet FOLLOW_line_rules_in_section_trace781 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_section_trace794 = new BitSet(new long[]{0x0000000000080002L}); + public static final BitSet FOLLOW_WS_in_line_clauses841 = new BitSet(new long[]{0x0000000000000020L}); + public static final BitSet FOLLOW_CLAUSES_in_line_clauses844 = new BitSet(new long[]{0x0000000000100000L}); + public static final BitSet FOLLOW_function_set_in_line_clauses848 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_WS_in_line_rules875 = new BitSet(new long[]{0x0000000001000000L}); + public static final BitSet FOLLOW_RULES_in_line_rules878 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_line_rules880 = new BitSet(new long[]{0x0000000000108000L}); + public static final BitSet FOLLOW_function_in_line_rules886 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_function_set_in_line_rules905 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_fname_in_line_rules924 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_CFS_in_line_cfs952 = new BitSet(new long[]{0x0000000000040000L}); + public static final BitSet FOLLOW_NEWLINE_in_line_cfs954 = new BitSet(new long[]{0x0000000000100000L}); + public static final BitSet FOLLOW_function_set_in_line_cfs958 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_FILE_in_target977 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_CONSTANT_in_summary_result994 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_O_BRACES_in_function_set1019 = new BitSet(new long[]{0x0000000080000000L}); + public static final BitSet FOLLOW_WS_in_function_set1021 = new BitSet(new long[]{0x0000000080008200L}); + public static final BitSet FOLLOW_function_in_function_set1040 = new BitSet(new long[]{0x0000000080000240L}); + public static final BitSet FOLLOW_COMMA_in_function_set1065 = new BitSet(new long[]{0x0000000000008000L}); + public static final BitSet FOLLOW_function_in_function_set1069 = new BitSet(new long[]{0x0000000080000240L}); + public static final BitSet FOLLOW_WS_in_function_set1079 = new BitSet(new long[]{0x0000000000000200L}); + public static final BitSet FOLLOW_C_BRACES_in_function_set1082 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_fname_in_function1109 = new BitSet(new long[]{0x0000000000400000L}); + public static final BitSet FOLLOW_O_PARENTHESIS_in_function1120 = new BitSet(new long[]{0x0000000000088000L}); + public static final BitSet FOLLOW_fvar_in_function1125 = new BitSet(new long[]{0x0000000000000840L}); + public static final BitSet FOLLOW_COMMA_in_function1141 = new BitSet(new long[]{0x0000000000088000L}); + public static final BitSet FOLLOW_fvar_in_function1145 = new BitSet(new long[]{0x0000000000000840L}); + public static final BitSet FOLLOW_C_PARENTHESIS_in_function1167 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_FTEXT_in_fname1217 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_var_in_fvar1244 = new BitSet(new long[]{0x0000000000000002L}); + public static final BitSet FOLLOW_function_in_fvar1256 = new BitSet(new long[]{0x0000000000000002L}); + +} diff --git a/src/examples/money-tasks/pom.xml b/src/examples/money-tasks/pom.xml new file mode 100644 index 0000000..8aefa09 --- /dev/null +++ b/src/examples/money-tasks/pom.xml @@ -0,0 +1,56 @@ + + 4.0.0 + + org.acme + money-tasks + 1.0.0-SNAPSHOT + jar + Acme Corporation Money Tasks + + + 5.7 + + + + + org.activiti + activiti-designer-integration + ${activiti.designer.version} + compile + + + + + + + maven-compiler-plugin + + 1.5 + 1.5 + true + true + true + + + + org.apache.maven.plugins + maven-jar-plugin + 2.3.1 + + + true + + false + true + + + Acme Money + + + + + + + + \ No newline at end of file diff --git a/src/examples/money-tasks/src/main/java/org/acme/palette/AcmeMoneyCustomizer.java b/src/examples/money-tasks/src/main/java/org/acme/palette/AcmeMoneyCustomizer.java new file mode 100644 index 0000000..82be616 --- /dev/null +++ b/src/examples/money-tasks/src/main/java/org/acme/palette/AcmeMoneyCustomizer.java @@ -0,0 +1,25 @@ +package org.acme.palette; + +import java.util.ArrayList; +import java.util.List; + +import org.activiti.designer.integration.palette.AbstractDefaultPaletteCustomizer; +import org.activiti.designer.integration.palette.PaletteEntry; + +/** + * Customizes the palette for the Money Tasks. + * + * @author John Doe + * @since 1.0.0 + * @version 1 + */ +public class AcmeMoneyCustomizer extends AbstractDefaultPaletteCustomizer { + + public List disablePaletteEntries() { + List result = new ArrayList(); + //Disable the mail task + result.add(PaletteEntry.MAIL_TASK); + return result; + } + +} diff --git a/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AccountManager.java b/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AccountManager.java new file mode 100644 index 0000000..f7b1c91 --- /dev/null +++ b/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AccountManager.java @@ -0,0 +1,28 @@ +package org.acme.servicetasks; + +import org.activiti.designer.integration.servicetask.PropertyType; +import org.activiti.designer.integration.servicetask.annotation.Help; +import org.activiti.designer.integration.servicetask.annotation.Property; + +/** + * Defines fields for a data grid managing AccountManagers. + * + * @author John Doe + * @since 1.0.0 + * @version 1 + */ +public class AccountManager { + + @Property(type = PropertyType.TEXT, displayName = "First name", required = true) + @Help(displayHelpShort = "First name", displayHelpLong = "The person's first name") + private String firstName; + + @Property(type = PropertyType.TEXT, displayName = "Last name", required = true) + @Help(displayHelpShort = "Last name", displayHelpLong = "The person's last name") + private String lastName; + + @Property(type = PropertyType.PERIOD, displayName = "Authorization period", required = true, defaultValue = "0y 2mo 0w 0d 0h 0m 0s") + @Help(displayHelpShort = "Authorization period", displayHelpLong = "The person's authorization period") + private String authorizationPeriod; + +} diff --git a/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AcmeMoneyTask.java b/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AcmeMoneyTask.java new file mode 100644 index 0000000..3ea7a39 --- /dev/null +++ b/src/examples/money-tasks/src/main/java/org/acme/servicetasks/AcmeMoneyTask.java @@ -0,0 +1,122 @@ +/** + * + */ +package org.acme.servicetasks; + +import java.util.List; + +import org.activiti.designer.integration.servicetask.AbstractCustomServiceTask; +import org.activiti.designer.integration.servicetask.PropertyType; +import org.activiti.designer.integration.servicetask.annotation.DataGridProperty; +import org.activiti.designer.integration.servicetask.annotation.DatePickerProperty; +import org.activiti.designer.integration.servicetask.annotation.Help; +import org.activiti.designer.integration.servicetask.annotation.Property; +import org.activiti.designer.integration.servicetask.annotation.PropertyItems; +import org.activiti.designer.integration.servicetask.annotation.Runtime; + +/** + * Defines the Money Task node. + * + * @author John Doe + * @version 1 + * @since 1.0.0 + */ +@Runtime(delegationClass = "org.acme.runtime.AcmeMoneyJavaDelegation") +@Help(displayHelpShort = "Creates a new account", displayHelpLong = "Creates a new account using the account number specified") +public class AcmeMoneyTask extends AbstractCustomServiceTask { + + private static final String HELP_ACCOUNT_NUMBER_LONG = "Provide a number that is suitable as an account number."; + + private static final String ACCOUNT_TYPE_SAVINGS_LABEL = "Savings account"; + private static final String ACCOUNT_TYPE_SAVINGS_VALUE = "savings"; + + private static final String ACCOUNT_TYPE_JUNIOR_LABEL = "Piggy Bank Account"; + private static final String ACCOUNT_TYPE_JUNIOR_VALUE = "junior"; + + private static final String ACCOUNT_TYPE_JOINT_LABEL = "Joint account"; + private static final String ACCOUNT_TYPE_JOINT_VALUE = "joint"; + + private static final String ACCOUNT_TYPE_TRANSACTIONAL_LABEL = "Transactional account"; + private static final String ACCOUNT_TYPE_TRANSACTIONAL_VALUE = "transactional"; + + private static final String ACCOUNT_TYPE_STUDENT_LABEL = "Student account"; + private static final String ACCOUNT_TYPE_STUDENT_VALUE = "student"; + + private static final String ACCOUNT_TYPE_SENIOR_LABEL = "Senior Citizen Account"; + private static final String ACCOUNT_TYPE_SENIOR_VALUE = "senior"; + + private static final String LIMIT_LOW_LABEL = "Low (250)"; + private static final String LIMIT_LOW_VALUE = "250"; + private static final String LIMIT_MEDIUM_LABEL = "Medium (1000)"; + private static final String LIMIT_MEDIUM_VALUE = "1000"; + private static final String LIMIT_HIGH_LABEL = "High (2500)"; + private static final String LIMIT_HIGH_VALUE = "2500"; + + @Property(type = PropertyType.TEXT, displayName = "Account Number", required = true, defaultValue = "1234567890") + @Help(displayHelpShort = "Provide an account number", displayHelpLong = HELP_ACCOUNT_NUMBER_LONG) + private String accountNumber; + + @Property(type = PropertyType.MULTILINE_TEXT, displayName = "Comments", required = true) + @Help(displayHelpShort = "Provide comments", displayHelpLong = "You can add comments to the node to provide a brief description.") + private String comments; + + @Property(type = PropertyType.PERIOD, displayName = "Processing Time", required = true, defaultValue = "0y 0mo 2w 0d 0h 0m 0s") + @Help(displayHelpShort = "The maximum allowed time for processing", displayHelpLong = "Processing must take no longer than the period you specify here.") + private String maximumProcessingTime; + + @Property(type = PropertyType.DATA_GRID, displayName = "Account managers") + @DataGridProperty(itemClass = AccountManager.class, orderable = true) + @Help(displayHelpShort = "People authorized for this account", displayHelpLong = "Specify the details of people allowed to manage this account.") + private List accountManagers; + + @Property(type = PropertyType.BOOLEAN_CHOICE, displayName = "VIP Customer", defaultValue = "false") + @Help(displayHelpShort = "Is the customer a VIP?", displayHelpLong = "VIP customers enjoy special privileges. Check this field to indicate the customer is a VIP.") + private String vipCustomer; + + @Property(type = PropertyType.COMBOBOX_CHOICE, displayName = "Account type", required = true, defaultValue = ACCOUNT_TYPE_STUDENT_VALUE) + @Help(displayHelpShort = "The type of account", displayHelpLong = "Choose a type of account from the list of options") + @PropertyItems({ ACCOUNT_TYPE_SAVINGS_LABEL, ACCOUNT_TYPE_SAVINGS_VALUE, ACCOUNT_TYPE_JUNIOR_LABEL, ACCOUNT_TYPE_JUNIOR_VALUE, ACCOUNT_TYPE_JOINT_LABEL, + ACCOUNT_TYPE_JOINT_VALUE, ACCOUNT_TYPE_TRANSACTIONAL_LABEL, ACCOUNT_TYPE_TRANSACTIONAL_VALUE, ACCOUNT_TYPE_STUDENT_LABEL, ACCOUNT_TYPE_STUDENT_VALUE, + ACCOUNT_TYPE_SENIOR_LABEL, ACCOUNT_TYPE_SENIOR_VALUE }) + private String accountType; + + @Property(type = PropertyType.RADIO_CHOICE, displayName = "Withdrawl limit", required = true) + @Help(displayHelpShort = "The maximum daily withdrawl amount ", displayHelpLong = "Choose the maximum daily amount that can be withdrawn from the account.") + @PropertyItems({ LIMIT_LOW_LABEL, LIMIT_LOW_VALUE, LIMIT_MEDIUM_LABEL, LIMIT_MEDIUM_VALUE, LIMIT_HIGH_LABEL, LIMIT_HIGH_VALUE }) + private String withdrawlLimit; + + @Property(type = PropertyType.DATE_PICKER, displayName = "Expiry date", required = true) + @Help(displayHelpShort = "The date the account expires ", displayHelpLong = "Choose the date when the account will expire if no extended before the date.") + @DatePickerProperty() + private String expiryDate; + + /* + * (non-Javadoc) + * + * @see + * org.activiti.designer.integration.servicetask.AbstractCustomServiceTask + * #contributeToPaletteDrawer() + */ + @Override + public String contributeToPaletteDrawer() { + return "Acme Corporation"; + } + + @Override + public String getName() { + return "Money node"; + } + + /* + * (non-Javadoc) + * + * @see + * org.activiti.designer.integration.servicetask.AbstractCustomServiceTask + * #getSmallIconPath() + */ + @Override + public String getSmallIconPath() { + return "icons/coins.png"; + } + +} diff --git a/src/examples/money-tasks/src/main/resources/icons/coins.png b/src/examples/money-tasks/src/main/resources/icons/coins.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca9074d66e7a008dbdd265a48ff37f454941be9 GIT binary patch literal 732 zcmV<20wev2P)7$(F5I~EPw2+A2=20Sy*#|n7r8sf)7*RgqMLv3&KWmL+^F4r z7i0Z}>kq&FSJ~Z9+<5!dQFwCOz1ndvw%m_4J#=sT@Q1U19`B}1iL1?~3va{ZF~|VI zfHw0WI@T{zdi2I_>3m@YYk3d;l(JU>d+bPFLOo8G;T$3)1!qp*$dock%HEEk|V0 z3L2&;r~p>tQh+yD{T!MxBF4;%7xC6JH1CtlE}+w%Xkuu&haUcdHC?=ZKr(+GZJfIQ zJ6@GU%>XYSae67{=&NN{rB<>+N;FbBA#_{A0WZW7cXJ0E=}(_?dx9< zr?bEW55s(NboZ^^cb|S1s~AxnBh?-gQ{Ob@*3}OO`vCi&FRqICO$~lSg*6r5QDf7DTmJy^bFNy&p3d3; O00004Tx0C)k_d1qJ@&9iUM<^`6p3Ob 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 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/dialogs/layout_organic.gif b/src/org.activiti.designer.eclipse/icons/dialogs/layout_organic.gif new file mode 100644 index 0000000000000000000000000000000000000000..9072219271f7bbbfe0c03fc4ef9a45f652a1d026 GIT binary patch literal 159 zcmZ?wbhEHb6krfwFlJy-{K>+|z`(_z!vF*zv1TBh-!tdp{W&+^{k*d8-v1Bt`p$k> z+P3-sYla<{vO&sF0gF#Sqvh1S5z}~`&N(zH%ynUmu$b2HVA{2lT%JtPj`O^?ysZ_# wsb3NFqHJa3CpH!y9=0&UA3aqJEpL1^6lM6%Jif{;XXc-_K;lH03j>2S01R|C_5c6? literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/general/arrow_down.gif b/src/org.activiti.designer.eclipse/icons/general/arrow_down.gif new file mode 100644 index 0000000000000000000000000000000000000000..08789854a552a12a59327afae4cd0ccf353d33f4 GIT binary patch literal 89 zcmZ?wbhEHb6krfw5M*Fb{K>+|z`)F)!vF*zu|^>M|NsBUnkhgAlh&O6l?T^IHt;-} pYq45Z;=)k;Nh{hImJlRh0x9gFEfFe4dx;n|;;jd@5QwqX*h^`fl%IlP4pGv2 zshVO{ss%-g2nH0%u|f}9RLmiV;>8{+X+Y4+wkB5Mo865T2Zld?|IB;y=f6FD=2Ylt z!bwirBDQ9;IdH9jV2CDYga)aHk~BFTuRM$D_ zJ)hUy^zpVPGIp7ma}N6qe7y`VNv4ZWJk$?t|I4bl3IyAdCN4ZPVn*Bt-vfX6DV+`? zcQq-~i$|Jx4Og%akcFJU>OyZpI2-e-_{O}eCNJ}q;cVQ;F06{aBPz{%%t*p2(>CtA zWR+o z4c@dlx3pQi^R4{ftAF3Bo8w7-yRgpX3O^gioB!^jObg-|YYlY`m z!TfB{Td%3PjHx-+Nd<4sIS%+&j&*KE_-B#N5t@bW-Zb3w0P7uSiZ#nxd~BYj$`PH< zU$>zfD|K->{}W-yS+YC4(c(f_l1PcE!R)&nc@OmFgW2pZ?tA+ah07)b+mjD0& literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/general/arrow_right.gif b/src/org.activiti.designer.eclipse/icons/general/arrow_right.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e458ccb4e75680c749d452941cfc46733346322 GIT binary patch literal 95 zcmZ?wbhEHb6krfw5M*Fb{K>+|z`)F)!vF*zu|^>M|NsBUnkhgAlfj(+m8T^x1~C}S v^1OPR|3_8AJ&UGhk4Xx%f}Bp2-tXqv*2`+5?6d3YZ^qndi!KH*FjxZsu!J8- literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/general/arrow_up.gif b/src/org.activiti.designer.eclipse/icons/general/arrow_up.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b3c2337f8b96c1e5978ea8d2c538cb1a9f6c8b7 GIT binary patch literal 94 zcmZ?wbhEHb6krfw5M*Fb{K>+|z`)F)!vF*zu|^>M|NsBUnkhgAlm49km14UYXITpz uv0Sw`zq&JH9;?y8opYC8n0V;4R+NBs@m;qabKZ6CI>eKpuegkX!5RRJN*?q8 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.128x128.png b/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..44f1cb74adb5b9dc1a9e3d7988ef9d99ac6268c6 GIT binary patch literal 49478 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 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.32x32.png b/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..b91cbe53bcb2b2fdf8cabadfe19a825507ce1b78 GIT binary patch literal 3225 zcma)8d2Ccg7@zm{?Y_N>w6(l#7YKnxnuXgI`JG$0@pl|v9r zOu!Hf_!s_#HuVZnf&{`L5RtPSwLrBTyW4xa_j~i+_|4Atb=huPCvWG?oB6)q_xpYG z&184Xol|Zzk1!*IY?T#d^WdFLe?}g9?CAI&UfimA<)x_Z(nt?{m_DpnveDWz!c_*tl$KvyUT$fYp!<%s7tI%rvj~No_TL zAjE$RG-l{$8{77uzW;<-*tu|mjt6Ag5(4)}pxGF_F^Fxy-QHOLFg+uUm{W>(oOgL6 z;Kg*Xejtz`QpC_V)ZS>91(QLqsswR}=eaI#VEbIBBSjoi$6yK=dQI((Mp}Qxzt*TE)(kvxc(2L&S3h2y&j#o(Z zLE#XNgcY5Nbf5;S!>y(Td;VfN7&HZ zW>El7I3|ckJ%LEg?6G5?v@l23Yhe=0lr7iPUVr2l>_*@nqvY=PFD-GDn7e@d( zQ%w&SLJOy4jY$>Ktq9PU)V^c3Ta9+p%3oG=_}jsZ@rbd}KEM;WxB9qf-Vx2aj&JP= zd|u`3*P+mv@=%7J5ElLwGLe^{*{lAFqQd0Bef=LqkgkF$g?XRfSLi z9gXq>jloIYZ$ffiprBRlz2kx%%hjnhr4IR8@t3^G`SbX~!n0 zcS?nF_jrR_7L4o9U5fz&$_#NwZyq|XL{_iMD+INp&()wBrK_APTS5`pN2mi zvAKS)!~kFruj6mGzhduYQPitiAw(hIjtk1l&Pp|< F{2!ZrzJ~w+ literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.48x48.png b/src/org.activiti.designer.eclipse/icons/logo/activiti.logo.gradients.48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8db12fdc07c718a4a937a44ae36339c972bd6f GIT binary patch literal 7081 zcmb_h3vd(H72Va!`dPBEEdNdIf@6m`;TtG{Krw|Hm+~z%VG0d2&`v`WaKS*sgr>oS zP-A9b%1oMpNz#}Zk~GegPUrw}oEZwubQ)~Z0>$BD{Fh}}vi@4_r)Tx#)!L3NOH}i` ze(c_N-?``9d-us4S-rB{WXLs86lJPdwqz}SPnUjlDqR1&`K4z3qIaz=Urg0s%eUem z`kl)*?4qdTbm@nt-a3_yo7&wKE0$`%R;O4Bv;J&Yu!o}Z=2t8!TlcJCX|L{h`J>SC8+z`isA*(ac+1>j|!1ts+Bl6E;bVD$kO(>}XWG@u(J?p@>rTH(MP7@`e{gsSk!fU`eH-JNtc} z0L${?;}g>);s*0v3^z+?*J*PeS^sEJwp4d9KQRCeD%Io+CYg;|rBK+KQPFLEo~2V# zR?W=q_pn&x(=_X)u=V2^~`UU41R&e=B1_X7v2q5GJp+e<`o%b zZe;RFX5^U-zgtt>GvK-1Wd}Dvv+?wgvkLR@lwlY{cFOiM&$ApW#~?2!li>^zZlKhC z8<%d>qNbD!z*DEgyXHyD#zCc&PsyBk_^Qo`>^2+v4_>OyEX)-LixVD@WWFBP?nS@J zOV7uWVcHD=BrDbDrJGxHjSB|@sUbC^mdGQag|+8+ z&Tn-eUU6)sc0(j1O7#p-sBrWTK{0@}-R^n1*c1~D01@r9NxCg_ws~zXK}5l!uE2K0 zC8J{W*`^oH{A{Fl5rzmi2R^!a$I7Ogv?JeBT@LTMIho@@BeO+(w)Z|bezjIirS%%U z{3tx3d6D<`xU0(c6Ya=T8eIc3#I)z^S8aW~*{B)1j8f4mD7F4O@u4A32qxQr^+;p2 z+MAv;afG! zva`IH#47I;*92=PW)@V9pDL( zaS@|5Cehoxz0qApO)YDUlKDr&C66Nyq8cg#6_ zkyY=1QFqzZn3kHx3n4)SrpQ2N`ug7O>XkKUo5V8G7=hr+gNtu;IdED4AIbqvEk@%n z-fs2=IUpc$#Dqc&$R3wlKL4P#PMfUZfdlTz5T)ac*X!9ZdDE1fQnUl&SptL^-a8hP z_T+O<+_McZY85An92FV71fFWQhhF+qGrodhkMUrVZO(pCckIhU`T2RgzzQPhkp?e@ zD7Dbu)w(#X{F%8M2^xYv+NlX;c6V^v{?E!D%SB2ln-~s2pv~d+Uf46AQ4M+FjK&sP z?wNnQ^O^H+I)hHeCo|X8)wz52D+`LthAoe{me7TB3Z44;p~Wp$Cwf3sYAG(Mqnq@} zTTfpbTRZX&MK1CJ?_vi88byv$=XeynRP&N*KA(5P zoT2cFRSrr;-LZwXzuP=o-NAeKbxzfuZ>c$dcY9go0^^bnYlol~aj?b^7_q&(qauCH zvvW6*Y#~a?JPl6>32)d0+LgZC@Ki}I>Pxo9MEb%d2!VkA(%#|PNoc}t_V|T6=dSm| zZ1uGC%8KH1%^&^Y=F!Z|9HgtYyXTcThZmMCQuqZoK}z)?Ozv5U%AB z!pn#f)f(NFQ$w_aQUuLkn|e+*c4(3qgEr|zL)*D)T`Q;mXnp=hf57MW2c9o_fuI?t zl#FROL*&6=tW@&@$L7=5bIhiY^d}CYhGc@7-4iU$(Z0KNCX|)k9lv-7Ac}KR5e9Ce zvEAr!R4(~e<+9=vjYm^86P}yD758QT@hcIVY50?<5)Z8D02^92-BPu@7_WsfxFL?m0t5?r{q+Zq z4R19~m|#LND0}eOS3bp2wY6tpZ+XFv??0lvKgK);pvWHKbnW*93#u*_ ze>;mG{FB)je(?wZ+imW*Hgr)?Re|14lWt>XMTgOZW*;1O2Ou`l4BpZG?i}w26ybz#7zbFkKMLDgmFd8To zN8Tv+h(j`YnM7*1?wme$Y3@{aOp%z5H~V!BSu;7a|fzE28Dj!LU5 Nmabef0b#bolpo+rr~Nr35E&K0F!bB+u@S!*v6J6S(apsW$WDSceVCY091t@j=$T_}nt$_^oU+ zE)uq`T2n_5$`s~@BtH6^7L{?oty;Y@u0@fQnlHO_@4?>*BA=*QvGk?aW5^}5E__4M zG>ukI@4+m_Q++%UfQeR}SR>V{DWn>RKhCX={`XGZYqPmM6rqrjIZ28)mKUs^tpf&0 zlKhs@m!*$^w~sVkYIiIy%kugtzhWXrE^lhLB+K2O{(6z*3=#uu+JCFh8z18DaKTiCJo6rR9aC%H;i5VmVVAbn1%7C@!dpR=pAj8ln zp&g_F*bL8c$N1Ir1q+m6hrwZwsaG-v3DPLz_ijZf>H$O&NjP2&lKY6`5*fxIz#QMk(wN6#%2&rO0IbKKz5G5f4U-HOhF19Dr4?Q%9uU&&$Sx zu`eoy2m$=+<&&zH!OMwB{2X@ZiNX$%05IyEe)S@b57Ay9eeteAql~dRJc~-S2;A{I z+nCESc5r%4R_o_=i^pn1E`@zBv}ylMn^U1v<1U{@P7yqe_8|rBY~1xjxs1tj?;L4t z?0Q_5qZZ`F7|Dq-*IKLA)O&m$w3)=`#?yoW0MF?gmg`iB%+iaTJvK*b zJhiW8?)X`Vt*c6^%T?cY*<|B8$_euFedDVOGSC2BUi)}`-Jv(a+8;s%fO_i?sZ%8o zG$nGs2$-9%e*Irx*3HP1>*C%zxG8jokb;;|?;x3+ zBk08tND@7EN2-z*Q_mso{X&1b$zGnVhQ!Ny#_ej>}Q?GJ^lGM$=B0GZZ@n1AzKIs8=P5XlJsh zu|I6}{DoNm(aYJT@Eq)T{A#Am+QHjB9Nd>ggBa>9j|pvZ0+ZB4PR8%UTzkIE)3;7h zNrYT3pdQVD6dxC_$c_&l)4~8y-#b8PRl)K-JSS}`5u)Gob#vwFIX|t=`AL_d!(Rh4 z2cCY0gy0MUE`+BO^8gLc@sG$&$1jlZob)6z8ui?8|GaYWi=Hz%S@~jN1}v9r*lTbJ z`cfbO*53SxRnJWkSb%zMGC66+4D2R;%`#+X<%umB8xNGhJ&|D?z}8Q0clLQFU3;xc zCdu0KiNJ8C=X7>fJ_3$kKUSt0J5UA>7{)3IVk8C-sbAjh{a@Pv6Sa7qBedI66n3kj zC!rpKUitpoDqVHAp`8SP;PeC)7Z>MB@f^MSi2wlh#oedw&o4-0^3B9(^4AP|e921O z=Lp{^@CS{o42C7C%WbwktfpAvQ>!#b8xQlxAIm~rHkZ?jRTj8mL?x)MwwnI2aRI-x z8~b}~a0~c=;OV2hu}QIAeVyFYBLL<{PIW@8U>~*;8Ev{2@7tdEQLe3^N!mwH zVrPObTh@~S;iYd_J)OWpeqQ>&^dp^P-Hz z?bC?DF#wF>@=`N*oL^L&Niht<2cC5Qt2Z8(j)7IbZvQVzW|zQgglENuC70>H(I2S! zmu5-|ryh;R0C0h^++OP09p@JoX<;p~19tdIZ#=POLG*SQRsT})tYSF5*o=5mYrWli zpyty6^=Lm10M{JD{K5>_L2N{YTy|M+I{9W)46ORKAOE~)R-w=5FWSiE^6whI zJ5Y0MqIv-UKEvFC3~VRN1Fz5lJ6vfoo!YvfA~%wFfHLzV)2|M$$(xxQ+;ch_I}g?h ztB0oy4C#ITMH|4Rb1cT1&rL;H-t8MsmfNoioD==O(;HrH0;*i_h{Qipcq#mFA{ny+#vppgcU{-e@zQ_VWaO$Gc|L&)a!nUNJHref7TK&hJ;U46h$srz_2( zd|+VIo14u?HvC&NMI#vHydft8KvR~Xbo;p(*=d+noI!T8t@lhFV-x-aT$xorcjtvU zg&F=kU;;bS*ZQ8jqYN95t<5aep}nQK_vnVt)FG%x<4G*QPR}uvWHAh!rho$MaJwB0 zizYH~>MIJ;vFmdkaVK`I#W==rVy(ifI9eO3dW;hi0NSw(&ul+eq)QEwXTi|a(c4hB zXeQ4Ntok`SFO=s)Jpz{>Sj;~n+-f!6^V{LuuEw;a^o(Tfq@KeqL8t&@4BO5Xj4*J6 zj4Oblxx;d5%Yw?{6iA1Z4vXV^yDydIjaz$uANW#ZoAJiG%ktBdY#08w!OLL)U?A2G zGqyG4Y8g9-#RCNC4fdJ3#L6P|9mC^`E%vh9ROWt>zx1QJ;F4f&>F&GoyB`2xv^vz! z@Blc5>DwBzGg2657ShB{4q5mTP54e9sLQWj-(_jqwJbd;E_Bb~#t9pM&ybO>Vd6oY zftyCSKoi)x+Pf{yyOu|$9>Ycgz%i86H)t|6{tYMs2pZ}ic3bZ3j$D1@035@#`i3OG z9l|1jU*YAnvD1=!APOc&QTB&4cQ4i*rj^Z7rSweL0b-G4u-wU+<@ zL$C}*^$m&?6>ozYr#IjNYv12veISK;j2x8(SY<3jVSNLwQ87s;=z%BO$3|<5MCvh> z1OOO?Whkg`aH*5UeF^)3%w@8+eSn+LNHV72%18siG333|;7}!jAz;s9lC6yNneFY8 zs+Y_H?Aow)$a(v$J!$I1J8xO9{ox;Q^DNogvy%!uUb0_A@EiLmo=bc8{`eJLoY&Ov zb-284pBGOqrv4u#lYM(uNv<9uC37JT*zZ5guxFc0mI0Sq8N0MBT^Xlf>$zr96{H7{ nN?C~GNa;c$PAP4(ryk%-nYC#avBt$LOV!HfR~%nf^WOgf9^wr_ literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/attribute_private.gif b/src/org.activiti.designer.eclipse/icons/modifier/attribute_private.gif new file mode 100644 index 0000000000000000000000000000000000000000..0e29242673408d31f33d7bdab9b7539b9d1f1cb1 GIT binary patch literal 88 zcmZ?wbhEHb6krfwSj50^-`;+{z5V_A`u||S00W9YSr{1@SQvCb0wA>v%(5Q4?))=2 f<@uULqD8yyhLAx|0!zt#(KSn-?kiZM!e9*mvdA2V literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/attribute_protected.gif b/src/org.activiti.designer.eclipse/icons/modifier/attribute_protected.gif new file mode 100644 index 0000000000000000000000000000000000000000..924fee2b66d4ae2fe530f17b8617c1dd7fd7e671 GIT binary patch literal 89 zcmZ?wbhEHb6krfwSj52a|9<`d{r3Co?d#+1|APSo7%2W^VPs%nWzYffKx!SB>$| literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/attribute_public.gif b/src/org.activiti.designer.eclipse/icons/modifier/attribute_public.gif new file mode 100644 index 0000000000000000000000000000000000000000..630b286c3bda32fa480e0e01949bad7409098b66 GIT binary patch literal 92 zcmZ?wbhEHb6krfwSj50!UvF<8Z@>Tk{`vdk|APSo7%2W^VPs%nWzYffKx!G76(e@t m`Dbv-b0LGn8Edx-f(8OD>YYm@IUT>}9*jO)lIzXMU=09r*&bs6 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/operation_private.gif b/src/org.activiti.designer.eclipse/icons/modifier/operation_private.gif new file mode 100644 index 0000000000000000000000000000000000000000..96f464d6798fb5472d98705e4013cdca2ece6551 GIT binary patch literal 96 zcmZ?wbhEHb6krfwSoELaz<~q*>+SEy+uyghpKou^00W9YSr|cV9S{Lh>%gqavFnbV p;}M5Bdvhk7-B|A|5hkwU`DFRJoZoW-fB7}t;VF3g&YOwB8US|fAL{@B literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/operation_protected.gif b/src/org.activiti.designer.eclipse/icons/modifier/operation_protected.gif new file mode 100644 index 0000000000000000000000000000000000000000..d52494442231a70ff4e696eef9e9bf6b24f53446 GIT binary patch literal 91 zcmZ?wbhEHb6krfwSoELaz<~q*@7Mp|Z@<6ZzCPZb0R|L*vM_?!Iv@h1)`3}pW7i#9 k#ZwPgl{Vkmo48=EN=8iPyz2~Y!CJ1#5{tJ?W?--e060z^ng9R* literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/operation_public.gif b/src/org.activiti.designer.eclipse/icons/modifier/operation_public.gif new file mode 100644 index 0000000000000000000000000000000000000000..b5129152c94ba899e28af508608a1e39747daba4 GIT binary patch literal 97 zcmZ?wbhEHb6krfwSoELaz<~qy_4fAh_Vx4Q=kJeafC0syEQ}zw4u}A$bzoNG*mXx% q<(T4}y}mEHcDD+B_dMcInXxL)QMzP7N#Bzk&SjeG{!C(Eum%8DJs$u7 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/modifier/reference_private.gif b/src/org.activiti.designer.eclipse/icons/modifier/reference_private.gif new file mode 100644 index 0000000000000000000000000000000000000000..ff1a11248a3b35ce6b01eea44feeb2160b48f958 GIT binary patch literal 627 zcmZ?wbhEHb6krfwcoxI3S6%&}hDM&a_#6d=J?iR9l$0tYC8x{F&sS93tg1RmPVR1W zbhEVdWo_--fq_>I4SQr|k85gP(bJnKC$~dQtyn^0v69j`Ev-$es>d`n?M@p z)U1<|x@Ky6&CKkGhQ?YIl?&S1S9Ej&1O>OMs)h*(-E?=~prSHOUj9y4*mgCwb{Uxl zX=!sFp4)zYxBdO2goSmvxRxm?x$*PgPfAJ=6$bLK zl9Ko0;(P=IT=@8$`1o#ldhSwFOBEH378X|K;FzbVcv?$qrLyvME35tL>UTmynxv&| zczG4s+5H3rZa6sHu(!WvVX;m{B|=E3Qc_ZejqO2dYO9RQgY@+O|Nk@43n>0%VPs&4 zVbB3t2#OO1_6rR$P0h+0UNX&{&Dx5LEFzr3QC&?QZcYNe`m!c!OkEPXY!MNxK1NH- z?3y`MHMt{Pqja1D#LT(anq2rrqxbW$?T-%Uoa`;A#V)W{Nr;J`OO}^el0nJFRDoT7 zzZ@3>pP&Xii;R_4LfV0_#%g^fX=#!JN6Ta znqP54+hmSs$XPv$6|Mni((DE zDreex0o6yOk7Y+NqPOPiiTVN|Nm#8BT)Rw!pOi7&7cFa z6BH*5>=zrNo0{2lZH1dVo7I$=S+zM88M>NGy=^!=gH;@T*}KHNxFRALnGBcMn>TZc zEAT{wFlg#)$hq@!HReMK#0@x28lbhsTya<)?SK?J75~JT0dl!e&jYI^#C!eGDY9H+Af`Hp=%8)FNEZtagE$+ zWLvFdm@LzLCDCJ&hVLA0(;T_5bq1bOH4~1Q#q2gQ&6blg;g8*Gl5p6}Z@!LBgrwJW zt<;m&jxDNzOZAG+`8YJH@JVx|pRyIz;*m7sQ*aP6N|UL$5G-pYV3aD8e9}VMUBta# z!*hye(lPUh&4#+slKu;HEK3w54EbDp)U!@IhHo;=JLAU8%A^-3C1)cjZ!c7E*0cUn zjDS36)8%+(HYQ~c5m8MZr*>7%VDX}J-WjLtRJ}ww1zF{61%=hQTdpLvT}@$NVEF(4 zKaivyQ2fcl$iR@mpaZf36ekSq7aJ0qn$=Y7l$$%7#T8hXwK>EXx|;OOV|XmX#m=)=M3Wcj zD>iN+CK10tVRqI1TC7Z5k}B-X%I;FJ`(x!}-)oqO8)@k}a0&Rod8Zi9=jL%Bg2Rc~ zsa;ari|2;YQN~90rVf?|51bA%X$5o{co-%!_Bo0&c^GU^JjSNO#$vHy(F)E6c_t1E frou(+ss>5{Ar%Y@7$06UJ@_0%<+lJ zqsts0kw>Q~Vu@P1%qf;GOPAGY`}p5}etw7l%4%r=ZYe+kZ#sa)BEqvggoS4_7jeg8 z$Yu^=Xvl@GkHcmdgc5PL(QF|8tB}JT8A>V{76ekO)oPiZ4XKHJ*RKg4FqIgNPl7PO z0(+7YK@4h{9ujpyr5A)Xhr2`)>=PC+Ui-}mkrWbBhJlI=hhvL5jaJk0Y#9n7u&Dbi z;1k%WHR>uc4QjXBZScRL?|1|N9pwM$?-NK?A1*89{J?oRw-vurcAmiC^=)Z4f)3HW zTA*v=)!ZlOU)}h6Upgiy=4PzA-~D={e!NulbjQ(HBB2zD+H8+L3NN6h^=Svw`MoRv zlLM*3snL~9_3AU~S#K(uE2cZ66Y1joh|;-j#NcouGnGjswOC0;lh0B3xUx8RRah_A ImzRL{1K)#~oB#j- literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/mof/mof.gif b/src/org.activiti.designer.eclipse/icons/mof/mof.gif new file mode 100644 index 0000000000000000000000000000000000000000..cbf85221a43550113a39cd3e3c7ff693d2f030e0 GIT binary patch literal 670 zcmV;P0%83}Nk%w1VGsZi0OkMyGfJD--Qc^%;Iz%$1qf6cFR3FoiIuh2bc3}1`TqX? z_>-EpyVT~y$lCV*{;9OgLPmA&{`_QTnEw9t$;7-`W0~sd+(}!fPgajqY`g#d{{$R| z3?X{{{q1C5nTUv&Y;u+V{_zJSj2SqG`S$W8Cs${Ls{jXOPEvOj7-Ef;tc;eoVPS>; z{r~;@`BiA3WO${In9gB$p=f!oNpZZeyw0GWwReHQ&fx2%v%Rjw(G)M1S#zMu$IlB5 zaGs{Ho1wp+s>PO@#pvn!Zgs14lHy=wauz|J8%Dr2TDq~PtyqA&rmVr)5dj%sdz{Qvv_06YHt{AYHs`~CAxZlYv{!a-@ibdbkNe5?EX{RbF$LQkyl`}^VP z(A^8LV00000EC2ui z01yBW000O3fMy8^W(t2;KMQ>mAz%((YqnKlCtXES0}TOIOGrpxCVvVb1SfB)8Fy-31ziSQu2cj< zHFFzDG&=qh3K;Z*~6a)x_xgY_BlO90_xv=2n1Bwy`0F22ZN6@Plf2vHdK%ovDC0h)&02>GZ EJB8juaR2}S literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/mof/newclass.gif b/src/org.activiti.designer.eclipse/icons/mof/newclass.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1c6545cd644ed7ecea4a95cf17dbd3934180840 GIT binary patch literal 598 zcmZ?wbhEHb6krfwc*ekxv!ZdqiFL+JzGlt-4xJHB-BE7+aUnCZqGlJw%qh%RR@1b3 zl1iDKUX7b&TR_B|+}L@A$&1PxH%(Y{a-D9Ci(aj(eyy89ottr^r}v};uL*JG>)LnR zIB3-1Zr$#0-x-v>qPlPIEW3^XyY>LLzHs;ch@fdn*~_c?_su$d_vEAZPlKio{2vS$s00*$vM@3*q%-J%%mc*<1N-KN z^rq&P*0%Q8_HY47J}H5)*oe*+ZaxQ3PcO&ln24B|W^P%Z(BKf?a6WJU zv~AmxlHw8*nmC*Sw*~pxqy@yM#5c2l~9o3IxQ!i zrX{beEUeG3%GNBXWMYwKpstu^ucyt>yw0Fwds_^*W@{cR z);zbi=i1&m$Er22?Va-e+R~*_igSvio}XL#|NnmmLO}5+3nK%A2!jqtA;?Y!) zzLd;)FFclnJlb=P(b{t-&*dW?JN8X!@?`upfuob@0Si;6#LQk5&w~{vJPofx9hGEM z5*j3QEZ4X-$}unCo5FNF>5gxg&g}DPOGGY8snk`ga0s>vvbPCx=%nlPi6}By0|0*E BO%VV9 literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/outline/thumbnail.gif b/src/org.activiti.designer.eclipse/icons/outline/thumbnail.gif new file mode 100644 index 0000000000000000000000000000000000000000..f302d8c882b0ffd7bcd1bb01a7f3ca634f048b6e GIT binary patch literal 167 zcmZ?wbhEHb6krfw*v!E2|347T-@kwU{rmg>-?!fnWX+%7(9jScAO9aHhXE9SvM@3* za5CtCWI$#xu!I<#v^?r4Ascnn;b@=;hkC`~>4~wglnx3qJbihOqkw^>>E1f;X9*fo z{SJ+eo0drAH61DZRpL6E)vr`wYTv&5x#FvROZPt5Q0Y`wG&l2Wq?hSAVL=9K022~E A)c^nh literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/outline/tree.gif b/src/org.activiti.designer.eclipse/icons/outline/tree.gif new file mode 100644 index 0000000000000000000000000000000000000000..852dc81ba6acfc111ead95079ffc3faeed1f4c89 GIT binary patch literal 133 zcmZ?wbhEHb6krfw*vtR~4fgi+_V)4re}DM@|9?Y6LwtNZP!z}pNn!xSpDc_F3>*wP zAQ_Mu3@k)6H1Y|sx0Dwm?k2DX5h4N(Z;L@ZkseL$bzJ@A~&HzNSCw% zsR2Qwq$W+K(NR>qLexkvCsGqpnreLDm@{+w?tgcObI$iV|6f{Gl6UA#I;GPZk=SQM zw1^U65wevrVzd|~hQ*L=Y9m^UR-#!n*;!>oX;DfPiz2(qMpz3gVHPGJ2^k?Rq=Z-q z1+W1PEG%Q1ERTKK7-b9_LzWhm)M0Of&)Odu8AxQWG zEh;AaaoAj)d)uaSLL0Ml6+7z$ZBuu$v#U-V_6Uwci{yy5H*s`WU(f{_yDN&y|&UB9V;86E_-sPrW8IIp5h88VH7)TPMy|zi8|D(9-Jf_0RS6 zhW>3NHxlurBo|_H(fIG&0Iet2*5a%A0cxJA8UFk7^U_3dkm^EZ{uT}1ZK^7|?Oq5!ymH`FVdJLg zz;bCctAv(fk)9*RcNJcxnfjq~O(%=4WtV*|XpFSC*HM4h$Fx7+4`0vQ+&AlezSDC# zYcBmdfUS59sarFGty?bsSxb^z!yN@UDfByOX>%Tug z8@FEn^!>Nfgu_oieBXTO`I(3BXC1kpvF!Z+|NqT84={{^(GVEQA)o_tJSZbs3X58R2L4>hsJ42e)k{<;JTQ~xrzFR7AAjx%w dnXJ^e9|jMv&6=Pr&l){-)zeeK>MSe_)&Lp}ZGQj& literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/sample.gif b/src/org.activiti.designer.eclipse/icons/sample.gif new file mode 100644 index 0000000000000000000000000000000000000000..34fb3c9d8cb7d489681b7f7aee4bdcd7eaf53610 GIT binary patch literal 983 zcmZ?wbhEHb6krfw_|CxKYUg-n!?izO{@9*?jxd%4aX0yzy`dymabz zw#(eg=y~&N&n)dZv2xzduG}5lraiApo3(c4*{Ylg5#|$JO_EEZ<^|a2`Z*=9ns7DV zy=TR&gYw*7f%auV?ip3tvjRPmcdoho{K?x$_vR?C#t5&<;~V}S*>OMCr>h}%%bLZ9 zmo3`hYEwTICo-TTCZwgTsC&VjZRgJ1eE#fBa^%9R zmmfWS@;bnyJ27HWY}kxYzv(Hl>yu;FCPlAEh+34Muq-8Rb6C)<8qA3{r2e5 z`$vyngh#H=FWlqqvnapfc5%(!sQ4v?r7J61-&eJNEN^;KTK}T7{#i-gJh%G*9vcYdwv_*~xdw!Gz4Va?T!sXyyF@8?w<>X`X=#j%uHV4GRvj@+tE@ zQ%F!a)GKcn^~8abN>4la1UNXVL;{ZWi)lEwyeatDu%Lr6;aASiLrXXW zQm#^`dHKQ9 z)8iHt22PC%nHHV2B)M>1LCJ=~?3L*`D>JHAWG_6{_W%EX2HZgLCkrD3gBXJjND0VJ z23EfXs(nWrdNOud1T9%&;AlIQak;0lW^ mOuf6vYx#Q4tyz0rQm=csZSK6WH8AhG@Y%{o33Vb&4AuaJKS#&_ literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/tree/tree_left.gif b/src/org.activiti.designer.eclipse/icons/tree/tree_left.gif new file mode 100644 index 0000000000000000000000000000000000000000..52dafefab4eefad60b543e6446059a5bd2d8324d GIT binary patch literal 209 zcmZ?wbhEHb6krfwIKsfNc=^WsvX-qo52`hIShffGOip&56dgJ{D|B{t*o>^`dHKQ9 z)8iHt22PC%nHHV2B)M>1LCJ=~?3L*`D>JHAWG_6{_W%EX2HZgLCkrD3gBXJjND0VJ z23EfXs(mS%YDbiqo<*2U3FdIr=DV!S>v(@QyN7Dig3c_pHph)t^McHtYln4wE7;X| nRY*ojM`LPhs-xD-;F%k94!x_{A2fZ(wz;z}?y-|+Vz34PUwBAi literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/icons/tree/tree_right.gif b/src/org.activiti.designer.eclipse/icons/tree/tree_right.gif new file mode 100644 index 0000000000000000000000000000000000000000..695e5a5cfa5b259193c4caa06228d1d38282d05e GIT binary patch literal 209 zcmZ?wbhEHb6krfwIKsfNc=^WsvX-qo52`hIShffGOip&56dgJ{D|B{t*o>^`dHKQ9 z)8iHt22PC%nHHV2B)M>1LCJ=~?3L*`D>JHAWG_6{_W%EX2HZgLCkrD3gBXJjND0VJ z23EfXs(mS$^D;O)x(+T0Q&0$Gl}%gly7`Mw^Bj+`f&eL2@7JQjYjwDt4moXp$h7ia m{sM2&e$N~&tK6u0rzb~*?R{FtsB7SAq7>|J^hSh^`dHKQ9 z)8iHt22PC%nHHV2B)M>1LCJ=~?3L*`D>JHAWG_6{_W%EX2HZgLCkrD3gBXJjND0VJ z2G*bjs&dYX^OjT^UAUr>{d=C<*8rB>$IFF0`&{3P+e8YeJ~qr0VPWx7|H8r%!5EUw qkjUHlqr^h4bg8LR=7Y)5?n literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.eclipse/plugin.properties b/src/org.activiti.designer.eclipse/plugin.properties new file mode 100644 index 0000000..75229ae --- /dev/null +++ b/src/org.activiti.designer.eclipse/plugin.properties @@ -0,0 +1,20 @@ +############################################################################### +# +# +# Copyright (c) 2005, 2010 SAP AG. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# SAP AG - initial API, implementation and documentation +# +# +# +############################################################################### +pluginName = Graphiti Examples Common (Incubation) +providerName = Eclipse Modeling Project + +_gfw_test_view = Graphiti Test View +_test_preferences_page = Graphiti Test Preferences diff --git a/src/org.activiti.designer.eclipse/plugin.xml b/src/org.activiti.designer.eclipse/plugin.xml new file mode 100644 index 0000000..7996271 --- /dev/null +++ b/src/org.activiti.designer.eclipse/plugin.xml @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create a new Activiti Project with a basic folder structure and a Maven POM file. + + + + + + + + + Create a new Activiti BPMN 2.0 Diagram. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org.activiti.designer.eclipse/pom.xml b/src/org.activiti.designer.eclipse/pom.xml new file mode 100644 index 0000000..8c27ec1 --- /dev/null +++ b/src/org.activiti.designer.eclipse/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + + org.activiti.designer.eclipse + eclipse-plugin + Activiti Designer - Eclipse + + \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.export.ExportMarshaller.exsd b/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.export.ExportMarshaller.exsd new file mode 100644 index 0000000..1225a13 --- /dev/null +++ b/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.export.ExportMarshaller.exsd @@ -0,0 +1,102 @@ + + + + + + + + + Allows you to provide custom marshallers when exporting diagrams. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Provide a class that implements the ExportMarshaller interface. An instance of this class will be created and invoked when the user chooses to export to your format. + + + + + + + + + + + + + + + 0.5.1 + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.validation.ProcessValidator.exsd b/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.validation.ProcessValidator.exsd new file mode 100644 index 0000000..4de8968 --- /dev/null +++ b/src/org.activiti.designer.eclipse/schema/org.activiti.designer.eclipse.extension.validation.ProcessValidator.exsd @@ -0,0 +1,102 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Provide a class that implements the ProcessValidator interface. An instance of this class will be created and invoked when the user chooses to validate the diagram (or, when this is done automatically by Activiti Designer). + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/Logger.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/Logger.java new file mode 100644 index 0000000..97c1ead --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/Logger.java @@ -0,0 +1,58 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2005, JBoss Inc., and individual contributors as indicated + * by the @authors tag. See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.activiti.designer.eclipse; + +import org.activiti.designer.eclipse.common.ActivitiPlugin; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +public class Logger { + + public static void logInfo(String message) { + log(IStatus.INFO, IStatus.OK, message, null); + } + + public static void logDebug(String message) { + log(IStatus.INFO, IStatus.OK, message, null); + } + + public static void logError(Throwable exception) { + logError("Unexpected Exception", exception); + } + + public static void logError(String message, Throwable exception) { + log(IStatus.ERROR, IStatus.OK, message, exception); + } + + public static void log(int severity, int code, String message, Throwable exception) { + log(createStatus(severity, code, message, exception)); + } + + public static IStatus createStatus(int severity, int code, String message, Throwable exception) { + return new Status(severity, ActivitiPlugin.getDefault().getBundle().getSymbolicName(), code, message, exception); + } + + public static void log(IStatus status) { + ActivitiPlugin.getDefault().getLog().log(status); + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BoundaryEventModel.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BoundaryEventModel.java new file mode 100644 index 0000000..b1a2f2b --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BoundaryEventModel.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmn; + +import org.eclipse.bpmn2.BoundaryEvent; + + +/** + * @author Tijs Rademakers + */ +public class BoundaryEventModel { + + public static final String TIMEEVENT = "timeevent"; + public static final String ERROREVENT = "errorevent"; + + public BoundaryEvent boundaryEvent; + public String attachedRef; + public String type; +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BpmnParser.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BpmnParser.java new file mode 100644 index 0000000..b679ea7 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/BpmnParser.java @@ -0,0 +1,1777 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmn; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.stream.XMLStreamReader; + +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.util.preferences.Preferences; +import org.apache.commons.lang.StringUtils; +import org.eclipse.bpmn2.ActivitiListener; +import org.eclipse.bpmn2.Activity; +import org.eclipse.bpmn2.AlfrescoMailTask; +import org.eclipse.bpmn2.AlfrescoScriptTask; +import org.eclipse.bpmn2.BoundaryEvent; +import org.eclipse.bpmn2.Bpmn2Factory; +import org.eclipse.bpmn2.BusinessRuleTask; +import org.eclipse.bpmn2.CallActivity; +import org.eclipse.bpmn2.CandidateGroup; +import org.eclipse.bpmn2.CandidateUser; +import org.eclipse.bpmn2.Documentation; +import org.eclipse.bpmn2.EndEvent; +import org.eclipse.bpmn2.ErrorEventDefinition; +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.FieldExtension; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.FlowNode; +import org.eclipse.bpmn2.FormProperty; +import org.eclipse.bpmn2.FormValue; +import org.eclipse.bpmn2.FormalExpression; +import org.eclipse.bpmn2.IOParameter; +import org.eclipse.bpmn2.InclusiveGateway; +import org.eclipse.bpmn2.IntermediateCatchEvent; +import org.eclipse.bpmn2.MailTask; +import org.eclipse.bpmn2.ManualTask; +import org.eclipse.bpmn2.MultiInstanceLoopCharacteristics; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.ReceiveTask; +import org.eclipse.bpmn2.ScriptTask; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.SubProcess; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.TimerEventDefinition; +import org.eclipse.bpmn2.UserTask; + +/** + * @author Tijs Rademakers + */ +public class BpmnParser { + + private static final String ACTIVITI_EXTENSIONS_NAMESPACE = "http://activiti.org/bpmn"; + private static final String CLASS_TYPE = "classType"; + private static final String EXPRESSION_TYPE = "expressionType"; + private static final String DELEGATE_EXPRESSION_TYPE = "delegateExpressionType"; + private static final String ALFRESCO_TYPE = "alfrescoScriptType"; + + public boolean bpmdiInfoFound; + public List bpmnList = new ArrayList(); + public List sequenceFlowList = new ArrayList(); + private List boundaryList = new ArrayList(); + public Map locationMap = new HashMap(); + public Map> flowLocationMap = new HashMap>(); + public Map defaultFlowMap = new HashMap(); + public org.eclipse.bpmn2.Process process; + + public void parseBpmn(XMLStreamReader xtr) { + try { + boolean processExtensionAvailable = false; + SubProcess activeSubProcess = null; + while (xtr.hasNext()) { + xtr.next(); + + if (xtr.isEndElement() && "subProcess".equalsIgnoreCase(xtr.getLocalName())) { + activeSubProcess = null; + } + + if (xtr.isStartElement() == false) + continue; + + if (xtr.isStartElement() && "definitions".equalsIgnoreCase(xtr.getLocalName())) { + + if (xtr.getAttributeValue(null, "targetNamespace") != null) { + createProcessElement(); + process.setNamespace(xtr.getAttributeValue(null, "targetNamespace")); + } + + } else if (xtr.isStartElement() && "process".equalsIgnoreCase(xtr.getLocalName())) { + + processExtensionAvailable = true; + if (xtr.getAttributeValue(null, "name") != null) { + createProcessElement(); + process.setName(xtr.getAttributeValue(null, "name")); + } + } else if (xtr.isStartElement() + && "documentation".equalsIgnoreCase(xtr.getLocalName())) { + + String docText = xtr.getElementText(); + if(process != null && StringUtils.isEmpty(docText) == false) { + Documentation documentation = Bpmn2Factory.eINSTANCE.createDocumentation(); + documentation.setText(docText); + if(activeSubProcess != null) { + activeSubProcess.getDocumentation().add(documentation); + } else { + process.getDocumentation().add(documentation); + } + } + + } else if (processExtensionAvailable == true && xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + + createProcessElement(); + process.getExecutionListeners().addAll(parseListeners(xtr)); + processExtensionAvailable = false; + + } else { + + processExtensionAvailable = false; + + if (xtr.isStartElement() && "startEvent".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + StartEvent startEvent = parseStartEvent(xtr); + startEvent.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(startEvent); + bpmnList.add(startEvent); + + } else if (xtr.isStartElement() && "subProcess".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + SubProcess subProcess = parseSubProcess(xtr); + subProcess.setId(elementid); + activeSubProcess = subProcess; + bpmnList.add(subProcess); + + } else if (activeSubProcess != null && xtr.isStartElement() && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + activeSubProcess.getActivitiListeners().addAll(parseListeners(xtr)); + + } else if (activeSubProcess != null && xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr.getLocalName())) { + + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + activeSubProcess.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isStartElement() && "userTask".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + UserTask userTask = parseUserTask(xtr); + userTask.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(userTask); + bpmnList.add(userTask); + + } else if (xtr.isStartElement() && "serviceTask".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + Task task = null; + if ("mail".equalsIgnoreCase(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "type"))) { + task = parseMailTask(xtr); + } else if ("org.alfresco.repo.workflow.activiti.script.AlfrescoScriptDelegate" + .equalsIgnoreCase(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "class"))) { + task = parseAlfrescoScriptTask(xtr); + } else { + task = parseServiceTask(xtr); + } + task.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(task); + bpmnList.add(task); + + } else if (xtr.isStartElement() && "task".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + ServiceTask task = parseTask(xtr); + task.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(task); + bpmnList.add(task); + + } else if (xtr.isStartElement() && "scriptTask".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + ScriptTask scriptTask = parseScriptTask(xtr); + scriptTask.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(scriptTask); + bpmnList.add(scriptTask); + + } else if (xtr.isStartElement() && "manualTask".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + ManualTask manualTask = parseManualTask(xtr); + manualTask.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(manualTask); + bpmnList.add(manualTask); + + } else if (xtr.isStartElement() && "receiveTask".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + ReceiveTask receiveTask = parseReceiveTask(xtr); + receiveTask.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(receiveTask); + bpmnList.add(receiveTask); + + } else if (xtr.isStartElement() && "businessRuleTask".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + BusinessRuleTask businessRuleTask = parseBusinessRuleTask(xtr); + businessRuleTask.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(businessRuleTask); + bpmnList.add(businessRuleTask); + + } else if (xtr.isStartElement() && "callActivity".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + CallActivity callActivity = parseCallActivity(xtr); + callActivity.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(callActivity); + bpmnList.add(callActivity); + + } else if (xtr.isStartElement() && "endEvent".equalsIgnoreCase(xtr.getLocalName())) { + + String elementid = xtr.getAttributeValue(null, "id"); + EndEvent endEvent = parseEndEvent(xtr); + endEvent.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(endEvent); + bpmnList.add(endEvent); + + } else if (xtr.isStartElement() && "intermediateCatchEvent".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + IntermediateCatchEvent catchEvent = parseIntermediateCatchEvent(xtr); + catchEvent.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(catchEvent); + bpmnList.add(catchEvent); + + } else if (xtr.isStartElement() && "exclusiveGateway".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + ExclusiveGateway exclusiveGateway = parseExclusiveGateway(xtr); + exclusiveGateway.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(exclusiveGateway); + bpmnList.add(exclusiveGateway); + + } else if (xtr.isStartElement() && "inclusiveGateway".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + InclusiveGateway inclusiveGateway = parseInclusiveGateway(xtr); + inclusiveGateway.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(inclusiveGateway); + bpmnList.add(inclusiveGateway); + + } else if (xtr.isStartElement() && "parallelGateway".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + ParallelGateway parallelGateway = parseParallelGateway(xtr); + parallelGateway.setId(elementid); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(parallelGateway); + bpmnList.add(parallelGateway); + + } else if (xtr.isStartElement() && "boundaryEvent".equalsIgnoreCase(xtr.getLocalName())) { + String elementid = xtr.getAttributeValue(null, "id"); + BoundaryEventModel event = parseBoundaryEvent(xtr); + event.boundaryEvent.setId(elementid); + boundaryList.add(event); + if (activeSubProcess != null) + activeSubProcess.getFlowElements().add(event.boundaryEvent); + bpmnList.add(event.boundaryEvent); + + } else if (xtr.isStartElement() && "sequenceFlow".equalsIgnoreCase(xtr.getLocalName())) { + SequenceFlowModel sequenceFlow = parseSequenceFlow(xtr); + sequenceFlowList.add(sequenceFlow); + + } else if (xtr.isStartElement() && "BPMNShape".equalsIgnoreCase(xtr.getLocalName())) { + bpmdiInfoFound = true; + String id = xtr.getAttributeValue(null, "bpmnElement"); + boolean readyWithBPMNShape = false; + while (readyWithBPMNShape == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() && "Bounds".equalsIgnoreCase(xtr.getLocalName())) { + GraphicInfo graphicInfo = new GraphicInfo(); + graphicInfo.x = Double + .valueOf(xtr.getAttributeValue(null, "x")).intValue(); + graphicInfo.y = Double + .valueOf(xtr.getAttributeValue(null, "y")).intValue(); + graphicInfo.height = Double.valueOf( + xtr.getAttributeValue(null, "height")).intValue(); + graphicInfo.width = Double.valueOf( + xtr.getAttributeValue(null, "width")).intValue(); + locationMap.put(id, graphicInfo); + readyWithBPMNShape = true; + } + } + + } else if(xtr.isStartElement() && "BPMNEdge".equalsIgnoreCase(xtr.getLocalName())) { + String id = xtr.getAttributeValue(null, "bpmnElement"); + List wayPointList = new ArrayList(); + boolean readyWithBPMNEdge = false; + while (readyWithBPMNEdge == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() && "waypoint".equalsIgnoreCase(xtr.getLocalName())) { + GraphicInfo graphicInfo = new GraphicInfo(); + graphicInfo.x = Double + .valueOf(xtr.getAttributeValue(null, "x")).intValue(); + graphicInfo.y = Double + .valueOf(xtr.getAttributeValue(null, "y")).intValue(); + wayPointList.add(graphicInfo); + } else if(xtr.isEndElement() && "BPMNEdge".equalsIgnoreCase(xtr.getLocalName())) { + readyWithBPMNEdge = true; + } + } + flowLocationMap.put(id, wayPointList); + } + } + } + + for (FlowElement flowElement : bpmnList) { + if (flowElement instanceof BoundaryEvent) { + BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement; + for (BoundaryEventModel eventModel : boundaryList) { + if (boundaryEvent.getId().equals(eventModel.boundaryEvent.getId())) { + for (FlowElement attachElement : bpmnList) { + if (attachElement instanceof Activity) { + if (attachElement.getId().equals(eventModel.attachedRef)) { + boundaryEvent.setAttachedToRef((Activity) attachElement); + } + } + } + } + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void createProcessElement() { + if (process == null) { + process = Bpmn2Factory.eINSTANCE.createProcess(); + } + } + + private StartEvent parseStartEvent(XMLStreamReader xtr) { + StartEvent startEvent = null; + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "formKey") != null) { + String[] formTypes = PreferencesUtil + .getStringArray(Preferences.ALFRESCO_FORMTYPES_STARTEVENT); + for (String form : formTypes) { + if (form.equals(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "formKey"))) { + startEvent = Bpmn2Factory.eINSTANCE.createAlfrescoStartEvent(); + } + } + } + if (startEvent == null) { + startEvent = Bpmn2Factory.eINSTANCE.createStartEvent(); + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "initiator") != null) { + startEvent.setInitiator(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "initiator")); + } + startEvent.setName("Start"); + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "formKey") != null) { + startEvent.setFormKey(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "formKey")); + } + boolean readyWithStartEvent = false; + try { + while (readyWithStartEvent == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "formProperty".equalsIgnoreCase(xtr.getLocalName())) { + FormProperty property = Bpmn2Factory.eINSTANCE.createFormProperty(); + startEvent.getFormProperties().add(property); + parseFormProperty(property, xtr); + + } else if (xtr.isStartElement() + && "timeDuration".equalsIgnoreCase(xtr.getLocalName())) { + addTimerEvent(startEvent, xtr.getLocalName(), xtr.getElementText()); + + } else if (xtr.isStartElement() + && "timeDate".equalsIgnoreCase(xtr.getLocalName())) { + addTimerEvent(startEvent, xtr.getLocalName(), xtr.getElementText()); + + } else if (xtr.isStartElement() + && "timeCycle".equalsIgnoreCase(xtr.getLocalName())) { + addTimerEvent(startEvent, xtr.getLocalName(), xtr.getElementText()); + + } else if (xtr.isEndElement() + && "startEvent".equalsIgnoreCase(xtr.getLocalName())) { + readyWithStartEvent = true; + } + } + } catch (Exception e) { + } + return startEvent; + } + + private void addTimerEvent(StartEvent startEvent, String type, String value) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(value); + if ("timeDuration".equalsIgnoreCase(type)) { + eventDef.setTimeDuration(expression); + } else if ("timeDate".equalsIgnoreCase(type)) { + eventDef.setTimeDate(expression); + } else { + eventDef.setTimeCycle(expression); + } + if (startEvent.getEventDefinitions().size() == 0) { + startEvent.getEventDefinitions().add(eventDef); + } else { + startEvent.getEventDefinitions().set(0, eventDef); + } + } + + private void parseFormProperty(FormProperty property, XMLStreamReader xtr) { + if (xtr.getAttributeValue(null, "id") != null) { + property.setId(xtr.getAttributeValue(null, "id")); + } + if (xtr.getAttributeValue(null, "name") != null) { + property.setName(xtr.getAttributeValue(null, "name")); + } + if (xtr.getAttributeValue(null, "type") != null) { + property.setType(xtr.getAttributeValue(null, "type")); + } + if (xtr.getAttributeValue(null, "variable") != null) { + property.setValue(xtr.getAttributeValue(null, "variable")); + } + if (xtr.getAttributeValue(null, "required") != null) { + property.setRequired(Boolean.valueOf(xtr.getAttributeValue(null, + "required"))); + } + if (xtr.getAttributeValue(null, "readable") != null) { + property.setReadable(Boolean.valueOf(xtr.getAttributeValue(null, + "readable"))); + } + if (xtr.getAttributeValue(null, "writable") != null) { + property.setWriteable(Boolean.valueOf(xtr.getAttributeValue(null, + "writable"))); + } + + boolean readyWithFormProperty = false; + try { + while (readyWithFormProperty == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "value".equalsIgnoreCase(xtr.getLocalName())) { + FormValue value = Bpmn2Factory.eINSTANCE.createFormValue(); + value.setValueId(xtr.getAttributeValue(null, "id")); + value.setValueName(xtr.getAttributeValue(null, "name")); + property.getFormValues().add(value); + + } else if (xtr.isEndElement() + && "formProperty".equalsIgnoreCase(xtr.getLocalName())) { + readyWithFormProperty = true; + } + } + } catch (Exception e) { + } + } + + private void parseMultiInstanceDef( + MultiInstanceLoopCharacteristics multiInstanceDef, XMLStreamReader xtr) { + if (xtr.getAttributeValue(null, "isSequential") != null) { + multiInstanceDef.setIsSequential(Boolean.valueOf(xtr.getAttributeValue( + null, "isSequential"))); + } + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "collection") != null) { + multiInstanceDef.setInputDataItem(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "collection")); + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "elementVariable") != null) { + multiInstanceDef.setElementVariable(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "elementVariable")); + } + + boolean readyWithMultiInstance = false; + try { + while (readyWithMultiInstance == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "loopCardinality".equalsIgnoreCase(xtr.getLocalName())) { + multiInstanceDef.setLoopCardinality(xtr.getElementText()); + + } else if (xtr.isStartElement() + && "loopDataInputRef".equalsIgnoreCase(xtr.getLocalName())) { + multiInstanceDef.setInputDataItem(xtr.getElementText()); + + } else if (xtr.isStartElement() + && "inputDataItem".equalsIgnoreCase(xtr.getLocalName())) { + if (xtr.getAttributeValue(null, "name") != null) { + multiInstanceDef.setElementVariable(xtr.getAttributeValue(null, + "name")); + } + + } else if (xtr.isStartElement() + && "completionCondition".equalsIgnoreCase(xtr.getLocalName())) { + multiInstanceDef.setCompletionCondition(xtr.getElementText()); + + } else if (xtr.isEndElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + readyWithMultiInstance = true; + } + } + } catch (Exception e) { + } + } + + private EndEvent parseEndEvent(XMLStreamReader xtr) { + EndEvent endEvent = Bpmn2Factory.eINSTANCE.createEndEvent(); + endEvent.setName("End"); + boolean readyWithEndEvent = false; + try { + while (readyWithEndEvent == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "errorEventDefinition".equalsIgnoreCase(xtr.getLocalName())) { + ErrorEventDefinition errorDef = Bpmn2Factory.eINSTANCE + .createErrorEventDefinition(); + endEvent.getEventDefinitions().add(errorDef); + if (xtr.getAttributeValue(null, "errorRef") != null) { + errorDef.setErrorCode(xtr.getAttributeValue(null, "errorRef")); + } + + } else if (xtr.isEndElement() + && "endEvent".equalsIgnoreCase(xtr.getLocalName())) { + readyWithEndEvent = true; + } + } + } catch (Exception e) { + } + return endEvent; + } + + private SubProcess parseSubProcess(XMLStreamReader xtr) { + SubProcess subProcess = Bpmn2Factory.eINSTANCE.createSubProcess(); + String name = xtr.getAttributeValue(null, "name"); + if (name != null) { + subProcess.setName(name); + } else { + subProcess.setName(xtr.getAttributeValue(null, "id")); + } + subProcess.setAsynchronous(parseAsync(xtr)); + return subProcess; + } + + private ExclusiveGateway parseExclusiveGateway(XMLStreamReader xtr) { + ExclusiveGateway exclusiveGateway = Bpmn2Factory.eINSTANCE + .createExclusiveGateway(); + String name = xtr.getAttributeValue(null, "name"); + if (name != null) { + exclusiveGateway.setName(name); + } else { + exclusiveGateway.setName(xtr.getAttributeValue(null, "id")); + } + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(exclusiveGateway, + xtr.getAttributeValue(null, "default")); + } + return exclusiveGateway; + } + + private InclusiveGateway parseInclusiveGateway(XMLStreamReader xtr) { + InclusiveGateway inclusiveGateway = Bpmn2Factory.eINSTANCE + .createInclusiveGateway(); + String name = xtr.getAttributeValue(null, "name"); + if (name != null) { + inclusiveGateway.setName(name); + } else { + inclusiveGateway.setName(xtr.getAttributeValue(null, "id")); + } + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(inclusiveGateway, + xtr.getAttributeValue(null, "default")); + } + return inclusiveGateway; + } + + private ParallelGateway parseParallelGateway(XMLStreamReader xtr) { + ParallelGateway parallelGateway = Bpmn2Factory.eINSTANCE + .createParallelGateway(); + parallelGateway.setName(xtr.getAttributeValue(null, "name")); + return parallelGateway; + } + + private SequenceFlowModel parseSequenceFlow(XMLStreamReader xtr) { + + SequenceFlowModel sequenceFlow = new SequenceFlowModel(); + sequenceFlow.sourceRef = xtr.getAttributeValue(null, "sourceRef"); + sequenceFlow.targetRef = xtr.getAttributeValue(null, "targetRef"); + sequenceFlow.id = xtr.getAttributeValue(null, "id"); + FormalExpression conditionValue = parseSequenceFlowCondition(xtr, + sequenceFlow); + sequenceFlow.conditionExpression = conditionValue; + return sequenceFlow; + } + + private static FormalExpression parseSequenceFlowCondition( + XMLStreamReader xtr, SequenceFlowModel sequenceFlow) { + FormalExpression condition = null; + if (xtr.getAttributeValue(null, "name") != null + && xtr.getAttributeValue(null, "name").contains("${")) { + condition = Bpmn2Factory.eINSTANCE.createFormalExpression(); + condition.setBody(xtr.getAttributeValue(null, "name")); + } + boolean readyWithSequenceFlow = false; + try { + while (readyWithSequenceFlow == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "conditionExpression".equalsIgnoreCase(xtr.getLocalName())) { + condition = Bpmn2Factory.eINSTANCE.createFormalExpression(); + condition.setBody(xtr.getElementText()); + + } else if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + sequenceFlow.listenerList.addAll(parseListeners(xtr)); + + } else if (xtr.isEndElement() + && "sequenceFlow".equalsIgnoreCase(xtr.getLocalName())) { + readyWithSequenceFlow = true; + } + } + } catch (Exception e) { + } + return condition; + } + + private UserTask parseUserTask(XMLStreamReader xtr) { + UserTask userTask = null; + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "formKey") != null) { + String[] formTypes = PreferencesUtil + .getStringArray(Preferences.ALFRESCO_FORMTYPES_USERTASK); + for (String form : formTypes) { + if (form.equals(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "formKey"))) { + userTask = Bpmn2Factory.eINSTANCE.createAlfrescoUserTask(); + } + } + } + if (userTask == null) { + userTask = Bpmn2Factory.eINSTANCE.createUserTask(); + } + + userTask.setName(xtr.getAttributeValue(null, "name")); + userTask.setAsynchronous(parseAsync(xtr)); + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "dueDate") != null) { + userTask.setDueDate(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "dueDate")); + } + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "assignee") != null) { + String assignee = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "assignee"); + userTask.setAssignee(assignee); + + } else if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "candidateUsers") != null) { + String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "candidateUsers"); + String[] expressionList = null; + if (expression.contains(";")) { + expressionList = expression.split(";"); + } else { + expressionList = new String[] { expression }; + } + for (String user : expressionList) { + CandidateUser candidateUser = Bpmn2Factory.eINSTANCE + .createCandidateUser(); + candidateUser.setUser(user); + userTask.getCandidateUsers().add(candidateUser); + } + + } else if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "candidateGroups") != null) { + String expression = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "candidateGroups"); + String[] expressionList = null; + if (expression.contains(";")) { + expressionList = expression.split(";"); + } else { + expressionList = new String[] { expression }; + } + for (String group : expressionList) { + CandidateGroup candidateGroup = Bpmn2Factory.eINSTANCE + .createCandidateGroup(); + candidateGroup.setGroup(group); + userTask.getCandidateGroups().add(candidateGroup); + } + } + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "formKey") != null) { + userTask.setFormKey(xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "formKey")); + } + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "priority") != null) { + Integer priorityValue = null; + try { + priorityValue = Integer.valueOf(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "priority")); + } catch (Exception e) { + } + userTask.setPriority(priorityValue); + } + + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(userTask, xtr.getAttributeValue(null, "default")); + } + + boolean readyWithUserTask = false; + try { + String assignmentType = null; + ActivitiListener listener = null; + while (readyWithUserTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "humanPerformer".equalsIgnoreCase(xtr.getLocalName())) { + assignmentType = "humanPerformer"; + + } else if (xtr.isStartElement() + && "potentialOwner".equalsIgnoreCase(xtr.getLocalName())) { + assignmentType = "potentialOwner"; + + } else if (xtr.isStartElement() + && "formalExpression".equalsIgnoreCase(xtr.getLocalName())) { + if ("potentialOwner".equals(assignmentType)) { + List assignmentList = new ArrayList(); + String assignmentText = xtr.getElementText(); + if (assignmentText.contains(",")) { + String[] assignmentArray = assignmentText.split(","); + assignmentList = Arrays.asList(assignmentArray); + } else { + assignmentList.add(assignmentText); + } + for (String assignmentValue : assignmentList) { + if (assignmentValue == null) + continue; + assignmentValue = assignmentValue.trim(); + if (assignmentValue.length() == 0) + continue; + + if (assignmentValue.trim().startsWith("user(")) { + CandidateUser user = Bpmn2Factory.eINSTANCE + .createCandidateUser(); + user.setUser(assignmentValue); + userTask.getCandidateUsers().add(user); + + } else { + CandidateGroup group = Bpmn2Factory.eINSTANCE + .createCandidateGroup(); + group.setGroup(assignmentValue); + userTask.getCandidateGroups().add(group); + } + } + + } else { + userTask.setAssignee(xtr.getElementText()); + } + + } else if (xtr.isStartElement() && ("taskListener".equalsIgnoreCase(xtr.getLocalName()))) { + + if (xtr.getAttributeValue(null, "class") != null + && "org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" + .equals(xtr.getAttributeValue(null, "class")) + || "org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" + .equals(xtr.getAttributeValue(null, "class"))) { + + listener = Bpmn2Factory.eINSTANCE.createActivitiListener(); + listener.setEvent(xtr.getAttributeValue(null, "event")); + listener.setImplementationType(ALFRESCO_TYPE); + boolean readyWithAlfrescoType = false; + while (readyWithAlfrescoType == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() && "field".equalsIgnoreCase(xtr.getLocalName())) { + String script = getFieldExtensionValue(xtr); + if (script != null && script.length() > 0) { + listener.setImplementation(script); + } + readyWithAlfrescoType = true; + } else if (xtr.isEndElement() && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + readyWithAlfrescoType = true; + readyWithUserTask = true; + } + } + } else { + listener = parseListener(xtr); + } + userTask.getActivitiListeners().add(listener); + + } else if (xtr.isStartElement() && "field".equalsIgnoreCase(xtr.getLocalName())) { + listener.getFieldExtensions().add(parseFieldExtension(xtr)); + + } else if (xtr.isStartElement() + && "formProperty".equalsIgnoreCase(xtr.getLocalName())) { + FormProperty property = Bpmn2Factory.eINSTANCE.createFormProperty(); + userTask.getFormProperties().add(property); + parseFormProperty(property, xtr); + + } else if (xtr.isStartElement() + && "documentation".equalsIgnoreCase(xtr.getLocalName())) { + + String docText = xtr.getElementText(); + if(StringUtils.isEmpty(docText) == false) { + Documentation documentation = Bpmn2Factory.eINSTANCE.createDocumentation(); + documentation.setText(docText); + userTask.getDocumentation().add(documentation); + } + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + userTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "userTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithUserTask = true; + } + } + } catch (Exception e) { + } + return userTask; + } + + private ScriptTask parseScriptTask(XMLStreamReader xtr) { + ScriptTask scriptTask = Bpmn2Factory.eINSTANCE.createScriptTask(); + scriptTask.setName(xtr.getAttributeValue(null, "name")); + scriptTask.setScriptFormat(xtr.getAttributeValue(null, "scriptFormat")); + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(scriptTask, xtr.getAttributeValue(null, "default")); + } + scriptTask.setAsynchronous(parseAsync(xtr)); + boolean readyWithScriptTask = false; + try { + while (readyWithScriptTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "script".equalsIgnoreCase(xtr.getLocalName())) { + scriptTask.setScript(xtr.getElementText()); + + } else if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + scriptTask.getActivitiListeners().addAll(parseListeners(xtr)); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + scriptTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "scriptTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithScriptTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return scriptTask; + } + + private MailTask parseMailTask(XMLStreamReader xtr) { + MailTask mailTask = Bpmn2Factory.eINSTANCE.createMailTask(); + mailTask.setName(xtr.getAttributeValue(null, "name")); + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(mailTask, xtr.getAttributeValue(null, "default")); + } + mailTask.setAsynchronous(parseAsync(xtr)); + boolean readyWithServiceTask = false; + try { + while (readyWithServiceTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + fillExtensionsForMailTask(xtr, mailTask); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + mailTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "serviceTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithServiceTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return mailTask; + } + + private Task parseAlfrescoScriptTask(XMLStreamReader xtr) { + String name = xtr.getAttributeValue(null, "name"); + String defaultValue = xtr.getAttributeValue(null, "default"); + boolean async = parseAsync(xtr); + List fieldList = new ArrayList(); + boolean readyWithExtensions = false; + ActivitiListener listener = null; + Task task = null; + MultiInstanceLoopCharacteristics multiInstanceDef = null; + List listenerList = new ArrayList(); + try { + while (readyWithExtensions == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + FieldModel field = parseFieldModel(xtr); + fieldList.add(field); + + } else if (xtr.isStartElement() + && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + if (fieldList.size() > 0) { + task = fillAlfrescoScriptTaskElements(fieldList); + fieldList = new ArrayList(); + } + listener = parseListener(xtr); + listenerList.add(listener); + + } else if (xtr.isEndElement() + && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + if (fieldList.size() > 0) { + fillListenerWithFields(listener, fieldList); + fieldList = new ArrayList(); + } + listenerList.add(listener); + + } else if (xtr.isEndElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + if (fieldList.size() > 0) { + task = fillAlfrescoScriptTaskElements(fieldList); + } + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "serviceTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithExtensions = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + if (task == null) { + return null; + } + + task.setName(name); + task.setAsynchronous(async); + + if (defaultValue != null) { + defaultFlowMap.put(task, xtr.getAttributeValue(null, "default")); + } + + if (multiInstanceDef != null) { + task.setLoopCharacteristics(multiInstanceDef); + } + + if (listenerList.size() > 0) { + task.getActivitiListeners().addAll(listenerList); + } + + return task; + } + + private static FieldModel parseFieldModel(XMLStreamReader xtr) { + FieldModel field = new FieldModel(); + field.name = xtr.getAttributeValue(null, "name"); + field.value = getFieldExtensionValue(xtr); + return field; + } + + private Task fillAlfrescoScriptTaskElements(List fieldList) { + if (fieldList == null || fieldList.size() == 0) + return null; + boolean isMailScript = false; + String mailScript = null; + for (FieldModel field : fieldList) { + if ("script".equalsIgnoreCase(field.name) && isMailScript(field.value)) { + isMailScript = true; + mailScript = field.value; + } + } + Task task = null; + + if (isMailScript == true) { + AlfrescoMailTask mailTask = Bpmn2Factory.eINSTANCE + .createAlfrescoMailTask(); + String value = getMailParamValue(mailScript, "mail.parameters.to"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setTo(value); + } + value = getMailParamValue(mailScript, "mail.parameters.to_many"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setToMany(value); + } + value = getMailParamValue(mailScript, "mail.parameters.subject"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setSubject(value); + } + value = getMailParamValue(mailScript, "mail.parameters.from"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setFrom(value); + } + value = getMailParamValue(mailScript, "mail.parameters.template"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setTemplate(value); + } + value = getMailParamValue(mailScript, "mail.parameters.template_model"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setTemplateModel(value); + } + value = getMailParamValue(mailScript, "mail.parameters.text"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setText(value); + } + value = getMailParamValue(mailScript, "mail.parameters.html"); + if (StringUtils.isNotEmpty(value)) { + mailTask.setHtml(value); + } + task = mailTask; + + } else { + + AlfrescoScriptTask scriptTask = Bpmn2Factory.eINSTANCE + .createAlfrescoScriptTask(); + for (FieldModel field : fieldList) { + if ("script".equalsIgnoreCase(field.name)) { + scriptTask.setScript(field.value); + } else if ("runAs".equalsIgnoreCase(field.name)) { + scriptTask.setRunAs(field.value); + } else if ("scriptProcessor".equalsIgnoreCase(field.name)) { + scriptTask.setScriptProcessor(field.value); + } + } + task = scriptTask; + } + return task; + } + + private String getMailParamValue(String mailScript, String searchString) { + int index = mailScript.indexOf(searchString); + if (index > -1) { + int startIndex = mailScript.indexOf("=", index); + int endIndex = mailScript.indexOf(";", index); + return mailScript.substring(startIndex + 1, endIndex).trim(); + } else { + return null; + } + } + + private boolean isMailScript(String script) { + boolean isMailScript = false; + if (script != null) { + if (script.contains("var mail = actions.create(\"mail\");") + && script.contains("mail.execute(bpm_package);")) { + + isMailScript = true; + } + } + return isMailScript; + } + + private void fillListenerWithFields(ActivitiListener listener, + List fieldList) { + if (fieldList == null || fieldList.size() == 0) + return; + for (FieldModel field : fieldList) { + FieldExtension extension = Bpmn2Factory.eINSTANCE.createFieldExtension(); + extension.setFieldname(field.name); + extension.setExpression(field.value); + listener.getFieldExtensions().add(extension); + } + } + + private ServiceTask parseServiceTask(XMLStreamReader xtr) { + ServiceTask serviceTask = Bpmn2Factory.eINSTANCE.createServiceTask(); + serviceTask.setName(xtr.getAttributeValue(null, "name")); + serviceTask.setAsynchronous(parseAsync(xtr)); + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "class") != null) { + serviceTask.setImplementationType(CLASS_TYPE); + serviceTask.setImplementation(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "class")); + } else if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "expression") != null) { + serviceTask.setImplementationType(EXPRESSION_TYPE); + serviceTask.setImplementation(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "expression")); + } else if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "delegateExpression") != null) { + serviceTask.setImplementationType(DELEGATE_EXPRESSION_TYPE); + serviceTask.setImplementation(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "delegateExpression")); + } + + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "resultVariableName") != null) { + serviceTask.setResultVariableName(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "resultVariableName")); + } + + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(serviceTask, xtr.getAttributeValue(null, "default")); + } + + boolean readyWithServiceTask = false; + try { + while (readyWithServiceTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + fillExtensionsForServiceTask(xtr, serviceTask); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + serviceTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isStartElement() + && "documentation".equalsIgnoreCase(xtr.getLocalName())) { + + String docText = xtr.getElementText(); + if(StringUtils.isEmpty(docText) == false) { + Documentation documentation = Bpmn2Factory.eINSTANCE.createDocumentation(); + documentation.setText(docText); + serviceTask.getDocumentation().add(documentation); + } + + } else if (xtr.isEndElement() + && "serviceTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithServiceTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return serviceTask; + } + + private ServiceTask parseTask(XMLStreamReader xtr) { + ServiceTask serviceTask = Bpmn2Factory.eINSTANCE.createServiceTask(); + serviceTask.setName(xtr.getAttributeValue(null, "name")); + serviceTask.setAsynchronous(parseAsync(xtr)); + return serviceTask; + } + + private static void fillExtensionsForServiceTask(XMLStreamReader xtr, + ServiceTask serviceTask) { + List extensionList = new ArrayList(); + boolean readyWithExtensions = false; + try { + ActivitiListener listener = null; + while (readyWithExtensions == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + FieldExtension extension = parseFieldExtension(xtr); + extensionList.add(extension); + + } else if (xtr.isStartElement() + && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + if (extensionList.size() > 0) { + serviceTask.getFieldExtensions().addAll(extensionList); + extensionList = new ArrayList(); + } + listener = parseListener(xtr); + serviceTask.getActivitiListeners().add(listener); + + } else if (xtr.isEndElement() + && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + if (extensionList.size() > 0) { + listener.getFieldExtensions().addAll(extensionList); + extensionList = new ArrayList(); + } + serviceTask.getActivitiListeners().add(listener); + + } else if (xtr.isEndElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + if (extensionList.size() > 0) { + serviceTask.getFieldExtensions().addAll(extensionList); + } + readyWithExtensions = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void fillExtensionsForMailTask(XMLStreamReader xtr, + MailTask mailTask) { + boolean readyWithExtensions = false; + try { + while (readyWithExtensions == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + String name = xtr.getAttributeValue(null, "name"); + if ("to".equalsIgnoreCase(name)) { + mailTask.setTo(getFieldExtensionValue(xtr)); + } else if ("from".equalsIgnoreCase(name)) { + mailTask.setFrom(getFieldExtensionValue(xtr)); + } else if ("cc".equalsIgnoreCase(name)) { + mailTask.setCc(getFieldExtensionValue(xtr)); + } else if ("bcc".equalsIgnoreCase(name)) { + mailTask.setBcc(getFieldExtensionValue(xtr)); + } else if ("subject".equalsIgnoreCase(name)) { + mailTask.setSubject(getFieldExtensionValue(xtr)); + } else if ("html".equalsIgnoreCase(name)) { + mailTask.setHtml(getFieldExtensionValue(xtr)); + } else if ("text".equalsIgnoreCase(name)) { + mailTask.setText(getFieldExtensionValue(xtr)); + } + } else if (xtr.isEndElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + readyWithExtensions = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void fillExtensionsForCallActivity(XMLStreamReader xtr, CallActivity callActivity) { + List extensionList = new ArrayList(); + boolean readyWithExtensions = false; + try { + ActivitiListener listener = null; + while(readyWithExtensions == false && xtr.hasNext()) { + xtr.next(); + if(xtr.isStartElement() && "field".equalsIgnoreCase(xtr.getLocalName())) { + FieldExtension extension = parseFieldExtension(xtr); + extensionList.add(extension); + + } else if(xtr.isStartElement() && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + listener = parseListener(xtr); + callActivity.getActivitiListeners().add(listener); + + } else if(xtr.isEndElement() && "executionListener".equalsIgnoreCase(xtr.getLocalName())) { + if(extensionList.size() > 0) { + listener.getFieldExtensions().addAll(extensionList); + extensionList = new ArrayList(); + } + callActivity.getActivitiListeners().add(listener); + + } else if(xtr.isStartElement() && "in".equalsIgnoreCase(xtr.getLocalName())) { + String source = xtr.getAttributeValue(null, "source"); + String target = xtr.getAttributeValue(null, "target"); + if(source != null && target != null) { + IOParameter parameter = Bpmn2Factory.eINSTANCE.createIOParameter(); + parameter.setSource(source); + parameter.setTarget(target); + callActivity.getInParameters().add(parameter); + } + + } else if(xtr.isStartElement() && "out".equalsIgnoreCase(xtr.getLocalName())) { + String source = xtr.getAttributeValue(null, "source"); + String target = xtr.getAttributeValue(null, "target"); + if(source != null && target != null) { + IOParameter parameter = Bpmn2Factory.eINSTANCE.createIOParameter(); + parameter.setSource(source); + parameter.setTarget(target); + callActivity.getOutParameters().add(parameter); + } + + } else if(xtr.isEndElement() && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + readyWithExtensions = true; + } + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + private static FieldExtension parseFieldExtension(XMLStreamReader xtr) { + FieldExtension extension = Bpmn2Factory.eINSTANCE.createFieldExtension(); + extension.setFieldname(xtr.getAttributeValue(null, "name")); + extension.setExpression(getFieldExtensionValue(xtr)); + return extension; + } + + private static String getFieldExtensionValue(XMLStreamReader xtr) { + if (xtr.getAttributeValue(null, "stringValue") != null) { + return xtr.getAttributeValue(null, "stringValue"); + + } else if (xtr.getAttributeValue(null, "expression") != null) { + return xtr.getAttributeValue(null, "expression"); + + } else { + boolean readyWithFieldExtension = false; + try { + while (readyWithFieldExtension == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "string".equalsIgnoreCase(xtr.getLocalName())) { + return readStringWithLineBreak(xtr.getElementText()); + + } else if (xtr.isStartElement() + && "expression".equalsIgnoreCase(xtr.getLocalName())) { + return readStringWithLineBreak(xtr.getElementText().trim()); + + } else if (xtr.isEndElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + return null; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + private static String readStringWithLineBreak(String value) { + if (value == null) + return null; + List lineList = new ArrayList(); + int startIndex = 0; + int endIndex = 0; + for (int i = 0; i < value.length(); i++) { + if (value.charAt(i) == '\n') { + endIndex = i; + lineList.add(value.substring(startIndex, endIndex).trim()); + startIndex = i + 1; + } + } + StringBuilder lineBuilder = new StringBuilder(); + for (String string : lineList) { + if (lineBuilder.length() > 0) { + lineBuilder.append("\n"); + } + lineBuilder.append(string); + } + return lineBuilder.toString(); + } + + private static List parseListeners(XMLStreamReader xtr) { + List listenerList = new ArrayList(); + boolean readyWithListener = false; + try { + ActivitiListener listener = null; + while (readyWithListener == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && ("executionListener".equalsIgnoreCase(xtr.getLocalName()) || "taskListener" + .equalsIgnoreCase(xtr.getLocalName()))) { + + if (xtr.getAttributeValue(null, "class") != null + && "org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener" + .equals(xtr.getAttributeValue(null, "class")) + || "org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener" + .equals(xtr.getAttributeValue(null, "class"))) { + + listener = Bpmn2Factory.eINSTANCE.createActivitiListener(); + listener.setEvent(xtr.getAttributeValue(null, "event")); + listener.setImplementationType(ALFRESCO_TYPE); + boolean readyWithAlfrescoType = false; + while (readyWithAlfrescoType == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + String script = getFieldExtensionValue(xtr); + if (script != null && script.length() > 0) { + listener.setImplementation(script); + } + readyWithAlfrescoType = true; + } else if (xtr.isEndElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + readyWithAlfrescoType = true; + readyWithListener = true; + } + } + } else { + listener = parseListener(xtr); + } + listenerList.add(listener); + + } else if (xtr.isStartElement() + && "field".equalsIgnoreCase(xtr.getLocalName())) { + listener.getFieldExtensions().add(parseFieldExtension(xtr)); + } else if (xtr.isEndElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + readyWithListener = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return listenerList; + } + + private static ActivitiListener parseListener(XMLStreamReader xtr) { + ActivitiListener listener = Bpmn2Factory.eINSTANCE.createActivitiListener(); + if (xtr.getAttributeValue(null, "class") != null) { + listener.setImplementation(xtr.getAttributeValue(null, "class")); + listener.setImplementationType(CLASS_TYPE); + } else if (xtr.getAttributeValue(null, "expression") != null) { + listener.setImplementation(xtr.getAttributeValue(null, "expression")); + listener.setImplementationType(EXPRESSION_TYPE); + } + listener.setEvent(xtr.getAttributeValue(null, "event")); + return listener; + } + + private ManualTask parseManualTask(XMLStreamReader xtr) { + ManualTask manualTask = Bpmn2Factory.eINSTANCE.createManualTask(); + manualTask.setName(xtr.getAttributeValue(null, "name")); + manualTask.setAsynchronous(parseAsync(xtr)); + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(manualTask, xtr.getAttributeValue(null, "default")); + } + boolean readyWithTask = false; + try { + while (readyWithTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + manualTask.getActivitiListeners().addAll(parseListeners(xtr)); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + manualTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "manualTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return manualTask; + } + + private CallActivity parseCallActivity(XMLStreamReader xtr) { + CallActivity callActivity = Bpmn2Factory.eINSTANCE.createCallActivity(); + callActivity.setName(xtr.getAttributeValue(null, "name")); + callActivity.setAsynchronous(parseAsync(xtr)); + if (xtr.getAttributeValue(null, "calledElement") != null + && xtr.getAttributeValue(null, "calledElement").length() > 0) { + callActivity.setCalledElement(xtr + .getAttributeValue(null, "calledElement")); + } + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(callActivity, xtr.getAttributeValue(null, "default")); + } + boolean readyWithTask = false; + try { + while (readyWithTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + + fillExtensionsForCallActivity(xtr, callActivity); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + callActivity.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "callActivity".equalsIgnoreCase(xtr.getLocalName())) { + readyWithTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return callActivity; + } + + private ReceiveTask parseReceiveTask(XMLStreamReader xtr) { + ReceiveTask receiveTask = Bpmn2Factory.eINSTANCE.createReceiveTask(); + receiveTask.setName(xtr.getAttributeValue(null, "name")); + receiveTask.setAsynchronous(parseAsync(xtr)); + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(receiveTask, xtr.getAttributeValue(null, "default")); + } + boolean readyWithTask = false; + try { + while (readyWithTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + receiveTask.getActivitiListeners().addAll(parseListeners(xtr)); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + receiveTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "receiveTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return receiveTask; + } + + private BusinessRuleTask parseBusinessRuleTask(XMLStreamReader xtr) { + BusinessRuleTask businessRuleTask = Bpmn2Factory.eINSTANCE + .createBusinessRuleTask(); + businessRuleTask.setName(xtr.getAttributeValue(null, "name")); + businessRuleTask.setAsynchronous(parseAsync(xtr)); + if (xtr.getAttributeValue(null, "default") != null) { + defaultFlowMap.put(businessRuleTask, + xtr.getAttributeValue(null, "default")); + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "rules") != null) { + String ruleNames = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "rules"); + if (ruleNames != null && ruleNames.length() > 0) { + businessRuleTask.getRuleNames().clear(); + if (ruleNames.contains(",") == false) { + businessRuleTask.getRuleNames().add(ruleNames); + } else { + String[] ruleNameList = ruleNames.split(","); + for (String rule : ruleNameList) { + businessRuleTask.getRuleNames().add(rule); + } + } + } + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "inputVariableNames") != null) { + String inputNames = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "inputVariableNames"); + if (inputNames != null && inputNames.length() > 0) { + businessRuleTask.getInputVariables().clear(); + if (inputNames.contains(",") == false) { + businessRuleTask.getInputVariables().add(inputNames); + } else { + String[] inputNamesList = inputNames.split(","); + for (String input : inputNamesList) { + businessRuleTask.getInputVariables().add(input); + } + } + } + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "exclude") != null) { + businessRuleTask.setExclude(Boolean.valueOf(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "exclude"))); + } + if (xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, + "resultVariableName") != null) { + businessRuleTask.setResultVariableName(xtr.getAttributeValue( + ACTIVITI_EXTENSIONS_NAMESPACE, "resultVariableName")); + } + + boolean readyWithTask = false; + try { + while (readyWithTask == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "extensionElements".equalsIgnoreCase(xtr.getLocalName())) { + businessRuleTask.getActivitiListeners().addAll(parseListeners(xtr)); + + } else if (xtr.isStartElement() + && "multiInstanceLoopCharacteristics".equalsIgnoreCase(xtr + .getLocalName())) { + MultiInstanceLoopCharacteristics multiInstanceDef = Bpmn2Factory.eINSTANCE + .createMultiInstanceLoopCharacteristics(); + businessRuleTask.setLoopCharacteristics(multiInstanceDef); + parseMultiInstanceDef(multiInstanceDef, xtr); + + } else if (xtr.isEndElement() + && "businessRuleTask".equalsIgnoreCase(xtr.getLocalName())) { + readyWithTask = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return businessRuleTask; + } + + private BoundaryEventModel parseBoundaryEvent(XMLStreamReader xtr) { + BoundaryEvent boundaryEvent = Bpmn2Factory.eINSTANCE.createBoundaryEvent(); + boundaryEvent.setName(xtr.getAttributeValue(null, "name")); + + if(xtr.getAttributeValue(null, "cancelActivity") != null) { + String cancelActivity = xtr.getAttributeValue(null, "cancelActivity"); + if("true".equalsIgnoreCase(cancelActivity)) { + boundaryEvent.setCancelActivity(true); + } else { + boundaryEvent.setCancelActivity(false); + } + } + + BoundaryEventModel model = new BoundaryEventModel(); + model.boundaryEvent = boundaryEvent; + model.attachedRef = xtr.getAttributeValue(null, "attachedToRef"); + boolean readyWithEvent = false; + try { + while (readyWithEvent == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "timerEventDefinition".equalsIgnoreCase(xtr.getLocalName())) { + model.type = BoundaryEventModel.TIMEEVENT; + } else if (xtr.isStartElement() + && "errorEventDefinition".equalsIgnoreCase(xtr.getLocalName())) { + model.type = BoundaryEventModel.ERROREVENT; + ErrorEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createErrorEventDefinition(); + if (xtr.getAttributeValue(null, "errorRef") != null) { + eventDef.setErrorCode(xtr.getAttributeValue(null, "errorRef")); + } + boundaryEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isStartElement() + && "timeDuration".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeDuration(expression); + boundaryEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isStartElement() + && "timeDate".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeDate(expression); + boundaryEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isStartElement() + && "timeCycle".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeCycle(expression); + boundaryEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isEndElement() + && "boundaryEvent".equalsIgnoreCase(xtr.getLocalName())) { + readyWithEvent = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return model; + } + + private boolean parseAsync(XMLStreamReader xtr) { + boolean async = false; + String asyncString = xtr.getAttributeValue(ACTIVITI_EXTENSIONS_NAMESPACE, "async"); + if ("true".equalsIgnoreCase(asyncString)) { + async = true; + } + return async; + } + + private IntermediateCatchEvent parseIntermediateCatchEvent(XMLStreamReader xtr) { + IntermediateCatchEvent catchEvent = Bpmn2Factory.eINSTANCE.createIntermediateCatchEvent(); + catchEvent.setName(xtr.getAttributeValue(null, "name")); + + boolean readyWithEvent = false; + try { + while (readyWithEvent == false && xtr.hasNext()) { + xtr.next(); + if (xtr.isStartElement() + && "timeDuration".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeDuration(expression); + catchEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isStartElement() + && "timeDate".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeDate(expression); + catchEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isStartElement() + && "timeCycle".equalsIgnoreCase(xtr.getLocalName())) { + TimerEventDefinition eventDef = Bpmn2Factory.eINSTANCE + .createTimerEventDefinition(); + FormalExpression expression = Bpmn2Factory.eINSTANCE + .createFormalExpression(); + expression.setBody(xtr.getElementText()); + eventDef.setTimeCycle(expression); + catchEvent.getEventDefinitions().add(eventDef); + readyWithEvent = true; + + } else if (xtr.isEndElement() + && "intermediateCatchEvent".equalsIgnoreCase(xtr.getLocalName())) { + readyWithEvent = true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return catchEvent; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/FieldModel.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/FieldModel.java new file mode 100644 index 0000000..c4eac77 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/FieldModel.java @@ -0,0 +1,10 @@ +package org.activiti.designer.eclipse.bpmn; + +/** + * @author Tijs Rademakers + */ +public class FieldModel { + + public String name; + public String value; +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/GraphicInfo.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/GraphicInfo.java new file mode 100644 index 0000000..7989a95 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/GraphicInfo.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmn; + +import org.eclipse.bpmn2.FlowElement; + + +/** + * @author Tijs Rademakers + */ +public class GraphicInfo { + + public int x; + public int y; + public int height; + public int width; + public FlowElement element; + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/SequenceFlowModel.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/SequenceFlowModel.java new file mode 100644 index 0000000..5406541 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmn/SequenceFlowModel.java @@ -0,0 +1,33 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmn; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.bpmn2.ActivitiListener; +import org.eclipse.bpmn2.FormalExpression; + + +/** + * @author Tijs Rademakers + */ +public class SequenceFlowModel { + + public String id; + public String sourceRef; + public String targetRef; + public FormalExpression conditionExpression; + public List listenerList = new ArrayList(); +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/BpmnFileReader.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/BpmnFileReader.java new file mode 100644 index 0000000..2c3a005 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/BpmnFileReader.java @@ -0,0 +1,1081 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmnimport; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; + +import org.activiti.designer.eclipse.bpmn.BpmnParser; +import org.activiti.designer.eclipse.bpmn.GraphicInfo; +import org.activiti.designer.eclipse.bpmn.SequenceFlowModel; +import org.activiti.designer.eclipse.preferences.PreferencesUtil; +import org.activiti.designer.util.preferences.Preferences; +import org.apache.commons.lang.StringUtils; +import org.eclipse.bpmn2.Activity; +import org.eclipse.bpmn2.BoundaryEvent; +import org.eclipse.bpmn2.Bpmn2Factory; +import org.eclipse.bpmn2.BusinessRuleTask; +import org.eclipse.bpmn2.CallActivity; +import org.eclipse.bpmn2.CandidateGroup; +import org.eclipse.bpmn2.CandidateUser; +import org.eclipse.bpmn2.Documentation; +import org.eclipse.bpmn2.EndEvent; +import org.eclipse.bpmn2.ErrorEventDefinition; +import org.eclipse.bpmn2.Event; +import org.eclipse.bpmn2.EventDefinition; +import org.eclipse.bpmn2.ExclusiveGateway; +import org.eclipse.bpmn2.FieldExtension; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.FlowNode; +import org.eclipse.bpmn2.Gateway; +import org.eclipse.bpmn2.InclusiveGateway; +import org.eclipse.bpmn2.MailTask; +import org.eclipse.bpmn2.ManualTask; +import org.eclipse.bpmn2.ParallelGateway; +import org.eclipse.bpmn2.ReceiveTask; +import org.eclipse.bpmn2.ScriptTask; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.StartEvent; +import org.eclipse.bpmn2.SubProcess; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.emf.common.util.EList; +import org.eclipse.graphiti.features.IAddFeature; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.impl.AddConnectionContext; +import org.eclipse.graphiti.features.context.impl.AddContext; +import org.eclipse.graphiti.mm.pictograms.Anchor; +import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.mm.pictograms.Shape; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.graphiti.services.ILinkService; + + +/** + * @author Tijs Rademakers + */ +public class BpmnFileReader { + + private static final int START_X = 30; + private static final int START_Y = 200; + private static final int EVENT_WIDTH = 35; + private static final int EVENT_HEIGHT = 35; + private static final int TASK_WIDTH = 105; + private static final int TASK_HEIGHT = 55; + private static final int GATEWAY_WIDTH = 40; + private static final int GATEWAY_HEIGHT = 40; + private static final int SEQUENCEFLOW_WIDTH = 40; + + private Diagram diagram; + private IFeatureProvider featureProvider; + private String filename; + private InputStream fileStream; + private String processName; + + private BpmnParser bpmnParser = new BpmnParser(); + private Map yMap = new HashMap(); + private List subProcessList = new ArrayList(); + + private boolean useBPMNDI = false; + + public BpmnFileReader(String filename, Diagram diagram, IFeatureProvider featureProvider) { + this.filename = filename; + this.diagram = diagram; + this.featureProvider = featureProvider; + } + + public BpmnFileReader(InputStream fileStream, String processName, Diagram diagram, IFeatureProvider featureProvider) { + this.fileStream = fileStream; + this.processName = processName; + this.diagram = diagram; + this.featureProvider = featureProvider; + } + + public void openStream() { + File bpmnFile = new File(filename); + if(bpmnFile.exists() == false) { + System.out.println("bpmn file does not exist " + filename); + return; + } + processName = filename.substring(filename.lastIndexOf(File.separator) + 1); + processName = processName.substring(0, processName.indexOf(".")); + try { + fileStream = new FileInputStream(bpmnFile); + } catch(Exception e) { + e.printStackTrace(); + } + } + + public void readBpmn() { + try { + XMLInputFactory xif = XMLInputFactory.newInstance(); + InputStreamReader in = new InputStreamReader(fileStream, "UTF-8"); + XMLStreamReader xtr = xif.createXMLStreamReader(in); + bpmnParser.parseBpmn(xtr); + + if(bpmnParser.bpmnList.size() == 0) return; + + org.eclipse.bpmn2.Process process = Bpmn2Factory.eINSTANCE.createProcess(); + String processId = processName.replace(" ", ""); + process.setId(processId); + if(bpmnParser.process != null && StringUtils.isNotEmpty(bpmnParser.process.getName())) { + process.setName(bpmnParser.process.getName()); + } else { + process.setName(processName); + } + if(bpmnParser.process != null && StringUtils.isNotEmpty(bpmnParser.process.getNamespace())) { + process.setNamespace(bpmnParser.process.getNamespace()); + } + + Documentation documentation = null; + if(bpmnParser.process == null || bpmnParser.process.getDocumentation().size() == 0) { + documentation = Bpmn2Factory.eINSTANCE.createDocumentation(); + documentation.setId("documentation_process"); + documentation.setText(""); + } else { + documentation = bpmnParser.process.getDocumentation().get(0); + } + + process.getDocumentation().add(documentation); + + if(bpmnParser.process != null && bpmnParser.process.getExecutionListeners().size() > 0) { + process.getExecutionListeners().addAll(bpmnParser.process.getExecutionListeners()); + } + diagram.eResource().getContents().add(process); + + if(PreferencesUtil.getBooleanPreference(Preferences.IMPORT_USE_BPMNDI) && bpmnParser.bpmdiInfoFound == true) { + useBPMNDI = true; + drawDiagramWithBPMNDI(diagram, featureProvider, bpmnParser.bpmnList, bpmnParser.sequenceFlowList, + bpmnParser.locationMap); + } else { + + List wrongOrderList = createDiagramElements(bpmnParser.bpmnList); + if(wrongOrderList.size() > 0) { + + int counter = 0; + while(wrongOrderList.size() > 0 && counter < 10) { + int sizeBefore = wrongOrderList.size(); + wrongOrderList = createDiagramElements(wrongOrderList); + + if(sizeBefore <= wrongOrderList.size()) { + counter++; + } else { + counter = 0; + } + } + } + drawSequenceFlows(); + } + setFriendlyIds(); + xtr.close(); + in.close(); + fileStream.close(); + + } catch(Exception e) { + e.printStackTrace(); + } + } + + private List createDiagramElements(List flowList) { + SubProcess activeSubProcess = null; + List wrongOrderList = new ArrayList(); + Set boundaryEventList = new HashSet(); + + // look for boundary events + for (FlowElement flowElement : flowList) { + if(flowElement instanceof BoundaryEvent) { + boundaryEventList.add((BoundaryEvent) flowElement); + } + } + + // first look for start event + for (FlowElement startElement : flowList) { + + if(startElement instanceof StartEvent) { + if(activeSubProcess == null || containsFlowElementId(activeSubProcess.getFlowElements(), startElement.getId()) == false) { + GraphicInfo graphicInfo = getNextGraphicInfo(null, startElement, yMap, boundaryEventList); + yMap.put(startElement.getId(), graphicInfo); + addBpmnElementToDiagram(startElement, graphicInfo, diagram); + + processDiagramInSequence(startElement, flowList, activeSubProcess, wrongOrderList, boundaryEventList); + + break; + + } + } + } + return wrongOrderList; + } + + private void processDiagramInSequence(FlowElement previousElement, List flowList, + SubProcess activeSubProcess, List wrongOrderList, Set boundaryEventList) { + + for(SequenceFlowModel sequence : bpmnParser.sequenceFlowList) { + if(sequence.sourceRef != null && sequence.sourceRef.equals(previousElement.getId()) && + sequence.targetRef != null && yMap.containsKey(sequence.targetRef) == false) { + + for (FlowElement flowElement : flowList) { + if(sequence.targetRef.equals(flowElement.getId())) { + + if(multipleIncomingSequenceFlows(flowElement, bpmnParser.sequenceFlowList) > 1) { + try { + getMaxX(flowElement.getId()); + calculateDivergingElementY(flowElement, bpmnParser.sequenceFlowList); + + } catch(FlowSourceNotFoundException e) { + if(activeSubProcess == null || containsFlowElementId(activeSubProcess.getFlowElements(), flowElement.getId()) == false) { + wrongOrderList.add(flowElement); + } + continue; + } + } + + GraphicInfo graphicInfo = getNextGraphicInfo(previousElement, flowElement, yMap, boundaryEventList); + + yMap.put(flowElement.getId(), graphicInfo); + + if(flowElement instanceof SubProcess) { + activeSubProcess = (SubProcess) flowElement; + subProcessList.add(activeSubProcess); + + } else if(activeSubProcess == null || containsFlowElementId(activeSubProcess.getFlowElements(), + flowElement.getId()) == false) { + + addBpmnElementToDiagram(flowElement, graphicInfo, diagram); + } + + processDiagramInSequence(flowElement, flowList, activeSubProcess, wrongOrderList, boundaryEventList); + + if(boundaryEventList.size() > 0 && + (flowElement instanceof SubProcess || flowElement instanceof CallActivity + || flowElement instanceof Task)) { + + if(flowElement instanceof SubProcess || activeSubProcess == null || + containsFlowElementId(activeSubProcess.getFlowElements(), flowElement.getId()) == false) { + + for (BoundaryEvent boundaryEvent : boundaryEventList) { + if(boundaryEvent.getAttachedToRef() != null && boundaryEvent.getAttachedToRef().getId().equals(flowElement.getId())) { + + GraphicInfo boundaryGraphicInfo = getNextGraphicInfo(null, boundaryEvent, yMap, boundaryEventList); + yMap.put(boundaryEvent.getId(), boundaryGraphicInfo); + addBpmnElementToDiagram(boundaryEvent, boundaryGraphicInfo, diagram); + + processDiagramInSequence(boundaryEvent, flowList, activeSubProcess, wrongOrderList, boundaryEventList); + } + } + } + } + + break; + } + } + } + } + } + + private boolean containsFlowElementId(List flowElementList, String id) { + for (FlowElement flowElement : flowElementList) { + if(id.equals(flowElement.getId())) { + return true; + } + } + return false; + } + + private GraphicInfo getNextGraphicInfo(FlowElement sourceFlowElement, FlowElement newFlowElement, + Map yMap, Set boundaryEventList) { + + GraphicInfo graphicInfo = new GraphicInfo(); + GraphicInfo sourceInfo = null; + if(sourceFlowElement != null && yMap.containsKey(sourceFlowElement.getId())) { + sourceInfo = yMap.get(sourceFlowElement.getId()); + if(sourceFlowElement instanceof BoundaryEvent && newFlowElement instanceof Task) { + sourceInfo.x -= 38; + } + } + + int x = 0; + int y = 0; + if(sourceInfo != null) { + x = sourceInfo.x; + y = sourceInfo.y; + + if(sourceFlowElement instanceof BoundaryEvent) { + y += SEQUENCEFLOW_WIDTH + TASK_HEIGHT; + + } else { + + if(multipleOutgoingSequenceFlows(sourceFlowElement, bpmnParser.sequenceFlowList) > 1) { + if(sourceFlowElement instanceof Gateway) { + x += GATEWAY_WIDTH; + } else if(sourceFlowElement instanceof Task) { + x += TASK_WIDTH; + } else if(sourceFlowElement instanceof Event) { + x += EVENT_WIDTH; + } else { + x += TASK_WIDTH; + } + y = calculateDirectElementChildY(sourceFlowElement, newFlowElement.getId(), sourceInfo.y, bpmnParser.sequenceFlowList); + + } else if(sourceFlowElement instanceof Gateway) { + x += GATEWAY_WIDTH; + if(newFlowElement instanceof Task) { + y -= 7; + } else if(newFlowElement instanceof EndEvent) { + y += 3; + } + + } else if(sourceFlowElement instanceof Event) { + x += EVENT_WIDTH; + if(newFlowElement instanceof Task) { + y -= 10; + } + + } else if(sourceFlowElement instanceof SubProcess) { + x += sourceInfo.width; + int height = 0; + if(newFlowElement instanceof Task) { + height = TASK_HEIGHT; + } else if(newFlowElement instanceof Gateway) { + height = GATEWAY_HEIGHT; + } else if(newFlowElement instanceof Event) { + height = EVENT_HEIGHT; + } + y += ((sourceInfo.height / 2) - (height / 2)); + } else { + x += TASK_WIDTH; + } + x += SEQUENCEFLOW_WIDTH; + + if(newFlowElement instanceof EndEvent && sourceFlowElement instanceof Task) { + y += 10; + } + + if(multipleIncomingSequenceFlows(newFlowElement, bpmnParser.sequenceFlowList) > 1) { + + y = calculateDivergingElementY(newFlowElement, bpmnParser.sequenceFlowList); + x = getMaxX(newFlowElement.getId()); + + } else if(newFlowElement instanceof Gateway){ + if(sourceFlowElement instanceof Task) { + y += 7; + } else if(sourceFlowElement instanceof StartEvent) { + y -= 2; + } + } + } + + } else { + x = START_X; + y = START_Y; + } + + graphicInfo.x = x; + graphicInfo.y = y; + + if(newFlowElement instanceof Event) { + graphicInfo.height = EVENT_HEIGHT; + if(newFlowElement instanceof BoundaryEvent) { + BoundaryEvent boundaryEvent = (BoundaryEvent) newFlowElement; + if(boundaryEvent.getAttachedToRef() instanceof SubProcess && yMap.containsKey(boundaryEvent.getAttachedToRef().getId())) { + GraphicInfo attachGraphInfo = yMap.get(boundaryEvent.getAttachedToRef().getId()); + graphicInfo.x = attachGraphInfo.x + attachGraphInfo.width / 2; + graphicInfo.y = attachGraphInfo.y + attachGraphInfo.height - 15; + } else if(yMap.containsKey(boundaryEvent.getAttachedToRef().getId())) { + GraphicInfo attachGraphInfo = yMap.get(boundaryEvent.getAttachedToRef().getId()); + graphicInfo.x = attachGraphInfo.x + TASK_WIDTH - 25; + graphicInfo.y = attachGraphInfo.y + TASK_HEIGHT - 25; + } + } + } else if(newFlowElement instanceof Gateway) { + graphicInfo.height = GATEWAY_HEIGHT; + } else if(newFlowElement instanceof SubProcess) { + int width = 0; + int height = 0; + Map subYMap = new HashMap(); + List subFlowElementList = new ArrayList(); + + // first go for start event + for(FlowElement startElement : ((SubProcess) newFlowElement).getFlowElements()) { + if(startElement instanceof StartEvent) { + GraphicInfo subGraphicInfo = new GraphicInfo(); + subGraphicInfo.height = EVENT_HEIGHT; + subGraphicInfo.x = 20; + subGraphicInfo.y = 50; + subYMap.put(startElement.getId(), subGraphicInfo); + subFlowElementList.add(startElement); + if(subGraphicInfo.x > width) + width = subGraphicInfo.x; + if(subGraphicInfo.y > height) + height = subGraphicInfo.y; + + processSubDiagramInSequence(startElement, (SubProcess) newFlowElement, + subFlowElementList, subYMap, boundaryEventList); + + break; + } + } + + for(String subElementId : subYMap.keySet()) { + GraphicInfo subGraphicInfo = subYMap.get(subElementId); + if(subGraphicInfo.x > width) + width = subGraphicInfo.x; + if(subGraphicInfo.y > height) + height = subGraphicInfo.y; + } + + + graphicInfo.width = width + 80; + graphicInfo.height = height + 40 + TASK_HEIGHT; + + if(yMap.containsKey(sourceFlowElement.getId())) { + GraphicInfo subSourceInfo = yMap.get(sourceFlowElement.getId()); + graphicInfo.y = subSourceInfo.y + (subSourceInfo.height / 2) - (graphicInfo.height / 2); + } + + addBpmnElementToDiagram(newFlowElement, graphicInfo, diagram); + + int differenceInitialStartEventAndSubProcessHeight = (graphicInfo.height / 2) - 50 - (EVENT_HEIGHT / 2); + + ILinkService linkService = Graphiti.getLinkService(); + List pictoList = linkService.getPictogramElements(diagram, (SubProcess) newFlowElement); + if(pictoList != null && pictoList.size() > 0) { + ContainerShape parent = (ContainerShape) pictoList.get(0); + for (FlowElement subFlowElement : subFlowElementList) { + GraphicInfo subInfoElem = subYMap.get(subFlowElement.getId()); + subInfoElem.y += differenceInitialStartEventAndSubProcessHeight; + addBpmnElementToDiagram(subFlowElement, subYMap.get(subFlowElement.getId()), parent); + } + } + + } else { + graphicInfo.height = TASK_HEIGHT; + } + + graphicInfo.element = newFlowElement; + return graphicInfo; + } + + private void processSubDiagramInSequence(FlowElement previousElement, SubProcess subProcess, + List subFlowElementList, Map subYMap, Set boundaryEventList) { + + for(SequenceFlowModel sequence : bpmnParser.sequenceFlowList) { + if(sequence.sourceRef != null && sequence.sourceRef.equals(previousElement.getId()) && + sequence.targetRef != null && subYMap.containsKey(sequence.targetRef) == false) { + + for(FlowElement subFlowElement : subProcess.getFlowElements()) { + if(sequence.targetRef.equals(subFlowElement.getId())) { + FlowElement subSourceElement = sourceRef(subFlowElement.getId(), subYMap); + GraphicInfo subGraphicInfo = getNextGraphicInfo(subSourceElement, subFlowElement, subYMap, boundaryEventList); + if(subGraphicInfo.y < 0) { + subGraphicInfo.y = 0; + } + + subYMap.put(subFlowElement.getId(), subGraphicInfo); + subFlowElementList.add(subFlowElement); + + processSubDiagramInSequence(subFlowElement, subProcess, subFlowElementList, subYMap, boundaryEventList); + + if(boundaryEventList.size() > 0 && + (subFlowElement instanceof CallActivity || subFlowElement instanceof Task)) { + + for (BoundaryEvent boundaryEvent : boundaryEventList) { + if(boundaryEvent.getAttachedToRef() != null && boundaryEvent.getAttachedToRef().getId().equals(subFlowElement.getId())) { + + GraphicInfo boundaryGraphicInfo = getNextGraphicInfo(null, boundaryEvent, subYMap, boundaryEventList); + subYMap.put(boundaryEvent.getId(), boundaryGraphicInfo); + subFlowElementList.add(boundaryEvent); + + processSubDiagramInSequence(boundaryEvent, subProcess, subFlowElementList, subYMap, boundaryEventList); + } + } + } + + break; + } + } + } + } + } + + private FlowElement sourceRef(String id, Map graphInfoMap) { + FlowElement sourceRef = null; + String sourceRefString = null; + for (SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) { + if(sequenceFlowModel.targetRef.equals(id) && graphInfoMap.containsKey(sequenceFlowModel.sourceRef)) { + sourceRefString = sequenceFlowModel.sourceRef; + } + } + if(sourceRefString != null) { + for (FlowElement flowElement : bpmnParser.bpmnList) { + if(flowElement.getId().equals(sourceRefString)) { + sourceRef = flowElement; + } + } + } + return sourceRef; + } + + private int getMaxX(String id) { + int maxX = 0; + String sourceRef = null; + for (SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) { + if(sequenceFlowModel.targetRef.equals(id)) { + if(yMap.containsKey(sequenceFlowModel.sourceRef)) { + int sourceX = yMap.get(sequenceFlowModel.sourceRef).x; + if(sourceX > maxX) { + maxX = sourceX; + sourceRef = sequenceFlowModel.sourceRef; + } + } else { + throw new FlowSourceNotFoundException(); + } + } + } + if(sourceRef != null) { + for (FlowElement flowElement : bpmnParser.bpmnList) { + if(flowElement.getId().equals(sourceRef)) { + if(flowElement instanceof Event) { + maxX += EVENT_WIDTH; + } else if(flowElement instanceof Gateway) { + maxX += GATEWAY_WIDTH; + } else if(flowElement instanceof Task) { + maxX += TASK_WIDTH; + } + } + } + } + maxX += SEQUENCEFLOW_WIDTH; + return maxX; + } + + private int multipleOutgoingSequenceFlows(FlowElement element, List sequenceFlowList) { + int counter = 0; + for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) { + if(sequenceFlowModel.sourceRef.equals(element.getId())) { + counter++; + } + } + return counter; + } + + private int multipleIncomingSequenceFlows(FlowElement element, List sequenceFlowList) { + int counter = 0; + for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) { + if(sequenceFlowModel.targetRef.equals(element.getId())) { + String source = sequenceFlowModel.sourceRef; + int sourceCounter = 0; + for (SequenceFlowModel sourceFlowModel : sequenceFlowList) { + if(sourceFlowModel.sourceRef.equals(source)) { + for(FlowElement flowElement : bpmnParser.bpmnList) { + if(flowElement.getId().equals(source) && flowElement instanceof BoundaryEvent == false) { + sourceCounter++; + } + } + } + } + if(sourceCounter == 1) { + counter++; + } + } + } + return counter; + } + + private int calculateDivergingElementY(FlowElement element, List sequenceFlowList) { + + if(element instanceof Gateway) { + GraphicInfo previousGateway = getDivergingGateway(element, sequenceFlowList, element.getClass().getName()); + if(previousGateway != null) { + return previousGateway.y; + } + } + + int y = 0; + List flowList = new ArrayList(); + for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) { + if(sequenceFlowModel.targetRef.equals(element.getId())) { + flowList.add(sequenceFlowModel); + } + } + + if(flowList.size() % 2 == 0) { + int middleTop = (flowList.size() / 2) - 1; + int middleBottom = flowList.size() / 2; + + if(yMap.containsKey(flowList.get(middleTop).sourceRef) && yMap.containsKey(flowList.get(middleBottom).sourceRef)) { + + GraphicInfo middleTopInfo = yMap.get(flowList.get(middleTop).sourceRef); + GraphicInfo middleBottomInfo = yMap.get(flowList.get(middleBottom).sourceRef); + y = middleTopInfo.y + middleTopInfo.height; + int middleOfGap = (middleBottomInfo.y - (middleTopInfo.y + middleTopInfo.height)) / 2; + if(element instanceof Task) { + y += middleOfGap - (TASK_HEIGHT / 2); + } else if(element instanceof Gateway) { + y += middleOfGap - (GATEWAY_HEIGHT / 2); + } else if(element instanceof Event) { + y += middleOfGap - (EVENT_HEIGHT / 2); + } else { + y += middleOfGap - (TASK_HEIGHT / 2); + } + + } else { + throw new FlowSourceNotFoundException(); + } + + } else { + int middle = ((flowList.size() - 1) / 2); + if(yMap.containsKey(flowList.get(middle).sourceRef)) { + GraphicInfo middleInfo = yMap.get(flowList.get(middle).sourceRef); + if(middleInfo.element instanceof Task) { + if(element instanceof Task) { + y = middleInfo.y; + } else if(element instanceof Gateway) { + y = middleInfo.y + 7; + } else if(element instanceof Event) { + y = middleInfo.y + 10; + } else { + y = middleInfo.y; + } + } else if(middleInfo.element instanceof Gateway) { + if(element instanceof Task) { + y = middleInfo.y - 7; + } else if(element instanceof Gateway) { + y = middleInfo.y; + } else if(element instanceof Event) { + y = middleInfo.y + 2; + } else { + y = middleInfo.y - 7; + } + } else if(middleInfo.element instanceof Event) { + if(element instanceof Task) { + y = middleInfo.y - 10; + } else if(element instanceof Gateway) { + y = middleInfo.y - 2; + } else if(element instanceof Event) { + y = middleInfo.y; + } else { + y = middleInfo.y - 10; + } + } else { + y = middleInfo.y; + } + + } else { + throw new FlowSourceNotFoundException(); + } + } + return y; + } + + private GraphicInfo getDivergingGateway(FlowElement element, List sequenceFlowList, String type) { + for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) { + + if(sequenceFlowModel.targetRef.equals(element.getId())) { + + FlowElement sourceElement = sourceRef(sequenceFlowModel.targetRef, yMap); + if(sourceElement == null) { + throw new FlowSourceNotFoundException(); + } + + if(sourceElement.getClass().getName().equals(type)) { + return yMap.get(sourceElement.getId()); + } + + GraphicInfo sourceTreeInfo = getDivergingGateway(sourceElement, sequenceFlowList, type); + if(sourceTreeInfo != null) { + return sourceTreeInfo; + } + } + } + throw null; + } + + private int calculateDirectElementChildY(FlowElement element, String id, int elementY, List sequenceFlowList) { + int y = 0; + int counter = 0; + int index = 0; + for (SequenceFlowModel sequenceFlowModel : sequenceFlowList) { + if(sequenceFlowModel.sourceRef.equals(element.getId())) { + counter++; + } + if(sequenceFlowModel.targetRef.equals(id)) { + index = counter; + } + } + + int childHeight = 20; + if(element instanceof Gateway) { + childHeight += GATEWAY_HEIGHT; + } else if(element instanceof Task) { + childHeight += TASK_HEIGHT; + } else if(element instanceof Event) { + childHeight += EVENT_HEIGHT; + } else { + childHeight += TASK_HEIGHT; + } + + if(counter % 2 == 0) { + if(index > (counter / 2)) { + y = elementY + ((index - (counter / 2)) * childHeight); + } else { + y = elementY - (((counter / 2) - index + 1) * childHeight); + } + } else { + int middle = ((counter - 1) / 2) + 1; + if(index > middle) { + y = elementY + ((index - middle) * childHeight); + } else if(index == middle) { + y = elementY; + } else { + y = elementY - ((middle - index) * childHeight); + } + } + return y; + } + + private void drawDiagramWithBPMNDI(Diagram diagram, IFeatureProvider featureProvider, List bpmnList, + List sequenceFlowList, Map locationMap) { + + for (FlowElement flowElement : bpmnList) { + String elementid = flowElement.getId(); + GraphicInfo graphicInfo = locationMap.get(elementid); + addBpmnElementToDiagram(flowElement, graphicInfo, diagram); + } + drawSequenceFlows(); + } + + private void setFriendlyIds() { + Map idMap = new HashMap(); + for (FlowElement flowElement : bpmnParser.bpmnList) { + if(StringUtils.isEmpty(flowElement.getId()) == false && + flowElement.getId().matches("sid-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}") == false) { + + continue; + } + if(flowElement instanceof StartEvent) { + flowElement.setId(getNextId("startevent", idMap)); + } else if(flowElement instanceof EndEvent) { + if(((EndEvent) flowElement).getEventDefinitions().size() > 0) { + flowElement.setId(getNextId("errorendevent", idMap)); + } else { + flowElement.setId(getNextId("endevent", idMap)); + } + } else if(flowElement instanceof ExclusiveGateway) { + flowElement.setId(getNextId("exclusivegateway", idMap)); + } else if(flowElement instanceof InclusiveGateway) { + flowElement.setId(getNextId("inclusivegateway", idMap)); + } else if(flowElement instanceof ParallelGateway) { + flowElement.setId(getNextId("parallelgateway", idMap)); + } else if(flowElement instanceof UserTask) { + flowElement.setId(getNextId("usertask", idMap)); + } else if(flowElement instanceof ScriptTask) { + flowElement.setId(getNextId("scripttask", idMap)); + } else if(flowElement instanceof ServiceTask) { + flowElement.setId(getNextId("servicetask", idMap)); + } else if(flowElement instanceof ManualTask) { + flowElement.setId(getNextId("manualtask", idMap)); + } else if(flowElement instanceof ReceiveTask) { + flowElement.setId(getNextId("receivetask", idMap)); + } else if(flowElement instanceof BusinessRuleTask) { + flowElement.setId(getNextId("businessruletask", idMap)); + } else if(flowElement instanceof MailTask) { + flowElement.setId(getNextId("mailtask", idMap)); + } else if(flowElement instanceof BoundaryEvent) { + if(((BoundaryEvent) flowElement).getEventDefinitions().size() > 0) { + EventDefinition definition = ((BoundaryEvent) flowElement).getEventDefinitions().get(0); + if(definition instanceof ErrorEventDefinition) { + flowElement.setId(getNextId("boundaryerror", idMap)); + } else { + flowElement.setId(getNextId("boundarytimer", idMap)); + } + } + } else if(flowElement instanceof CallActivity) { + flowElement.setId(getNextId("callactivity", idMap)); + } else if(flowElement instanceof SubProcess) { + flowElement.setId(getNextId("subprocess", idMap)); + } + } + } + + private String getNextId(String elementName, Map idMap) { + if(idMap.containsKey(elementName)) { + idMap.put(elementName, idMap.get(elementName) + 1); + } else { + idMap.put(elementName, 1); + } + return elementName + idMap.get(elementName); + } + + private void drawSequenceFlows() { + int sequenceCounter = 1; + for(SequenceFlowModel sequenceFlowModel : bpmnParser.sequenceFlowList) { + SequenceFlow sequenceFlow = Bpmn2Factory.eINSTANCE.createSequenceFlow(); + if(StringUtils.isEmpty(sequenceFlowModel.id) || sequenceFlowModel.id.matches("sid-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}-\\w{4,12}")) { + sequenceFlow.setId("flow" + sequenceCounter); + sequenceCounter++; + } else { + sequenceFlow.setId(sequenceFlowModel.id); + } + sequenceFlow.setSourceRef(getFlowNode(sequenceFlowModel.sourceRef)); + sequenceFlow.setTargetRef(getFlowNode(sequenceFlowModel.targetRef)); + if(sequenceFlow.getSourceRef() == null || sequenceFlow.getSourceRef().getId() == null || + sequenceFlow.getTargetRef() == null || sequenceFlow.getTargetRef().getId() == null) continue; + if(sequenceFlowModel.conditionExpression != null) { + sequenceFlow.setConditionExpression(sequenceFlowModel.conditionExpression); + } + if(sequenceFlowModel.listenerList.size() > 0) { + sequenceFlow.getExecutionListeners().addAll(sequenceFlowModel.listenerList); + } + + ContainerShape parent = null; + SubProcess subProcess = subProcessContains(sequenceFlow.getSourceRef(), subProcessList); + if(subProcess != null) { + ILinkService linkService = Graphiti.getLinkService(); + List pictoList = linkService.getPictogramElements(diagram, subProcess); + if(pictoList != null && pictoList.size() > 0) { + parent = (ContainerShape) pictoList.get(0); + subProcess.getFlowElements().add(sequenceFlow); + } + } + + if(parent == null) { + diagram.eResource().getContents().add(sequenceFlow); + parent = diagram; + } + + sequenceFlow.getSourceRef().getOutgoing().add(sequenceFlow); + sequenceFlow.getTargetRef().getIncoming().add(sequenceFlow); + + EList shapeList = parent.getChildren(); + ILinkService linkService = Graphiti.getLinkService(); + Anchor sourceAnchor = null; + Anchor targetAnchor = null; + for (Shape shape : shapeList) { + FlowNode flowNode = (FlowNode) linkService.getBusinessObjectForLinkedPictogramElement(shape.getGraphicsAlgorithm().getPictogramElement()); + if(flowNode == null || flowNode.getId() == null) continue; + + if(sequenceFlow.getSourceRef() instanceof BoundaryEvent) { + if(flowNode instanceof Task || flowNode instanceof SubProcess) { + for(Shape subShape : ((ContainerShape) shape).getChildren()) { + FlowNode subFlowNode = (FlowNode) linkService.getBusinessObjectForLinkedPictogramElement( + subShape.getGraphicsAlgorithm().getPictogramElement()); + if(subFlowNode == null || subFlowNode.getId() == null) continue; + + if(subFlowNode.getId().equals(sequenceFlow.getSourceRef().getId())) { + EList anchorList = ((ContainerShape) subShape).getAnchors(); + for (Anchor anchor : anchorList) { + if(anchor instanceof ChopboxAnchor) { + sourceAnchor = anchor; + break; + } + } + } + } + } + + } else { + + if(flowNode.getId().equals(sequenceFlow.getSourceRef().getId())) { + EList anchorList = ((ContainerShape) shape).getAnchors(); + for (Anchor anchor : anchorList) { + if(anchor instanceof ChopboxAnchor) { + sourceAnchor = anchor; + break; + } + } + } + } + + if(flowNode.getId().equals(sequenceFlow.getTargetRef().getId())) { + EList anchorList = ((ContainerShape) shape).getAnchors(); + for (Anchor anchor : anchorList) { + if(anchor instanceof ChopboxAnchor) { + targetAnchor = anchor; + break; + } + } + } + } + + AddConnectionContext addContext = new AddConnectionContext(sourceAnchor, targetAnchor); + + if(useBPMNDI) { + List bendpointList = new ArrayList(); + for (String sequenceGraphElement : bpmnParser.flowLocationMap.keySet()) { + if(sequenceFlowModel.id.equalsIgnoreCase(sequenceGraphElement)) { + List pointList = bpmnParser.flowLocationMap.get(sequenceGraphElement); + if(pointList.size() > 2) { + for(int i = 1; i < pointList.size() - 1; i++) { + bendpointList.add(pointList.get(i)); + } + } + } + } + + addContext.putProperty("org.activiti.designer.bendpoints", bendpointList); + } + + addContext.setNewObject(sequenceFlow); + featureProvider.addIfPossible(addContext); + + if(bpmnParser.defaultFlowMap.containsValue(sequenceFlowModel.id)) { + Iterator itDefaultFlow = bpmnParser.defaultFlowMap.keySet().iterator(); + while(itDefaultFlow.hasNext()) { + FlowNode flowNode = itDefaultFlow.next(); + String defaultId = bpmnParser.defaultFlowMap.get(flowNode); + if(defaultId.equalsIgnoreCase(sequenceFlowModel.id)) { + if(flowNode instanceof ExclusiveGateway) { + ((ExclusiveGateway) flowNode).setDefault(sequenceFlow); + } else if(flowNode instanceof InclusiveGateway) { + ((InclusiveGateway) flowNode).setDefault(sequenceFlow); + } else { + ((Activity) flowNode).setDefault(sequenceFlow); + } + } + } + } + } + } + + private SubProcess subProcessContains(FlowNode sourceRef, List subProcessList) { + for (SubProcess subProcess : subProcessList) { + for (FlowElement flowElement : subProcess.getFlowElements()) { + if(flowElement.getId().equals(sourceRef.getId())) { + return subProcess; + } + } + } + return null; + } + + private FlowNode getFlowNode(String elementid) { + FlowNode flowNode = null; + for(FlowElement flowElement : bpmnParser.bpmnList) { + if(flowElement.getId().equalsIgnoreCase(elementid)) { + flowNode = (FlowNode) flowElement; + } + } + return flowNode; + } + + private void addBpmnElementToDiagram(FlowElement flowElement, GraphicInfo graphicInfo, + ContainerShape parent) { + + if(flowElement instanceof BoundaryEvent) { + BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement; + AddContext addContext = new AddContext(); + boolean parentIsSubProcess = false; + + if(boundaryEvent.getAttachedToRef() instanceof SubProcess) { + parentIsSubProcess = true; + } + + ILinkService linkService = Graphiti.getLinkService(); + List pictoList = linkService.getPictogramElements(diagram, boundaryEvent.getAttachedToRef()); + if(pictoList != null && pictoList.size() > 0) { + addContext.setTargetContainer((ContainerShape) pictoList.get(0)); + } + + addContext.setNewObject(boundaryEvent); + if(parentIsSubProcess == true) { + addContext.setX(addContext.getTargetContainer().getGraphicsAlgorithm().getWidth() / 2); + addContext.setY(addContext.getTargetContainer().getGraphicsAlgorithm().getHeight() - 15); + } else { + addContext.setX(TASK_WIDTH - 25); + addContext.setY(TASK_HEIGHT - 25); + } + + IAddFeature addFeature = featureProvider.getAddFeature(addContext); + if (addFeature.canAdd(addContext)) { + addFeature.add(addContext); + } + return; + } + + if(flowElement instanceof UserTask) { + UserTask userTask = (UserTask) flowElement; + if(userTask.getCandidateUsers() != null && userTask.getCandidateUsers().size() > 0) { + for (CandidateUser candidateUser : userTask.getCandidateUsers()) { + diagram.eResource().getContents().add(candidateUser); + } + } + if(userTask.getCandidateGroups() != null && userTask.getCandidateGroups().size() > 0) { + for (CandidateGroup candidateGroup : userTask.getCandidateGroups()) { + diagram.eResource().getContents().add(candidateGroup); + } + } + } else if(flowElement instanceof ServiceTask) { + ServiceTask serviceTask = (ServiceTask) flowElement; + if(serviceTask.getFieldExtensions() != null && serviceTask.getFieldExtensions().size() > 0) { + for (FieldExtension fieldExtension : serviceTask.getFieldExtensions()) { + diagram.eResource().getContents().add(fieldExtension); + } + } + } + + AddContext addContext = new AddContext(); + addContext.setNewObject(flowElement); + addContext.setTargetContainer(parent); + addContext.setX(graphicInfo.x); + + if(useBPMNDI) { + addContext.setHeight(graphicInfo.height); + addContext.setWidth(graphicInfo.width); + } + + + if(flowElement instanceof StartEvent || flowElement instanceof EndEvent) { + if(useBPMNDI == false && graphicInfo.height < EVENT_HEIGHT) { + addContext.setY(graphicInfo.y - 25); + } else { + addContext.setY(graphicInfo.y); + } + } else if(flowElement instanceof ExclusiveGateway || flowElement instanceof InclusiveGateway || + flowElement instanceof ParallelGateway) { + if(useBPMNDI == false && graphicInfo.height < GATEWAY_HEIGHT) { + addContext.setY(graphicInfo.y - 20); + } else { + addContext.setY(graphicInfo.y); + } + } else if(flowElement instanceof SubProcess) { + addContext.setHeight(graphicInfo.height); + addContext.setWidth(graphicInfo.width); + addContext.setY(graphicInfo.y); + } else { + addContext.setY(graphicInfo.y); + } + + IAddFeature addFeature = featureProvider.getAddFeature(addContext); + if (addFeature.canAdd(addContext)) { + addFeature.add(addContext); + } + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/FlowSourceNotFoundException.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/FlowSourceNotFoundException.java new file mode 100644 index 0000000..4a43b5b --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/FlowSourceNotFoundException.java @@ -0,0 +1,7 @@ +package org.activiti.designer.eclipse.bpmnimport; + +public class FlowSourceNotFoundException extends RuntimeException { + + private static final long serialVersionUID = 1L; + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnElementsCommand.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnElementsCommand.java new file mode 100755 index 0000000..e8132cd --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnElementsCommand.java @@ -0,0 +1,61 @@ +package org.activiti.designer.eclipse.bpmnimport; + +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.graphiti.dt.IDiagramTypeProvider; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.graphiti.ui.services.GraphitiUi; + +public class ImportBpmnElementsCommand extends RecordingCommand { + + private TransactionalEditingDomain editingDomain; + private String diagramName; + private String bpmnFileName; + private Resource createdResource; + private Diagram diagram; + private IContainer targetFolder; + + public ImportBpmnElementsCommand(TransactionalEditingDomain editingDomain, + String diagramName, String bpmnFileName, IContainer targetFolder) { + super(editingDomain); + this.editingDomain = editingDomain; + this.diagramName = diagramName; + this.bpmnFileName = bpmnFileName; + this.targetFolder = targetFolder; + } + + @Override + protected void doExecute() { + // Create the diagram and its file + diagram = Graphiti.getPeCreateService().createDiagram("BPMNdiagram", diagramName, true); //$NON-NLS-1$ + IFile diagramFile = targetFolder.getFile(new Path(diagramName + ".activiti")); //$NON-NLS-1$ + URI uri = URI.createPlatformResourceURI(diagramFile.getFullPath().toString(), true); + createdResource = editingDomain.getResourceSet().createResource(uri); + createdResource.getContents().add(diagram); + + IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, + "org.activiti.designer.diagram.ActivitiBPMNDiagramTypeProvider"); //$NON-NLS-1$ + IFeatureProvider featureProvider = dtp.getFeatureProvider(); + BpmnFileReader bpmnFileReader = new BpmnFileReader(bpmnFileName, diagram, featureProvider); + bpmnFileReader.openStream(); + bpmnFileReader.readBpmn(); + } + + /** + * @return the createdResource + */ + public Resource getCreatedResource() { + return createdResource; + } + + public Diagram getDiagram() { + return diagram; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnUtil.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnUtil.java new file mode 100644 index 0000000..5e08285 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/bpmnimport/ImportBpmnUtil.java @@ -0,0 +1,66 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.bpmnimport; + +import java.io.IOException; + +import org.activiti.designer.eclipse.common.ActivitiPlugin; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.swt.widgets.Display; + + +/** + * @author Tijs Rademakers + */ +public class ImportBpmnUtil { + + public static ImportBpmnElementsCommand createDiagram(String processName, String bpmnFile, + IProject project, IContainer targetFolder) { + + // Get the default resource set to hold the new resource + ResourceSet resourceSet = new ResourceSetImpl(); + TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(resourceSet); + if (editingDomain == null) { + // Not yet existing, create one + editingDomain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet); + } + + // Create the data within a command and save (must not happen inside + // the command since finishing the command will trigger setting the + // modification flag on the resource which will be used by the save + // operation to determine which resources need to be saved) + ImportBpmnElementsCommand operation = new ImportBpmnElementsCommand( + editingDomain, processName, bpmnFile, targetFolder); + editingDomain.getCommandStack().execute(operation); + try { + operation.getCreatedResource().save(null); + } catch (IOException e) { + IStatus status = new Status(IStatus.ERROR, ActivitiPlugin.getID(), e.getMessage(), e); //$NON-NLS-1$ + ErrorDialog.openError(Display.getCurrent().getActiveShell(), "Error Occured", e.getMessage(), status); + } + + // Dispose the editing domain to eliminate memory leak + editingDomain.dispose(); + return operation; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/AbstractImageCache.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/AbstractImageCache.java new file mode 100644 index 0000000..1aaabe2 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/AbstractImageCache.java @@ -0,0 +1,39 @@ +package org.activiti.designer.eclipse.common; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; + +/** + * Provides access to the plugin's image resources. + * + * @author Tiese Barrell + * @since 5.5 + * @version 1 + * + */ +public abstract class AbstractImageCache { + + private static final Map imageMap = new HashMap(); + + protected static final Image getImage(ImageDescriptor imageDescriptor) { + if (imageDescriptor == null) + return null; + Image image = (Image) imageMap.get(imageDescriptor); + if (image == null) { + image = imageDescriptor.createImage(); + imageMap.put(imageDescriptor, image); + } + return image; + } + + public void dispose() { + Iterator iter = imageMap.values().iterator(); + while (iter.hasNext()) + iter.next().dispose(); + imageMap.clear(); + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiBPMNDiagramConstants.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiBPMNDiagramConstants.java new file mode 100644 index 0000000..a7a22ae --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiBPMNDiagramConstants.java @@ -0,0 +1,48 @@ +package org.activiti.designer.eclipse.common; + +/** + * Constants for BPMN diagrams. + * + * @author Tiese Barrell + * @since 0.5.0 + * @version 2 + * + */ +public final class ActivitiBPMNDiagramConstants { + + public static final String DIAGRAM_FOLDER = "src/main/resources/diagrams/"; + public static final String DIAGRAM_EXTENSION_RAW = "activiti"; + public static final String DIAGRAM_EXTENSION = "." + DIAGRAM_EXTENSION_RAW; + // public static final String DIAGRAM_EDITOR_ID = + // "org.activiti.designer.editor.diagram"; + public static final String DIAGRAM_EDITOR_ID = "org.activiti.designer.editor.multiPageEditor"; + public static final String BPMN_EDITOR_ID = "org.activiti.designer.editor.bpmn"; + public static final String BPMN2_CONTENTTYPE_ID = "org.activiti.designer.editor.bpmn.contenttype"; + + public static final String BPMN_MARSHALLER_NAME = "Activiti Designer BPMN 2.0"; + public static final String BPMN_VALIDATOR_ID = "ActivitiDesignerBPMNValidator"; + public static final String BPMN_VALIDATOR_NAME = "Activiti Designer BPMN Validator"; + public static final String IMAGE_MARSHALLER_NAME = "Activiti Designer Image"; + + // + // Adding Marshaller and Validator constants. + public static final String HTML_MARSHALLER_NAME = "SAP Research SCVM HTML"; + public static final String ASLAN_MARSHALLER_NAME = "SAP Research SCVM ASLan"; + + public static final String XACML_MARSHALLER_NAME = "SAP Research SCVM Xacml"; + public static final String XACML_VALIDATOR_ID = "SAPResearchSCVMXacmlValidator"; + + public static final String ASLAN_VALIDATOR_ID = "SAPResearchSCVMASLanValidator"; + public static final String ASLAN_VALIDATOR_NAME = "SAP Research ASLan SCVM Validator"; + // + + public static final String BPMN_MARSHALLER_VALIDATION_SKIP = "skip"; + public static final String BPMN_MARSHALLER_VALIDATION_ATTEMPT = "attempt"; + + public static final String ACTIVITI_GENERAL_MARKER_ID = "org.activiti.designer.eclipse.activitiGeneralMarker"; + + private ActivitiBPMNDiagramConstants() { + + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiEclipseImageProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiEclipseImageProvider.java new file mode 100644 index 0000000..bf1b30e --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiEclipseImageProvider.java @@ -0,0 +1,42 @@ +package org.activiti.designer.eclipse.common; + +import org.eclipse.graphiti.ui.platform.AbstractImageProvider; + +public class ActivitiEclipseImageProvider extends AbstractImageProvider { + + private static final String ROOT_FOLDER_FOR_IMG = "icons/"; //$NON-NLS-1$ + + @Override + protected void addAvailableImages() { + // attributes + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_A_PUBLIC, ROOT_FOLDER_FOR_IMG + "modifier/attribute_public.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_A_PROTECTED, ROOT_FOLDER_FOR_IMG + "modifier/attribute_protected.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_A_PRIVATE, ROOT_FOLDER_FOR_IMG + "modifier/attribute_private.gif"); //$NON-NLS-1$ + + // references + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_R_PROTECTED, ROOT_FOLDER_FOR_IMG + "modifier/reference_public.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_R_PUBLIC, ROOT_FOLDER_FOR_IMG + "modifier/reference_protected.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_R_PRIVATE, ROOT_FOLDER_FOR_IMG + "modifier/reference_private.gif"); //$NON-NLS-1$ + + // operations + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_O_PRIVATE, ROOT_FOLDER_FOR_IMG + "modifier/operation_public.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_O_PROTECTED, ROOT_FOLDER_FOR_IMG + "modifier/operation_protected.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MODIFIER_O_PUBLIC, ROOT_FOLDER_FOR_IMG + "modifier/operation_private.gif"); //$NON-NLS-1$ + + // mof + addImageFilePath(ISampleImageConstants.IMG_CLASS, ROOT_FOLDER_FOR_IMG + "mof/class.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_NEW_CLASS, ROOT_FOLDER_FOR_IMG + "mof/newclass.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_PACKAGE, ROOT_FOLDER_FOR_IMG + "mof/package.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_MOF, ROOT_FOLDER_FOR_IMG + "mof/mof.gif"); //$NON-NLS-1$ + + // tree + addImageFilePath(ISampleImageConstants.IMG_TREE_DOWN, ROOT_FOLDER_FOR_IMG + "tree/tree_down.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_TREE_LEFT, ROOT_FOLDER_FOR_IMG + "tree/tree_left.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_TREE_RIGHT, ROOT_FOLDER_FOR_IMG + "tree/tree_right.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_TREE_UP, ROOT_FOLDER_FOR_IMG + "tree/tree_up.gif"); //$NON-NLS-1$ + + // outline + addImageFilePath(ISampleImageConstants.IMG_OUTLINE_TREE, ROOT_FOLDER_FOR_IMG + "outline/tree.gif"); //$NON-NLS-1$ + addImageFilePath(ISampleImageConstants.IMG_OUTLINE_THUMBNAIL, ROOT_FOLDER_FOR_IMG + "outline/thumbnail.gif"); //$NON-NLS-1$ + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiPlugin.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiPlugin.java new file mode 100644 index 0000000..60d5a6c --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiPlugin.java @@ -0,0 +1,175 @@ +package org.activiti.designer.eclipse.common; + +import java.net.URL; + +import org.activiti.designer.eclipse.outline.ContentOutlinePageAdapterFactory; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.Platform; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class ActivitiPlugin extends AbstractUIPlugin { + + public static final String PLUGIN_ID = "org.activiti.designer.eclipse"; //$NON-NLS-1$ + + /** + * The name used for the user library that contains extensions for the + * Activiti Designer. + */ + public static final String USER_LIBRARY_NAME_EXTENSIONS = "Activiti Designer Extensions"; + + public static final String DESIGNER_EXTENSIONS_USER_LIB_PATH = "org.eclipse.jdt.USER_LIBRARY/" + USER_LIBRARY_NAME_EXTENSIONS; + + public static final String EXPORT_MARSHALLER_EXTENSIONPOINT_ID = "org.activiti.designer.eclipse.extension.export.ExportMarshaller"; + + public static final String PROCESS_VALIDATOR_EXTENSIONPOINT_ID = "org.activiti.designer.eclipse.extension.validation.ProcessValidator"; + + private static ActivitiPlugin _plugin; + + // The image cache object used in the plugin + private static ImageCache imageCache; + + /** + * Creates the Plugin and caches its default instance. + */ + public ActivitiPlugin() { + _plugin = this; + } + + // ============ overwritten methods of AbstractUIPlugin ==================== + + /** + * This method is called upon plug-in activation. + * + * @param context + * the context + * + * @throws Exception + * the exception + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + + IAdapterManager manager = Platform.getAdapterManager(); + manager.registerAdapters(new ContentOutlinePageAdapterFactory(), DiagramEditor.class); + + // Initialize the image cache + imageCache = new ImageCache(); + } + + @Override + public void stop(BundleContext context) throws Exception { + // Allow the image cache to destroy itself so image references are cleaned + // up + imageCache.dispose(); + } + + // ======================== static access methods ========================== + + /** + * Gets the default-instance of this plugin. Actually the default-instance + * should always be the only instance -> Singleton. + * + * @return the default + */ + public static ActivitiPlugin getDefault() { + return _plugin; + } + + // =========================== public helper methods ====================== + + /** + * Returns the current Workspace. + * + * @return The current Workspace. + */ + public static IWorkspace getWorkspace() { + return ResourcesPlugin.getWorkspace(); + } + + /** + * Returns the URL, which points to where this Plugin is installed. + * + * @return The URL, which points to where this Plugin is installed. + */ + public static URL getInstallURL() { + return getDefault().getBundle().getEntry("/"); + } + + /** + * Returns the Plugin-ID. + * + * @return The Plugin-ID. + */ + public static String getID() { + return getDefault().getBundle().getSymbolicName(); + } + + /** + * Returns the currently active WorkbenchPage. + * + * @return The currently active WorkbenchPage. + */ + public static IWorkbenchPage getActivePage() { + IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (workbenchWindow != null) + return workbenchWindow.getActivePage(); + return null; + } + + /** + * Returns the currently active Shell. + * + * @return The currently active Shell. + */ + public static Shell getShell() { + return getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(); + } + + /** + * Returns an image descriptor for the image file at the given plug-in + * relative path + * + * @param path + * the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return imageDescriptorFromPlugin(PLUGIN_ID, path); + } + + /** + * Gets an image from this plugin. + * + * @param pluginImage + * the PluginImage to get the image for + * + * @return an Image if the image was found, null otherwise + */ + public static Image getImage(PluginImage pluginImage) { + return imageCache.getImage(pluginImage); + } + + /** + * Gets an image descriptor for an image from this plugin. + * + * @param pluginImage + * the PluginImage to get the image descriptor for + * + * @return an ImageDescriptor if the image was found, null otherwise + */ + public static ImageDescriptor getImageDescriptor(PluginImage pluginImage) { + return getImageDescriptor(pluginImage.getImagePath()); + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiProjectNature.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiProjectNature.java new file mode 100644 index 0000000..8a1d419 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ActivitiProjectNature.java @@ -0,0 +1,34 @@ +package org.activiti.designer.eclipse.common; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectNature; +import org.eclipse.core.runtime.CoreException; + +public class ActivitiProjectNature implements IProjectNature { + + public static final String NATURE_ID = "org.activiti.designer.nature"; + + IProject p; + + @Override + public void configure() throws CoreException { + + } + + @Override + public void deconfigure() throws CoreException { + + } + + @Override + public IProject getProject() { + return p; + } + + @Override + public void setProject(IProject project) { + p = project; + + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ColoredFont.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ColoredFont.java new file mode 100644 index 0000000..0706aaa --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ColoredFont.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.common; + +import org.eclipse.graphiti.mm.algorithms.styles.Color; +import org.eclipse.graphiti.mm.algorithms.styles.Font; + +/** + * The Class ColoredFont. + */ +public class ColoredFont { + + private Font font; + private Color color; + + /** + * Instantiates a new colored font. + * + * @param font + * the font + * @param color + * the color + */ + public ColoredFont(Font font, Color color) { + super(); + setFont(font); + setColor(color); + } + + /** + * Gets the color. + * + * @return Returns the color. + */ + public Color getColor() { + return color; + } + + /** + * Gets the font. + * + * @return Returns the font. + */ + public Font getFont() { + return font; + } + + /** + * Sets the color. + * + * @param color + * The color to set. + */ + public void setColor(Color color) { + this.color = color; + } + + /** + * Sets the font. + * + * @param font + * The font to set. + */ + public void setFont(Font font) { + this.font = font; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/FileService.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/FileService.java new file mode 100644 index 0000000..f1948ee --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/FileService.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.common; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRunnable; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.util.WrappedException; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.Transaction; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.ui.editor.DiagramEditorFactory; + +public class FileService { + + public static TransactionalEditingDomain createEmfFileForDiagram(URI diagramResourceUri, final Diagram diagram, + final InputStream contentStream, final IFile resourceFile) { + + // Create a resource set and EditingDomain + final TransactionalEditingDomain editingDomain = DiagramEditorFactory.createResourceSetAndEditingDomain(); + final ResourceSet resourceSet = editingDomain.getResourceSet(); + // Create a resource for this file. + final Resource resource = resourceSet.createResource(diagramResourceUri); + + final CommandStack commandStack = editingDomain.getCommandStack(); + commandStack.execute(new RecordingCommand(editingDomain) { + + @Override + protected void doExecute() { + resource.setTrackingModification(true); + if (contentStream == null) { + resource.getContents().add(diagram); + } else { + try { + resourceFile.create(contentStream, IResource.FORCE, null); + } catch (CoreException e) { + // TODO + e.printStackTrace(); + } + } + } + }); + + save(editingDomain, Collections.> emptyMap()); + return editingDomain; + } + + private static void save(TransactionalEditingDomain editingDomain, Map> options) { + saveInWorkspaceRunnable(editingDomain, options); + } + + private static void saveInWorkspaceRunnable(final TransactionalEditingDomain editingDomain, + final Map> options) { + + final Map failedSaves = new HashMap(); + final IWorkspaceRunnable wsRunnable = new IWorkspaceRunnable() { + @Override + public void run(final IProgressMonitor monitor) throws CoreException { + + final Runnable runnable = new Runnable() { + + @Override + public void run() { + Transaction parentTx; + if (editingDomain != null + && (parentTx = ((TransactionalEditingDomainImpl) editingDomain).getActiveTransaction()) != null) { + do { + if (!parentTx.isReadOnly()) { + throw new IllegalStateException( + "FileService.save() called from within a command (likely produces a deadlock)"); + } + } while ((parentTx = ((TransactionalEditingDomainImpl) editingDomain) + .getActiveTransaction().getParent()) != null); + } + + final EList resources = editingDomain.getResourceSet().getResources(); + // Copy list to an array to prevent + // ConcurrentModificationExceptions + // during the saving of the dirty resources + Resource[] resourcesArray = new Resource[resources.size()]; + resourcesArray = resources.toArray(resourcesArray); + final Set savedResources = new HashSet(); + for (int i = 0; i < resourcesArray.length; i++) { + // In case resource modification tracking is + // switched on, we can check if a resource + // has been modified, so that we only need to same + // really changed resources; otherwise + // we need to save all resources in the set + final Resource resource = resourcesArray[i]; + if (resource.isModified()) { + try { + resource.save(options.get(resource)); + savedResources.add(resource); + } catch (final Throwable t) { + failedSaves.put(resource.getURI(), t); + } + } + } + } + }; + + try { + editingDomain.runExclusive(runnable); + } catch (final InterruptedException e) { + throw new RuntimeException(e); + } + editingDomain.getCommandStack().flush(); + } + }; + try { + ResourcesPlugin.getWorkspace().run(wsRunnable, null); + if (!failedSaves.isEmpty()) { + throw new WrappedException(createMessage(failedSaves), new RuntimeException()); + } + } catch (final CoreException e) { + final Throwable cause = e.getStatus().getException(); + if (cause instanceof RuntimeException) { + throw (RuntimeException) cause; + } + throw new RuntimeException(e); + } + } + + private static String createMessage(Map failedSaves) { + final StringBuilder buf = new StringBuilder("The following resources could not be saved:"); + for (final Entry entry : failedSaves.entrySet()) { + buf.append("\nURI: ").append(entry.getKey().toString()).append(", cause: \n") + .append(getExceptionAsString(entry.getValue())); + } + return buf.toString(); + } + + private static String getExceptionAsString(Throwable t) { + final StringWriter stringWriter = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(stringWriter); + t.printStackTrace(printWriter); + final String result = stringWriter.toString(); + try { + stringWriter.close(); + } catch (final IOException e) { + // $JL-EXC$ ignore + } + printWriter.close(); + return result; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ISampleImageConstants.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ISampleImageConstants.java new file mode 100644 index 0000000..480b7bf --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ISampleImageConstants.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +/** + * + */ +package org.activiti.designer.eclipse.common; + +/** + * The Interface IMofImageConstants. + */ +public interface ISampleImageConstants { + + /** + * The Constant PRE. + */ + static final String PRE = "org.eclipse.graphiti.examples.common."; //$NON-NLS-1$ + + /** + * The Constant IMG_MISSING. + */ + static final String IMG_MISSING = PRE + "missing"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_A_PUBLIC. + */ + static final String IMG_MODIFIER_A_PUBLIC = PRE + "mod.a.public"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_A_PRIVATE. + */ + static final String IMG_MODIFIER_A_PRIVATE = PRE + "mod.a.private"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_A_PROTECTED. + */ + static final String IMG_MODIFIER_A_PROTECTED = PRE + "mod.a.protected"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_R_PUBLIC. + */ + static final String IMG_MODIFIER_R_PUBLIC = PRE + "mod.r.public"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_R_PRIVATE. + */ + static final String IMG_MODIFIER_R_PRIVATE = PRE + "mod.r.private"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_R_PROTECTED. + */ + static final String IMG_MODIFIER_R_PROTECTED = PRE + "mod.r.protected"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_O_PUBLIC. + */ + static final String IMG_MODIFIER_O_PUBLIC = PRE + "mod.o.public"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_O_PRIVATE. + */ + static final String IMG_MODIFIER_O_PRIVATE = PRE + "mod.o.private"; //$NON-NLS-1$ + + /** + * The Constant IMG_MODIFIER_O_PROTECTED. + */ + static final String IMG_MODIFIER_O_PROTECTED = PRE + "mod.o.protected"; //$NON-NLS-1$ + + /** + * The Constant IMG_NEW_CLASS. + */ + static final String IMG_NEW_CLASS = PRE + "new_class"; //$NON-NLS-1$ + + /** + * The Constant IMG_CLASS. + */ + static final String IMG_CLASS = PRE + "class"; //$NON-NLS-1$ + + /** + * The Constant IMG_PACKAGE. + */ + static final String IMG_PACKAGE = PRE + "package"; //$NON-NLS-1$ + + /** + * The Constant IMG_MOF. + */ + static final String IMG_MOF = PRE + "mof"; //$NON-NLS-1$ + + // tree + /** + * The Constant IMG_TREE_UP. + */ + static final String IMG_TREE_UP = PRE + "tree.up"; //$NON-NLS-1$ + + /** + * The Constant IMG_TREE_DOWN. + */ + static final String IMG_TREE_DOWN = PRE + "tree.down"; //$NON-NLS-1$ + + /** + * The Constant IMG_TREE_LEFT. + */ + static final String IMG_TREE_LEFT = PRE + "tree.left"; //$NON-NLS-1$ + + /** + * The Constant IMG_TREE_RIGHT. + */ + static final String IMG_TREE_RIGHT = PRE + "tree.right"; //$NON-NLS-1$ + + // outline + /** + * The Constant IMG_OUTLINE_TREE. + */ + static final String IMG_OUTLINE_TREE = PRE + "outline.tree"; //$NON-NLS-1$ + + /** + * The Constant IMG_OUTLINE_THUMBNAIL. + */ + static final String IMG_OUTLINE_THUMBNAIL = PRE + "outline.thumbnail"; //$NON-NLS-1$ +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ImageCache.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ImageCache.java new file mode 100644 index 0000000..3d38905 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/ImageCache.java @@ -0,0 +1,44 @@ +/** + * + */ +package org.activiti.designer.eclipse.common; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.plugin.AbstractUIPlugin; + + +/** + * @author Tiese Barrell + * @since 5.5 + * @version 1 + * + */ +public class ImageCache extends AbstractImageCache { + + /** + * Returns an {@link ImageDescriptor} for the image file at the given plug-in + * relative path + * + * @param image + * the {@link PluginImage} + * @return the image descriptor + */ + public static final ImageDescriptor getImageDescriptor(PluginImage image) { + return AbstractUIPlugin.imageDescriptorFromPlugin(ActivitiPlugin.PLUGIN_ID, image.getImagePath()); + } + + /** + * Returns an {@link Image} for the image file at the given plug-in relative + * path + * + * @param image + * the {@link PluginImage} + * @return the image + */ + public final Image getImage(PluginImage image) { + final ImageDescriptor descriptor = getImageDescriptor(image); + return getImage(descriptor); + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/PluginImage.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/PluginImage.java new file mode 100644 index 0000000..44cbd09 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/PluginImage.java @@ -0,0 +1,31 @@ +/** + * + */ +package org.activiti.designer.eclipse.common; + +/** + * Enum that lists the frequently used images available in this plugin. + * + * @author Tiese Barrell + * @version 1 + * @since 5.5 + * + * + */ +public enum PluginImage { + + ACTIVITI_LOGO_16x16("icons/logo/activiti.logo.gradients.16x16.png"), ACTIVITI_LOGO_32x32("icons/logo/activiti.logo.gradients.32x32.png"), ACTIVITI_LOGO_48x48( + "icons/logo/activiti.logo.gradients.48x48.png"), ACTIVITI_LOGO_64x64("icons/logo/activiti.logo.gradients.64x64.png"), ACTIVITI_LOGO_128x128( + "icons/logo/activiti.logo.gradients.128x128.png"); + + private String imagePath; + + private PluginImage(String imagePath) { + this.imagePath = imagePath; + } + + public String getImagePath() { + return imagePath; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/RenameActionProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/RenameActionProvider.java new file mode 100644 index 0000000..e8f829b --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/RenameActionProvider.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.common; + +import java.io.IOException; +import java.util.Collections; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.edit.command.CommandParameter; +import org.eclipse.emf.edit.command.SetCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.navigator.CommonActionProvider; +import org.eclipse.ui.navigator.ICommonMenuConstants; + +public class RenameActionProvider extends CommonActionProvider { + + @Override + public void fillContextMenu(IMenuManager menu) { + super.fillContextMenu(menu); + ISelection selection = getContext().getSelection(); + if (selection.isEmpty()) + return; + if (selection instanceof IStructuredSelection) { + IStructuredSelection sel = (IStructuredSelection) selection; + Object el = sel.getFirstElement(); + if (el instanceof EClass) { + EClass eclass = (EClass) el; + String platformString = eclass.eResource().getURI().toPlatformString(true); + Path path = new Path(platformString); + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); + if (file == null) + return; + IProject project = file.getProject(); + try { + if (!project.hasNature(ActivitiProjectNature.NATURE_ID)) + return; + } catch (CoreException e) { + e.printStackTrace(); + } + menu.appendToGroup(ICommonMenuConstants.GROUP_ADDITIONS, getAction(eclass)); + + } + } + } + + private IAction getAction(EClass eo) { + return new RenameAction(eo); + } + + private static class RenameAction extends Action { + + private EClass eclass; + + public RenameAction(EClass eo) { + this.eclass = eo; + } + + @Override + public void run() { + InputDialog inputDialog = new InputDialog(null, "Provide String", "Provide a new Name for the EClass", eclass.getName(), null); + int open = inputDialog.open(); + if (open == Dialog.OK) { + String newName = inputDialog.getValue(); + Resource resource = eclass.eResource(); + ResourceSet resourceSet = resource.getResourceSet(); + TransactionalEditingDomain domain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet); + try{ + if (domain != null){ + Command setCommand = domain.createCommand(SetCommand.class, new CommandParameter(eclass, + EcorePackage.Literals.ENAMED_ELEMENT__NAME, newName)); + domain.getCommandStack().execute(setCommand); + try { + resource.save(Collections.emptyMap()); + } catch (IOException e) { + e.printStackTrace(); + } + } + }finally{ + domain.dispose(); + } + } + } + + @Override + public String getText() { + return "Rename EClass"; + } + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/SampleUtil.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/SampleUtil.java new file mode 100644 index 0000000..042431a --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/common/SampleUtil.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.common; + +import org.eclipse.graphiti.mm.algorithms.styles.Color; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.ColorDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; + +public class SampleUtil { + + /** + * Opens an simple input dialog with OK and Cancel buttons. + *

    + * + * @param dialogTitle + * the dialog title, or null if none + * @param dialogMessage + * the dialog message, or null if none + * @param initialValue + * the initial input value, or null if none + * (equivalent to the empty string) + * @return the string + */ + public static String askString(String dialogTitle, String dialogMessage, String initialValue) { + String ret = null; + Shell shell = getShell(); + InputDialog inputDialog = new InputDialog(shell, dialogTitle, dialogMessage, initialValue, null); + int retDialog = inputDialog.open(); + if (retDialog == Window.OK) { + ret = inputDialog.getValue(); + } + return ret; + } + + /** + * Opens a dialog to change the color. + * + * @param color + * the color to change + * @return the changed color + */ + public static Color editColor(Color color) { + if (color != null && color.eContainer() instanceof Diagram) { + Shell shell = getShell(); + ColorDialog colorDialog = new ColorDialog(shell); + colorDialog.setText("Choose Color"); + colorDialog.setRGB(new RGB(color.getRed(), color.getGreen(), color.getBlue())); + + RGB retRgb = colorDialog.open(); + if (retRgb == null) { + return null; + } + + Diagram diagram = (Diagram) color.eContainer(); + Color newColor = Graphiti.getGaService().manageColor(diagram, retRgb.red, retRgb.green, retRgb.blue); + return newColor; + + } + + return null; + } + + /** + * Returns the currently active Shell. + * + * @return The currently active Shell. + */ + private static Shell getShell() { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/DeploymentInfo.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/DeploymentInfo.java new file mode 100644 index 0000000..f362554 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/DeploymentInfo.java @@ -0,0 +1,62 @@ +package org.activiti.designer.eclipse.deployment; + +import org.eclipse.core.resources.IFolder; + +public class DeploymentInfo { + + private String serverName = null; + private String serverPort = null; + private String serverDeployer = null; + private IFolder processFolder = null; + private Object[] classesAndResources = null; + private Object[] filesAndFolders = null; + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerName() { + return serverName; + } + + public void setServerPort(String serverPort) { + this.serverPort = serverPort; + } + + public String getServerPort() { + return serverPort; + } + + public void setServerDeployer(String serverDeployer) { + this.serverDeployer = serverDeployer; + } + + public String getServerDeployer() { + return serverDeployer; + } + + public void setProcessFolder(IFolder processFolder) { + this.processFolder = processFolder; + } + + public IFolder getProcessFolder() { + return processFolder; + } + + public void setClassesAndResources(Object[] classesAndResources) { + this.classesAndResources = classesAndResources; + } + + public Object[] getClassesAndResources() { + return classesAndResources; + } + + public void setFilesAndFolders(Object[] filesAndFolders) { + this.filesAndFolders = filesAndFolders; + } + + public Object[] getFilesAndFolders() { + return filesAndFolders; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesTreeContentProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesTreeContentProvider.java new file mode 100644 index 0000000..29f8b18 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesTreeContentProvider.java @@ -0,0 +1,145 @@ +package org.activiti.designer.eclipse.deployment; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.activiti.designer.eclipse.Logger; +import org.eclipse.core.resources.IResource; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Control; + +public class IncludeClassesTreeContentProvider implements ITreeContentProvider { + + public Object[] getElements(Object parent) { + if (parent instanceof IJavaProject) { + return getPackageFragmentRoots((IJavaProject)parent); + } + return new Object[0]; + } + + private IPackageFragmentRoot[] getPackageFragmentRoots(IJavaProject project) { + try { + ArrayList list = new ArrayList(); + IClasspathEntry[] entries = project.getRawClasspath(); + for (int i = 0; i < entries.length; i++) { + if (entries[i].getEntryKind() != IClasspathEntry.CPE_CONTAINER && entries[i].getEntryKind() != IClasspathEntry.CPE_VARIABLE) { + IPackageFragmentRoot[] roots = project.findPackageFragmentRoots(entries[i]); + for (int j = 0; j < roots.length; j++) { + list.add(roots[j]); + } + } + } + Iterator itPackage = list.iterator(); + while(itPackage.hasNext()) { + IPackageFragmentRoot packageRoot = itPackage.next(); + if(packageRoot.getPath().toOSString().contains("src/test")) { + itPackage.remove(); + } + } + return (IPackageFragmentRoot[])list.toArray(new IPackageFragmentRoot[list.size()]); + } + catch (JavaModelException e) { + Logger.logError(e); + } + return new IPackageFragmentRoot[0]; + } + + public Object[] getChildren(Object parent) { + ArrayList list = new ArrayList(); + try { + if (parent instanceof IPackageFragmentRoot) { + list.addAll(toArrayList(((IPackageFragmentRoot)parent).getNonJavaResources())); + list.addAll(getNonEmptyPackageFragments((IPackageFragmentRoot) parent)); + } else if (parent instanceof IPackageFragment) { + list.addAll(toArrayList(((IPackageFragment)parent).getNonJavaResources())); + list.addAll(toArrayList(((IPackageFragment)parent).getChildren())); + } + } catch (JavaModelException e) { + Logger.logError(e); + } + return list.toArray(); + } + + private ArrayList toArrayList(Object[] resources){ + ArrayList list = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + list.add(resources[i]); + } + return list; + } + + private ArrayList getNonEmptyPackageFragments(IPackageFragmentRoot parent) { + ArrayList list = new ArrayList(); + try { + Object[] children = parent.getChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof IPackageFragment && hasChildren(children, i)) { + list.add(children[i]); + } + } + } catch (JavaModelException e) { + Logger.logError(e); + } + return list; + } + + private boolean hasChildren(Object[] children, int i) throws JavaModelException { + return (((IPackageFragment)children[i]).getChildren().length != 0) + || (((IPackageFragment)children[i]).getNonJavaResources().length != 0); + } + + public Object getParent(Object element) { + if (element == null) { + return null; + } else if (element instanceof IJavaElement) { + return ((IJavaElement)element).getParent(); + } else if (element instanceof IResource) { + IJavaElement javaElement = JavaCore.create(((IResource) element).getParent()); + if (javaElement != null) { + return javaElement; + } else { + return ((IResource)element).getParent(); + } + } + return null; + } + + public boolean hasChildren(Object element) { + if (element instanceof IPackageFragmentRoot) { + return getChildren(element).length > 0; + } else if (element instanceof IPackageFragment) { + return getChildren(element).length > 0; + } + return false; + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + asyncRefresh(viewer); + } + + private void asyncRefresh(final Viewer viewer) { + Control control = viewer.getControl(); + if (!control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + + public void run() { + if (!viewer.getControl().isDisposed()) { + viewer.refresh(); + } + } + }); + } + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesViewerFilter.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesViewerFilter.java new file mode 100644 index 0000000..a356923 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeClassesViewerFilter.java @@ -0,0 +1,20 @@ +package org.activiti.designer.eclipse.deployment; + +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; + +public class IncludeClassesViewerFilter extends ViewerFilter { + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if(element instanceof IPackageFragment) { + IPackageFragment packageFragment = (IPackageFragment) element; + if("diagrams".equalsIgnoreCase(packageFragment.getElementName()) == true) { + return false; + } + } + return true; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesTreeContentProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesTreeContentProvider.java new file mode 100644 index 0000000..d0f2622 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesTreeContentProvider.java @@ -0,0 +1,68 @@ +package org.activiti.designer.eclipse.deployment; + +import org.activiti.designer.eclipse.Logger; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Control; + +public class IncludeFilesTreeContentProvider implements ITreeContentProvider { + + public Object[] getElements(Object parent) { + if (parent instanceof IFolder) { + try { + return ((IFolder) parent).members(); + } catch (CoreException e) { + Logger.logError(e); + } + } + return new Object[0]; + } + + public Object[] getChildren(Object parent) { + try { + if (parent instanceof IFolder) { + return ((IFolder) parent).members(); + } + } catch (CoreException e) { + Logger.logError(e); + } + return new Object[0]; + } + + public Object getParent(Object element) { + if (element != null && element instanceof IResource) { + return ((IResource) element).getParent(); + } + return null; + } + + public boolean hasChildren(Object element) { + if (element instanceof IFolder) + return getChildren(element).length > 0; + return false; + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + asyncRefresh(viewer); + } + + private void asyncRefresh(final Viewer viewer) { + Control control = viewer.getControl(); + if (!control.isDisposed()) { + control.getDisplay().asyncExec(new Runnable() { + public void run() { + if (!viewer.getControl().isDisposed()) { + viewer.refresh(); + } + } + }); + } + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesViewerFilter.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesViewerFilter.java new file mode 100644 index 0000000..6ba249d --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeFilesViewerFilter.java @@ -0,0 +1,20 @@ +package org.activiti.designer.eclipse.deployment; + +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; + +public class IncludeFilesViewerFilter extends ViewerFilter { + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if(element instanceof IResource) { + IResource resource = (IResource) element; + if("xml".equalsIgnoreCase(resource.getFileExtension())) { + return true; + } + } + return false; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeInDeploymentTreeViewer.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeInDeploymentTreeViewer.java new file mode 100644 index 0000000..fc110d6 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/IncludeInDeploymentTreeViewer.java @@ -0,0 +1,88 @@ +package org.activiti.designer.eclipse.deployment; + +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.swt.widgets.Tree; + +public class IncludeInDeploymentTreeViewer extends CheckboxTreeViewer { + + public IncludeInDeploymentTreeViewer(Tree tree) { + super(tree); + addCheckStateListener(new ICheckStateListener() { + public void checkStateChanged(CheckStateChangedEvent event) { + handleCheckStateChanged(event); + } + }); + } + + private void handleCheckStateChanged(CheckStateChangedEvent event) { + updateChecks(event.getElement(), event.getChecked()); + } + + public boolean setChecked(final Object element, final boolean state) { + boolean result = super.setChecked(element, state); + if (result) { + updateChecks(element, state); + } + return result; + } + + public void setCheckedElements(final Object[] elements) { + if(elements == null) return; + super.setCheckedElements(elements); + for (int i = 0; i < elements.length; i++) { + updateChecks(elements[i], true); + } + } + + private void updateChecks(Object object, boolean state) { + updateChecksForChildren(object, state); + updateChecksForParents(object, state); + } + + private void updateChecksForChildren(Object object, boolean state) { + setGrayed(object, false); + Object[] children = ((ITreeContentProvider)getContentProvider()).getChildren(object); + for (int i = 0; i < children.length; i++) { + if (getChecked(children[i]) != state) { + super.setChecked(children[i], state); + updateChecksForChildren(children[i], state); + } + } + } + + private void updateChecksForParents(Object object, boolean state) { + ITreeContentProvider provider = (ITreeContentProvider)getContentProvider(); + Object child = object; + Object parent = provider.getParent(child); + boolean change = true; + while (parent != null && change) { + Object[] siblings = provider.getChildren(parent); + int numberChecked = 0; + boolean grayed = false; + change = false; + for (int i = 0; i < siblings.length; i++) { + if (getChecked(siblings[i])) numberChecked++; + if (getGrayed(siblings[i])) grayed = true; + } + if (numberChecked == 0) { + if (getChecked(parent) || getGrayed(parent)) change = true; + setGrayChecked(parent, false); + } + else if (numberChecked == siblings.length) { + if (!getChecked(parent) || getGrayed(parent) != grayed) change = true; + setGrayed(parent, false); + setChecked(parent, true); + } + else { + if (!getChecked(parent) || !getGrayed(parent)) change = true; + setGrayChecked(parent, true); + } + child = parent; + parent = provider.getParent(child); + } + + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/ProcessDeployer.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/ProcessDeployer.java new file mode 100644 index 0000000..e2949ec --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/deployment/ProcessDeployer.java @@ -0,0 +1,304 @@ +package org.activiti.designer.eclipse.deployment; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.net.ConnectException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.activiti.designer.eclipse.Logger; +import org.activiti.designer.eclipse.common.ActivitiPlugin; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Shell; + +public class ProcessDeployer { + Shell shell; + IFolder processFolder; + String targetLocation; + List classesAndResources; + List filesAndFolders; + boolean useCredentials = false; + //newly added variables + String activitiProPath; + + + public void setShell(Shell shell) { + this.shell = shell; + } + + public void setActivitiPropPath(String path) { + activitiProPath = path; + } + + public void setProcessFolder(IFolder processFolder) { + this.processFolder = processFolder; + } + + public void setTargetLocation(String targetLocation) { + this.targetLocation = targetLocation; + } + + public void setClassesAndResources(List classesAndResources) { + this.classesAndResources = classesAndResources; + } + + public void setFilesAndFolders(List filesAndFolders) { + this.filesAndFolders = filesAndFolders; + } + + public void setUseCredentials(boolean useCredentials) { + this.useCredentials = useCredentials; + } + + public boolean deploy() { + try { + showProgressMonitorDialog(); + showSuccessDialog(); + return true; + } + catch (ConnectException e) { + MessageDialog dialog = new MessageDialog(shell, "Server Not Found", null, + "The server could not be reached. Check your connection parameters.", + SWT.ICON_INFORMATION, new String[] { "OK" }, 0); + dialog.open(); + return false; + } + catch (IOException e) { + if (e.getMessage().contains("Server returned HTTP response code: 403 for URL")) { + MessageDialog dialog = new MessageDialog(shell, "Not Allowed", null, + "The server refused to perform the deployment. Check your credentials.", + SWT.ICON_INFORMATION, new String[] { "OK" }, 0); + dialog.open(); + return false; + } else { + showErrorDialog(e); + return false; + } + } + catch (Exception e) { + // NOTE that Error's are not caught because that might halt the JVM and mask the original Error. + showErrorDialog(e); + return false; + } + } + + public void saveWithoutDeploying() { + try { + saveParFile(createParBytes(getProjectClasspathUrls())); + } catch (Exception e) { + Logger.logError(e); + ErrorDialog dialog = new ErrorDialog(shell, + "Unexpected Exception While Saving", + "An exception happened while saving the process definition archive", + new Status( + Status.ERROR, + ActivitiPlugin.getDefault().getBundle() + .getSymbolicName(), + Status.ERROR, + "An unexpected exception caused the save operation to fail", + e), Status.ERROR); + dialog.open(); + } + } + + private void showProgressMonitorDialog() throws Exception { + ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(shell); + progressMonitorDialog.run(false, false, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) + throws InterruptedException { + try { + byte[] baos = createParBytes(getProjectClasspathUrls()); + if (targetLocation != null) { + saveParFile(baos); + } + deployProcess(); + return; + } catch (IOException e) { + if (e.getMessage().contains("Server returned HTTP response code: 403 for URL")) { + Logger.logError( + "The server refused to execute the deployment. Check your credentials.", + e); + } + } catch (Exception e) { + Logger + .logError( + "Exception happened while deploying", + e); + } + throw new InterruptedException( + "Error while deploying, look in the Error Log for more info"); + } + }); + } + + public void deployProcess() { + /*ProcessEngine processEngine = new ProcessEngineBuilder().configureFromPropertiesResource("activiti.properties").buildProcessEngine(); + ZipInputStream inputStream = null; + try { + inputStream = new ZipInputStream(new FileInputStream(targetLocation)); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + RepositoryService ser = processEngine.getRepositoryService(); + DeploymentBuilder build = ser.createDeployment(); + build.addZipInputStream(inputStream); + build.deploy();*/ + + } + + private void saveParFile(byte[] parBytes) throws IOException { + File file = new Path(targetLocation).toFile(); + String barFileName = "/activiti.bar"; + int idx = targetLocation.indexOf("."); + if(idx>0){ + idx = targetLocation.lastIndexOf("/"); + barFileName = targetLocation.substring(idx, targetLocation.length()); + targetLocation = targetLocation.substring(0, idx+1); + file = null; + file = new Path(targetLocation).toFile(); + } + if (!file.exists()) { + file.mkdirs(); + } + targetLocation = file.getAbsolutePath()+barFileName; + file = null; + file = new Path(targetLocation).toFile(); + if (!file.exists()) { + file.createNewFile(); + } + FileOutputStream fos = new FileOutputStream(file); + fos.write(parBytes); + fos.close(); + } + + private byte[] createParBytes(URL[] urls) throws Exception { + URLClassLoader newLoader = new URLClassLoader(urls, getClass() + .getClassLoader()); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream); + addFilesAndFolders(zipOutputStream); + addClassesAndResources(zipOutputStream, newLoader); + zipOutputStream.close(); + return byteArrayOutputStream.toByteArray(); + } + + private void addFilesAndFolders(ZipOutputStream zipOutputStream) throws Exception { + for (int i = 0; i < filesAndFolders.size(); i++) { + IResource resource = (IResource)filesAndFolders.get(i); + int index = processFolder.getProjectRelativePath().toString().length() + 1; + addFile(zipOutputStream, resource.getProjectRelativePath().toString().substring(index)); + } + } + + private void showSuccessDialog() { + MessageDialog dialog = new MessageDialog(shell, "Deployment Successful", null, + "The process archive deployed successfully.", + SWT.ICON_INFORMATION, new String[] { "OK" }, 0); + dialog.open(); + } + + private void showErrorDialog(Throwable t) { + ErrorDialog dialog = new ErrorDialog(shell, + "Unexpected Deployment Exception", + "An exception happened during the deployment of the process", + new Status( + Status.ERROR, + ActivitiPlugin.getDefault().getBundle() + .getSymbolicName(), + Status.ERROR, + "An unexpected exception caused the deployment to fail", + t), Status.ERROR); + dialog.open(); + } + + private void addClassesAndResources(ZipOutputStream zos, ClassLoader loader) + throws CoreException, IOException { + for (int i = 0; i < classesAndResources.size(); i++) { + addClassOrResource(zos, loader, (String)classesAndResources.get(i)); + } + } + + private void addClassOrResource(ZipOutputStream zos, ClassLoader loader, String classOrResource) throws IOException { + byte[] buff = new byte[256]; + zos.putNextEntry(new ZipEntry(classOrResource)); + InputStream is = loader.getResourceAsStream(classOrResource); + int read; + while ((read = is.read(buff)) != -1) { + zos.write(buff, 0, read); + } + is.close(); + if (classOrResource.endsWith(".class")) { + final String className = + classOrResource.substring(classOrResource.lastIndexOf('/') + 1, classOrResource.length() - 6) + '$'; + URL url = loader.getResource(classOrResource); + File file = new File(url.getFile()); + File folder = new File(file.getParent()); + String nestedClasses[] = folder.list(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.startsWith(className); + } + }); + if (nestedClasses != null) { + for (int i = 0; i < nestedClasses.length; i++) { + String fileName = classOrResource.substring(0, classOrResource.lastIndexOf("/") + 1) + nestedClasses[i]; + zos.putNextEntry(new ZipEntry(fileName)); + is = loader.getResourceAsStream(fileName); + while ((read = is.read(buff)) != -1) { + zos.write(buff, 0, read); + } + is.close(); + } + } + } + } + + private void addFile(ZipOutputStream zos, String fileName) + throws CoreException, IOException { + byte[] buff = new byte[256]; + IFile file = processFolder.getFile(fileName); + if (!file.exists()) return; + InputStream is = file.getContents(); + zos.putNextEntry(new ZipEntry(fileName)); + int read; + while ((read = is.read(buff)) != -1) { + zos.write(buff, 0, read); + } + } + + private URL[] getProjectClasspathUrls() throws CoreException, MalformedURLException { + IProject project = processFolder.getProject(); + IJavaProject javaProject = JavaCore.create(project); + String[] pathArray = JavaRuntime + .computeDefaultRuntimeClassPath(javaProject); + URL[] urls = new URL[pathArray.length]; + for (int i = 0; i < pathArray.length; i++) { + urls[i] = new File(pathArray[i]).toURI().toURL(); + } + return urls; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiBMPN2Editor.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiBMPN2Editor.java new file mode 100644 index 0000000..82554da --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiBMPN2Editor.java @@ -0,0 +1,107 @@ +package org.activiti.designer.eclipse.editor; + +import java.io.File; + +import org.activiti.designer.eclipse.bpmnimport.ImportBpmnUtil; +import org.activiti.designer.eclipse.common.ActivitiPlugin; +import org.activiti.designer.eclipse.editor.sync.DiagramUpdater; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.ui.internal.services.GraphitiUiInternal; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.PartInitException; +import org.eclipse.wst.sse.ui.StructuredTextEditor; + +public class ActivitiBMPN2Editor extends StructuredTextEditor { + + @Override + public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException { + IFile associatedBPMN2File = ((IFileEditorInput) editorInput).getFile(); + final IFile diagramFile = getAssociatedDiagramIFile(associatedBPMN2File); + if(diagramFile.exists() == false) { + String bpmnFile = associatedBPMN2File.getRawLocation().toFile().getAbsolutePath(); + String processName = bpmnFile.substring(bpmnFile.lastIndexOf(File.separator) + 1); + processName = processName.replace(".xml", ""); + processName = processName.replace(".bpmn20", ""); + ImportBpmnUtil.createDiagram(processName, bpmnFile, + associatedBPMN2File.getProject(), associatedBPMN2File.getParent()); + } + super.init(site, editorInput); + } + + @Override + public void doSave(IProgressMonitor progressMonitor) { + super.doSave(progressMonitor); + IFile associatedBPMN2File = ((IFileEditorInput) getEditorInput()).getFile(); + final IFile diagramFile = getAssociatedDiagramIFile(associatedBPMN2File); + if(diagramFile.exists() == false) { + String bpmnFile = associatedBPMN2File.getRawLocation().toFile().getAbsolutePath(); + String processName = bpmnFile.substring(bpmnFile.lastIndexOf(File.separator) + 1); + processName = processName.replace(".xml", ""); + processName = processName.replace(".bpmn20", ""); + ImportBpmnUtil.createDiagram(processName, bpmnFile, + associatedBPMN2File.getProject(), associatedBPMN2File.getParent()); + + } else { + ResourceSet resourceSet = new ResourceSetImpl(); + TransactionalEditingDomain domain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain(resourceSet); + final Diagram diagram = GraphitiUiInternal.getEmfService().getDiagramFromFile(diagramFile, domain.getResourceSet()); + domain.getResourceSet().getResources().add(diagram.eResource()); + + try { + + final IStorage storage = ((IFileEditorInput) getEditorInput()).getStorage(); + DiagramUpdater operation = new DiagramUpdater( + domain, diagram, storage); + domain.getCommandStack().execute(operation); + + diagram.eResource().save(null); + } catch (Exception e) { + IStatus status = new Status(IStatus.ERROR, ActivitiPlugin.getID(), e.getMessage(), e); //$NON-NLS-1$ + ErrorDialog.openError(Display.getCurrent().getActiveShell(), "Failed to synchronize Activiti model file", e.getMessage(), status); + } + + // Dispose the editing domain to eliminate memory leak + domain.dispose(); + } + } + + + + private IFile getAssociatedDiagramIFile(final IFile bpmnFile) { + + IPath path = getAssociatedDiagramURI(bpmnFile); + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final IFile diagramFile = workspace.getRoot().getFile(path); + + return diagramFile; + } + + private IPath getAssociatedDiagramURI(final IFile bpmnFile) { + + final IPath originalPath = bpmnFile.getFullPath(); + + final IPath parentPath = originalPath.removeLastSegments(1); + + String finalSegment = originalPath.lastSegment(); + finalSegment = finalSegment.replace(".bpmn20.xml", ".activiti"); + final IPath returnPath = parentPath.append(new Path(finalSegment)); + return returnPath; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiDiagramEditor.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiDiagramEditor.java new file mode 100644 index 0000000..e8b14b7 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiDiagramEditor.java @@ -0,0 +1,176 @@ +package org.activiti.designer.eclipse.editor; + +import java.util.Collection; +import java.util.List; + +import org.activiti.designer.eclipse.Logger; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.activiti.designer.eclipse.extension.export.SequenceFlowSynchronizer; +import org.activiti.designer.eclipse.ui.ActivitiEditorContextMenuProvider; +import org.activiti.designer.eclipse.ui.ExportMarshallerRunnable; +import org.activiti.designer.eclipse.util.ExtensionPointUtil; +import org.activiti.designer.util.eclipse.ActivitiUiUtil; +import org.eclipse.bpmn2.Task; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.draw2d.IFigure; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.ContextMenuProvider; +import org.eclipse.gef.GraphicalViewer; +import org.eclipse.gef.LayerConstants; +import org.eclipse.gef.editparts.LayerManager; +import org.eclipse.gef.editparts.ScalableFreeformRootEditPart; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.algorithms.MultiText; +import org.eclipse.graphiti.mm.algorithms.Text; +import org.eclipse.graphiti.mm.algorithms.styles.Orientation; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.Shape; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +import org.eclipse.graphiti.ui.editor.DiagramEditorInput; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.progress.IProgressService; + +public class ActivitiDiagramEditor extends DiagramEditor { + + public final static String ID = "org.activiti.designer.diagmrameditor"; //$NON-NLS-1$ + private static GraphicalViewer activeGraphicalViewer; + + public ActivitiDiagramEditor() { + super(); + } + + @Override + public void init(IEditorSite site, IEditorInput input) throws PartInitException { + super.init(site, input); + } + + @Override + public void createPartControl(Composite parent) { + super.createPartControl(parent); + GraphicalViewer graphicalViewer = (GraphicalViewer) getAdapter(GraphicalViewer.class); + if (graphicalViewer != null && graphicalViewer.getEditPartRegistry() != null) { + ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart) graphicalViewer.getEditPartRegistry().get(LayerManager.ID); + IFigure gridFigure = ((LayerManager) rootEditPart).getLayer(LayerConstants.GRID_LAYER); + gridFigure.setVisible(false); + } + } + + @SuppressWarnings("rawtypes") + @Override + public Object getAdapter(Class type) { + return super.getAdapter(type); + } + + @Override + public void doSave(final IProgressMonitor monitor) { + // Get a reference to the editor part + + final IEditorPart editorPart = getEditorSite().getPage().getActiveEditor(); + final DiagramEditorInput editorInput; + + editorInput = (DiagramEditorInput) editorPart.getEditorInput(); + SequenceFlowSynchronizer.synchronize(editorInput.getDiagram() + .getConnections(), (DiagramEditor) editorPart); + + activeGraphicalViewer = (GraphicalViewer) getAdapter(GraphicalViewer.class); + + // Regular save + try { + super.doSave(monitor); + } catch(Throwable e) { + e.printStackTrace(); + } + + // Determine list of ExportMarshallers to invoke after regular save + final Collection marshallers = ExtensionPointUtil + .getActiveExportMarshallers(); + + if (marshallers.size() > 0) { + // Get the resource belonging to the editor part + final Diagram diagram = editorInput.getDiagram(); + + // Get the progress service so we can have a progress monitor + final IProgressService progressService = PlatformUI.getWorkbench() + .getProgressService(); + + try { + final ExportMarshallerRunnable runnable = new ExportMarshallerRunnable( + diagram, marshallers); + progressService.busyCursorWhile(runnable); + } catch (Exception e) { + Logger.logError("Exception while performing save", e); + } + } + } + + @Override + protected void setInput(final IEditorInput input) { + super.setInput(input); + if(input instanceof DiagramEditorInput) { + final Diagram diagram = ((DiagramEditorInput) input).getDiagram(); + boolean shouldMigrate = Graphiti.getMigrationService().shouldMigrate070To080(diagram); + if(shouldMigrate) { + ActivitiUiUtil.runModelChange(new Runnable() { + public void run() { + setTransparencyAndLineWidth(diagram, diagram); + Graphiti.getMigrationService().migrate070To080(diagram); + } + }, getEditingDomain(), "Mirgation from Graphiti 0.7 to 0.8"); + } + } + } + + private void setTransparencyAndLineWidth(ContainerShape parent, Diagram diagram) { + List shapes = parent.getChildren(); + for (Shape shape : shapes) { + if(shape instanceof ContainerShape) { + GraphicsAlgorithm graphics = ((ContainerShape) shape).getGraphicsAlgorithm(); + graphics.setLineWidth(1); + graphics.setTransparency(0.0); + List graphicsChildren = graphics.getGraphicsAlgorithmChildren(); + for (GraphicsAlgorithm graphicsAlgorithm : graphicsChildren) { + if(graphicsAlgorithm.getLineWidth() == null || graphicsAlgorithm.getLineWidth() <= 1) { + graphicsAlgorithm.setLineWidth(1); + } + graphicsAlgorithm.setTransparency(0.0); + } + setTransparencyAndLineWidth((ContainerShape) shape, diagram); + + } else if(shape.getGraphicsAlgorithm() != null && shape.getGraphicsAlgorithm() instanceof Text) { + if(parent.getLink().getBusinessObjects() != null && parent.getLink().getBusinessObjects().size() > 0) { + EObject object = parent.getLink().getBusinessObjects().get(0); + if(object instanceof Task) { + Text text = (Text) shape.getGraphicsAlgorithm(); + MultiText multiText = Graphiti.getGaService().createDefaultMultiText(diagram, shape, text.getValue()); + multiText.setStyle(text.getStyle()); + multiText.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER); + multiText.setVerticalAlignment(Orientation.ALIGNMENT_CENTER); + multiText.setFont(text.getFont()); + multiText.setX(text.getX()); + multiText.setY(text.getY()); + multiText.setHeight(30); + multiText.setWidth(text.getWidth()); + shape.setGraphicsAlgorithm(multiText); + } + } + } + } + } + + @Override + protected ContextMenuProvider createContextMenuProvider() { + return new ActivitiEditorContextMenuProvider(getGraphicalViewer(), + getActionRegistry(), getConfigurationProvider()); + } + + public static GraphicalViewer getActiveGraphicalViewer() { + return activeGraphicalViewer; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiMultiPageEditor.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiMultiPageEditor.java new file mode 100644 index 0000000..34ca8bf --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/ActivitiMultiPageEditor.java @@ -0,0 +1,288 @@ +package org.activiti.designer.eclipse.editor; + +import java.io.File; + +import org.activiti.designer.eclipse.bpmnimport.ImportBpmnUtil; +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.editor.sync.DiagramUpdater; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IStorage; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.content.IContentDescription; +import org.eclipse.core.runtime.content.IContentType; +import org.eclipse.draw2d.IFigure; +import org.eclipse.emf.common.util.URI; +import org.eclipse.gef.GraphicalViewer; +import org.eclipse.gef.LayerConstants; +import org.eclipse.gef.editparts.LayerManager; +import org.eclipse.gef.editparts.ScalableFreeformRootEditPart; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.ui.editor.DiagramEditorFactory; +import org.eclipse.graphiti.ui.editor.DiagramEditorInput; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.part.MultiPageEditorPart; +import org.eclipse.wst.sse.ui.StructuredTextEditor; + +/** + * @author Yvo Swillens + * @since 0.6.1 + * @version 1 + * + */ +public class ActivitiMultiPageEditor extends MultiPageEditorPart implements IResourceChangeListener { + + private static final String DIAGRAM_PANE_TILE = "Diagram"; + private static final String XML_PANE_TITLE = "BPMN2.0"; + + /** The diagram editor used in page 0. */ + private ActivitiDiagramEditor diagramEditor; + + /** The XML editor used in page 1. */ + private StructuredTextEditor bpmnEditor; + + private IFile associatedBPMN2File; + + /** + * Creates a multi-page editor example. + */ + public ActivitiMultiPageEditor() { + super(); + ResourcesPlugin.getWorkspace().addResourceChangeListener(this); + } + + private void createDiagramPage() { + + try { + diagramEditor = new ActivitiDiagramEditor(); + int index = addPage(diagramEditor, getEditorInput()); + setPageText(index, ActivitiMultiPageEditor.DIAGRAM_PANE_TILE); + GraphicalViewer graphicalViewer = (GraphicalViewer) diagramEditor.getAdapter(GraphicalViewer.class); + if (graphicalViewer != null && graphicalViewer.getEditPartRegistry() != null) { + ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart) graphicalViewer.getEditPartRegistry().get(LayerManager.ID); + IFigure gridFigure = ((LayerManager) rootEditPart).getLayer(LayerConstants.GRID_LAYER); + gridFigure.setVisible(false); + } + } catch (PartInitException e) { + ErrorDialog.openError(getSite().getShell(), "Error creating nested Activiti Diagram editor", null, e.getStatus()); + } + } + + private void createBPMN2Page() { + try { + bpmnEditor = new StructuredTextEditor(); + int index = addPage(bpmnEditor, getBPMN2EditorInput()); + setPageText(index, ActivitiMultiPageEditor.XML_PANE_TITLE); + } catch (PartInitException e) { + ErrorDialog.openError(getSite().getShell(), "Error creating nested Activiti BPMN2.0 editor", null, e.getStatus()); + } + } + /** + * Creates the pages of the multi-page editor. + */ + protected void createPages() { + createDiagramPage(); + createBPMN2Page(); + } + + public void dispose() { + ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); + super.dispose(); + } + + public void doSave(IProgressMonitor monitor) { + int activePage = getActivePage(); + if (activePage == 0) { + getEditor(0).doSave(monitor); + } else if (activePage == 1) { + + // Save BPMN editor contents + getEditor(1).doSave(monitor); + + // sync Activiti Diagram + DiagramEditorInput diagramEditorInput = (DiagramEditorInput) getEditor(0).getEditorInput(); + Diagram diagram = diagramEditorInput.getDiagram(); + FileEditorInput bpmn2EditorInput = (FileEditorInput) getEditor(1).getEditorInput(); + + IStorage bpmnStorage = bpmn2EditorInput.getStorage(); + //DiagramUpdater.syncDiagram(diagramEditor, diagram, bpmnStorage); + + // Save BPMN editor contents + getEditor(0).doSave(monitor); + } + } + + public void doSaveAs() { + int activePage = getActivePage(); + if (activePage == 0) { + IEditorPart editor = getEditor(0); + editor.doSaveAs(); + setPageText(0, editor.getTitle()); + setInput(editor.getEditorInput()); + } else if (activePage == 1) { + IEditorPart editor = getEditor(1); + editor.doSaveAs(); + setPageText(1, editor.getTitle()); + setInput(editor.getEditorInput()); + } + } + + public void gotoMarker(IMarker marker) { + setActivePage(0); + IDE.gotoMarker(getEditor(0), marker); + } + + public void init(IEditorSite site, IEditorInput editorInput) throws PartInitException { + if (!(editorInput instanceof IFileEditorInput) && !(editorInput instanceof DiagramEditorInput)) + throw new PartInitException("Invalid Input: Must be Activiti Diagram or BPMN2.0 XML"); + + // checks if the editor was opened with non Diagram file + if (editorInput instanceof IFileEditorInput) { + + if (isBPM2FileType((IFileEditorInput) editorInput)) { + associatedBPMN2File = ((IFileEditorInput) editorInput).getFile(); + final IFile diagramFile = getAssociatedDiagramIFile(associatedBPMN2File); + if(diagramFile.exists() == false) { + String bpmnFile = associatedBPMN2File.getRawLocation().toFile().getAbsolutePath(); + String processName = bpmnFile.substring(bpmnFile.lastIndexOf(File.separator) + 1); + processName = processName.replace(".xml", ""); + processName = processName.replace(".bpmn20", ""); + ImportBpmnUtil.createDiagram(processName, bpmnFile, + associatedBPMN2File.getProject(), associatedBPMN2File.getParent()); + } + final IEditorInput diagramFileEditorInput = new FileEditorInput(diagramFile); + + // creates DiagramEditorInput from FileEditorInput + editorInput = new DiagramEditorFactory().createEditorInput(diagramFileEditorInput); + } + } + super.init(site, editorInput); + } + + public boolean isSaveAsAllowed() { + return true; + } + + public ActivitiDiagramEditor getActivitiDiagramEditor() { + IEditorPart editor = getEditor(0); + return (ActivitiDiagramEditor) editor; + } + + /** + * Closes all project files on project close. + */ + public void resourceChanged(final IResourceChangeEvent event) { + if (event.getType() == IResourceChangeEvent.PRE_CLOSE) { + Display.getDefault().asyncExec(new Runnable() { + + public void run() { + IWorkbenchPage[] pages = getSite().getWorkbenchWindow().getPages(); + for (int i = 0; i < pages.length; i++) { + if (((FileEditorInput) bpmnEditor.getEditorInput()).getFile().getProject().equals(event.getResource())) { + IEditorPart editorPart = pages[i].findEditor(bpmnEditor.getEditorInput()); + pages[i].closeEditor(editorPart, true); + } + } + } + }); + } + } + + /** + * Reloads contents of BPMN2 pane when selected + */ + protected void pageChange(int newPageIndex) { + super.pageChange(newPageIndex); + if (newPageIndex == 1) { + bpmnEditor.setInput(getBPMN2EditorInput()); + bpmnEditor.doRevertToSaved(); + } + } + + private IFile getAssociatedBPMN2IFile() { + + URI uri = getAssociatedBPMN2URI(); + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final IFile bpmn20File = workspace.getRoot().getFile(new Path(uri.toPlatformString(true))); + + return bpmn20File; + } + + private URI getAssociatedBPMN2URI() { + + final Diagram diagram = ((DiagramEditorInput) diagramEditor.getEditorInput()).getDiagram(); + final URI originalURI = diagram.eResource().getURI(); + final URI parentURI = originalURI.trimSegments(1); + final String REGEX_FILENAME = "\\$originalFile"; + + String finalSegment = "$originalFile" + ".bpmn20.xml"; + finalSegment = finalSegment.replaceAll(REGEX_FILENAME, originalURI.lastSegment().substring( + 0, originalURI.lastSegment().indexOf("."))); + + return parentURI.appendSegment(finalSegment); + } + + private IFile getAssociatedDiagramIFile(final IFile bpmnFile) { + + IPath path = getAssociatedDiagramURI(bpmnFile); + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final IFile diagramFile = workspace.getRoot().getFile(path); + + return diagramFile; + } + + private IPath getAssociatedDiagramURI(final IFile bpmnFile) { + + final IPath originalPath = bpmnFile.getFullPath(); + + final IPath parentPath = originalPath.removeLastSegments(1); + + String finalSegment = originalPath.lastSegment(); + finalSegment = finalSegment.replace(".bpmn20.xml", ".activiti"); + final IPath returnPath = parentPath.append(new Path(finalSegment)); + return returnPath; + } + + private IFileEditorInput getBPMN2EditorInput() { + associatedBPMN2File = getAssociatedBPMN2IFile(); + return new FileEditorInput(associatedBPMN2File); + } + + private boolean isBPM2FileType(final IFileEditorInput editorInput) { + + boolean isBPMN2File = false; + IFile file = editorInput.getFile(); + try { + IContentDescription desc = file.getContentDescription(); + if (desc != null) { + IContentType type = desc.getContentType(); + if (ActivitiBPMNDiagramConstants.BPMN2_CONTENTTYPE_ID.equals(type.getId())) { + isBPMN2File = true; + } + } + } catch (CoreException e) { + e.printStackTrace(); + return isBPMN2File; + } + + return isBPMN2File; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/sync/DiagramUpdater.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/sync/DiagramUpdater.java new file mode 100644 index 0000000..b20f62d --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/editor/sync/DiagramUpdater.java @@ -0,0 +1,343 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @Autor Yvo Swillens + * + * Updates existing (Flow)elements in Activiti Diagram + * based on elements in BPMN2.0.xml + */ +package org.activiti.designer.eclipse.editor.sync; + +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.List; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; + +import org.activiti.designer.eclipse.bpmn.BpmnParser; +import org.activiti.designer.eclipse.bpmn.SequenceFlowModel; +import org.eclipse.bpmn2.BaseElement; +import org.eclipse.bpmn2.BusinessRuleTask; +import org.eclipse.bpmn2.CandidateGroup; +import org.eclipse.bpmn2.CandidateUser; +import org.eclipse.bpmn2.FieldExtension; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.MailTask; +import org.eclipse.bpmn2.ScriptTask; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.bpmn2.ServiceTask; +import org.eclipse.bpmn2.Task; +import org.eclipse.bpmn2.UserTask; +import org.eclipse.core.resources.IStorage; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.graphiti.dt.IDiagramTypeProvider; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.IReason; +import org.eclipse.graphiti.features.IUpdateFeature; +import org.eclipse.graphiti.features.context.impl.UpdateContext; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.ui.services.GraphitiUi; + +/** + * @author Yvo Swillens + */ +public class DiagramUpdater extends RecordingCommand { + + Diagram diagram; + IStorage bpmnStorage; + + public DiagramUpdater(TransactionalEditingDomain editingDomain, + Diagram diagram, IStorage bpmnStorage) { + + super(editingDomain); + this.diagram = diagram; + this.bpmnStorage = bpmnStorage; + } + + @Override + protected void doExecute() { + syncDiagram(); + } + + private void syncDiagram() { + + if (diagram == null) { + System.out.println("diagram cannot be null"); + return; + } + if (bpmnStorage == null) { + System.out.println("bpmnStorage cannot be null"); + return; + } + + IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, + GraphitiUi.getExtensionManager().getDiagramTypeProviderId(diagram.getDiagramTypeId())); //$NON-NLS-1$ + IFeatureProvider featureProvider = dtp.getFeatureProvider(); + + BpmnParser bpmnParser = readBpmn(bpmnStorage); + + if (bpmnParser.process != null) { + updateProcessInDiagram(diagram, bpmnParser.process); + } + + if (bpmnParser.bpmnList == null || bpmnParser.bpmnList.size() == 0) + return; + + updateFlowElementsInDiagram(diagram, bpmnParser.bpmnList, featureProvider); + + if (bpmnParser.sequenceFlowList == null || bpmnParser.sequenceFlowList.size() == 0) + return; + + updateSequenceFlowsInDiagram(diagram, bpmnParser.sequenceFlowList); + } + + private static BpmnParser readBpmn(IStorage bpmnStorage) { + + BpmnParser bpmnParser = new BpmnParser(); + try { + XMLInputFactory xif = XMLInputFactory.newInstance(); + InputStreamReader in = new InputStreamReader(bpmnStorage.getContents(), "UTF-8"); + XMLStreamReader xtr = xif.createXMLStreamReader(in); + + bpmnParser.parseBpmn(xtr); + + xtr.close(); + in.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + return bpmnParser; + } + + private static void updateFlowElementsInDiagram(final Diagram diagram, final List bpmnFlowElements, + IFeatureProvider featureProvider) { + + for (FlowElement bpmnFlowElement : bpmnFlowElements) { + FlowElement diagramFlowElement = lookupFlowElementInDiagram(bpmnFlowElement, diagram); + if (diagramFlowElement != null) { + + diagramFlowElement.setName(bpmnFlowElement.getName()); + + if (diagramFlowElement instanceof UserTask && bpmnFlowElement instanceof UserTask) { + + UserTask targetUserTask = (UserTask) diagramFlowElement; + UserTask parsedUserTask = (UserTask) bpmnFlowElement; + + targetUserTask.setAssignee(parsedUserTask.getAssignee()); + targetUserTask.setFormKey(parsedUserTask.getFormKey()); + targetUserTask.setPriority(parsedUserTask.getPriority()); + targetUserTask.setDueDate(parsedUserTask.getDueDate()); + + targetUserTask.getFormProperties().clear(); + targetUserTask.getFormProperties().addAll(parsedUserTask.getFormProperties()); + + Iterator itCandidateGroup = targetUserTask.getCandidateGroups().iterator(); + while (itCandidateGroup.hasNext()) { + diagram.eResource().getContents().remove(itCandidateGroup.next()); + } + targetUserTask.getCandidateGroups().clear(); + + if (parsedUserTask.getCandidateGroups() != null) { + for (CandidateGroup candidateGroup : parsedUserTask.getCandidateGroups()) { + diagram.eResource().getContents().add(candidateGroup); + targetUserTask.getCandidateGroups().add(candidateGroup); + } + } + + Iterator itCandidateUser = targetUserTask.getCandidateUsers().iterator(); + while (itCandidateUser.hasNext()) { + diagram.eResource().getContents().remove(itCandidateUser.next()); + } + targetUserTask.getCandidateUsers().clear(); + + if (parsedUserTask.getCandidateUsers() != null) { + for (CandidateUser candidateUser : parsedUserTask.getCandidateUsers()) { + diagram.eResource().getContents().add(candidateUser); + targetUserTask.getCandidateUsers().add(candidateUser); + } + } + + } else if (diagramFlowElement instanceof ScriptTask && bpmnFlowElement instanceof ScriptTask) { + + ScriptTask targetScriptTask = (ScriptTask) diagramFlowElement; + ScriptTask parsedScriptTask = (ScriptTask) bpmnFlowElement; + + targetScriptTask.setScriptFormat(parsedScriptTask.getScriptFormat()); + targetScriptTask.setScript(parsedScriptTask.getScript()); + + } else if (diagramFlowElement instanceof ServiceTask && bpmnFlowElement instanceof ServiceTask) { + + ServiceTask targetServiceTask = (ServiceTask) diagramFlowElement; + ServiceTask parsedServiceTask = (ServiceTask) bpmnFlowElement; + + targetServiceTask.setImplementationType(parsedServiceTask.getImplementationType()); + targetServiceTask.setImplementation(parsedServiceTask.getImplementation()); + targetServiceTask.setResultVariableName(parsedServiceTask.getResultVariableName()); + + Iterator itField = targetServiceTask.getFieldExtensions().iterator(); + while (itField.hasNext()) { + diagram.eResource().getContents().remove(itField.next()); + } + targetServiceTask.getFieldExtensions().clear(); + + if (parsedServiceTask.getFieldExtensions() != null) { + for (FieldExtension fieldExtension : parsedServiceTask.getFieldExtensions()) { + diagram.eResource().getContents().add(fieldExtension); + targetServiceTask.getFieldExtensions().add(fieldExtension); + } + } + + } else if (diagramFlowElement instanceof BusinessRuleTask && bpmnFlowElement instanceof BusinessRuleTask) { + + BusinessRuleTask targetBusinessRuleTask = (BusinessRuleTask) diagramFlowElement; + BusinessRuleTask parsedBusinessRuleTask = (BusinessRuleTask) bpmnFlowElement; + + targetBusinessRuleTask.setResultVariableName(parsedBusinessRuleTask.getResultVariableName()); + targetBusinessRuleTask.setExclude(parsedBusinessRuleTask.isExclude()); + + targetBusinessRuleTask.getRuleNames().clear(); + targetBusinessRuleTask.getRuleNames().addAll(parsedBusinessRuleTask.getRuleNames()); + + targetBusinessRuleTask.getInputVariables().clear(); + targetBusinessRuleTask.getInputVariables().addAll(parsedBusinessRuleTask.getInputVariables()); + + } else if (diagramFlowElement instanceof MailTask && bpmnFlowElement instanceof MailTask) { + + MailTask targetMailTask = (MailTask) diagramFlowElement; + MailTask parsedMailTask = (MailTask) bpmnFlowElement; + + targetMailTask.setBcc(parsedMailTask.getBcc()); + targetMailTask.setCc(parsedMailTask.getCc()); + targetMailTask.setFrom(parsedMailTask.getFrom()); + targetMailTask.setHtml(parsedMailTask.getHtml()); + targetMailTask.setSubject(parsedMailTask.getSubject()); + targetMailTask.setText(parsedMailTask.getText()); + targetMailTask.setTo(parsedMailTask.getTo()); + } + + if (diagramFlowElement instanceof Task && bpmnFlowElement instanceof Task) { + + Task targetTask = (Task) diagramFlowElement; + Task parsedTask = (Task) bpmnFlowElement; + + targetTask.setLoopCharacteristics(parsedTask.getLoopCharacteristics()); + targetTask.setAsynchronous(parsedTask.isAsynchronous()); + + targetTask.getActivitiListeners().clear(); + if (parsedTask.getActivitiListeners() != null) { + targetTask.getActivitiListeners().addAll(parsedTask.getActivitiListeners()); + } + } + + updatePictogramContext(diagramFlowElement, featureProvider); + } + } + } + + private static void updateSequenceFlowsInDiagram(final Diagram diagram, + final List sequenceFlowElements) { + + for (SequenceFlowModel sequenceFlowModel : sequenceFlowElements) { + SequenceFlow diagramFlowElement = lookupSequenceFlowInDiagram(sequenceFlowModel, diagram); + if (diagramFlowElement != null) { + + if (sequenceFlowModel.conditionExpression != null) { + diagramFlowElement.setConditionExpression(sequenceFlowModel.conditionExpression); + } + if (sequenceFlowModel.listenerList != null) { + diagramFlowElement.getExecutionListeners().clear(); + diagramFlowElement.getExecutionListeners().addAll(sequenceFlowModel.listenerList); + } + } + } + } + + private static void updateProcessInDiagram(final Diagram diagram, final org.eclipse.bpmn2.Process process) { + + org.eclipse.bpmn2.Process diagramElement = lookupProcessInDiagram(diagram); + if (diagramElement != null) { + + if (process.getExecutionListeners() != null) { + diagramElement.getExecutionListeners().clear(); + diagramElement.getExecutionListeners().addAll(process.getExecutionListeners()); + } + } + } + + private static void updatePictogramContext(BaseElement source, IFeatureProvider featureProvider) { + + PictogramElement pictoElem = featureProvider.getPictogramElementForBusinessObject(source); + UpdateContext context = new UpdateContext(pictoElem); + IUpdateFeature feature = featureProvider.getUpdateFeature(context); + if (feature.canUpdate(context)) { + IReason reason = feature.updateNeeded(context); + if (reason.toBoolean()) { + feature.update(context); + } + } + } + + private static FlowElement lookupFlowElementInDiagram(FlowElement sourceElement, Diagram diagram) { + + FlowElement modifyElement = null; + for (EObject targetElement : diagram.eResource().getContents()) { + + if ((targetElement instanceof FlowElement) && flowIdIsEqual(sourceElement, (FlowElement) targetElement)) { + modifyElement = (FlowElement) targetElement; + break; + } + } + return modifyElement; + } + + private static boolean flowIdIsEqual(FlowElement f1, FlowElement f2) { + + return f1.getId().equalsIgnoreCase(f2.getId()); + } + + private static SequenceFlow lookupSequenceFlowInDiagram(SequenceFlowModel sequenceModel, Diagram diagram) { + + SequenceFlow modifyElement = null; + for (EObject targetElement : diagram.eResource().getContents()) { + + if ((targetElement instanceof SequenceFlow)) { + SequenceFlow sequenceFlow = (SequenceFlow) targetElement; + if (sequenceModel.sourceRef.equals(sequenceFlow.getSourceRef().getId()) && sequenceModel.targetRef.equals(sequenceFlow.getTargetRef().getId())) { + + modifyElement = sequenceFlow; + break; + } + } + } + return modifyElement; + } + + private static org.eclipse.bpmn2.Process lookupProcessInDiagram(Diagram diagram) { + + org.eclipse.bpmn2.Process process = null; + for (EObject targetElement : diagram.eResource().getContents()) { + + if ((targetElement instanceof org.eclipse.bpmn2.Process)) { + process = (org.eclipse.bpmn2.Process) targetElement; + break; + } + } + return process; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/AbstractDiagramWorker.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/AbstractDiagramWorker.java new file mode 100644 index 0000000..8d5ebfd --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/AbstractDiagramWorker.java @@ -0,0 +1,386 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.activiti.designer.eclipse.extension; + +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.extension.export.ExportMarshaller; +import org.activiti.designer.eclipse.extension.validation.ProcessValidator; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +/** + * Abstract base class for diagram workers, such as {@link ExportMarshaller}s + * and {@link ProcessValidator}s. + * + * @author Tiese Barrell + * @since 0.6.1 + * @version 2 + */ +public abstract class AbstractDiagramWorker { + + public static final String ATTRIBUTE_NODE_ID = "nodeId"; + public static final String ATTRIBUTE_WORKER_ID = "workerId"; + + private static final String DATE_TIME_PATTERN = "yyyy-MM-dd-HH-mm-ss"; + + private static final SimpleDateFormat SDF = new SimpleDateFormat(DATE_TIME_PATTERN); + + private static final String REGEX_DATE_TIME = "\\" + ExportMarshaller.PLACEHOLDER_DATE_TIME + ""; + private static final String REGEX_FILENAME = "\\" + ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME + ""; + private static final String REGEX_FILENAME_WITHOUT_EXTENSION = "\\" + ExportMarshaller.PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION + ""; + private static final String REGEX_EXTENSION = "\\" + ExportMarshaller.PLACEHOLDER_ORIGINAL_FILE_EXTENSION + ""; + + private static final int EXTRACTION_WORK_UNIT = 1; + + /** + * Gets an {@link InputStream} to the contents of the provided {@link Diagram} + * . + * + * @param diagram + * the diagram to get the input stream for + * @return an input stream to the diagram's contents + */ + protected InputStream getInputStreamForDiagram(final Diagram diagram) { + + InputStream result = null; + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + final IFile file = workspace.getRoot().getFile(new Path(getResourceForDiagram(diagram).getURI().toPlatformString(true))); + + try { + result = file.getContents(); + } catch (CoreException e) { + + } + return result; + } + + /** + * Gets the {@link Resource} associated with the provided {@link Diagram}. + * + * @param diagram + * the diagram to find the resource for + * @return the resource associated with the diagram + */ + protected Resource getResourceForDiagram(final Diagram diagram) { + return diagram.eResource(); + } + + /** + * Gets the {@link URI} associated with the provided {@link Diagram}'s + * resource. + * + * @param diagram + * the diagram to find the URI for + * @return the URI for the resource associated with the diagram + */ + protected URI getURIForDiagram(final Diagram diagram) { + return getResourceForDiagram(diagram).getURI(); + } + + /** + * Gets a new URI based on the provided {@link Diagram}s location and relative + * to the resource associated to the {@link Diagram}. + * + *

    + * If replacement of {@link ExportMarshaller}'s replacement variables is + * required, the provided relativePath should contain these variables in the + * final segment of the path. Replacement variables in other segments will not + * be parsed and will result in exceptions. + * + *

    + * Example usage: + *

    + * if you wish to get a URI for a file named "my-file.xml" to be saved in the + * same directory as the original diagram, you would use:
    + * {@link #getRelativeURIForDiagram(diagram, "my-file.xml")}. + *

    + * To store the same file in a subdirectory called "my-dir" of the original + * diagram's directory, you would use
    + * {@link #getRelativeURIForDiagram(diagram, "my-dir/my-file.xml")}. + *

    + * To store the same file in the same subdirectory and use the original + * diagram's extension as the extension for the new resource you would use
    + * {@link #getRelativeURIForDiagram(diagram, "my-dir/my-file." + + * ExportMarshaller.PLACEHOLDER_ORIGINAL_FILE_EXTENSION)}. + * + * @param diagram + * the diagram to find the URI for + * @param relativePath + * the relative path to the diagram provided + * @return the URI for the resource associated with the diagram + */ + protected URI getRelativeURIForDiagram(final Diagram diagram, final String relativePath) { + final URI originalURI = getResourceForDiagram(diagram).getURI(); + + String finalSegment = relativePath; + final URI parentURI = originalURI.trimSegments(1); + + // Parse any replacement variables in the filename + final Calendar now = Calendar.getInstance(); + + finalSegment = finalSegment.replaceAll(REGEX_DATE_TIME, SDF.format(now.getTime())); + finalSegment = finalSegment.replaceAll(REGEX_EXTENSION, originalURI.fileExtension()); + finalSegment = finalSegment.replaceAll(REGEX_FILENAME, originalURI.lastSegment()); + finalSegment = finalSegment.replaceAll(REGEX_FILENAME_WITHOUT_EXTENSION, originalURI.trimFileExtension().lastSegment()); + + return parentURI.appendSegment(finalSegment); + } + + /** + * Checks whether the provided resourceURI points to a resource that exists in + * the workspace. + * + * @param resourceURI + * @return + */ + protected boolean resourceExists(URI resourceURI) { + final IResource fileResource = ResourcesPlugin.getWorkspace().getRoot().findMember(resourceURI.toPlatformString(true)); + + return fileResource != null && fileResource.exists(); + } + + /** + * Gets a resource attached to the provided URI. + * + * @param resourceURI + * the URI to the resource + * @return a resource or null if there is none + */ + protected IResource getResource(URI resourceURI) { + IResource result = null; + if (resourceExists(resourceURI)) { + result = ResourcesPlugin.getWorkspace().getRoot().findMember(resourceURI.toPlatformString(true)); + } + return result; + } + + /** + * Saves a resource at the provided URI. Use this method to create or update + * resources created by {@link ExportMarshaller}s. This method adheres to the + * overwrite flag provided. + * + *

    + * The URI provided is not parsed for replacements and is + * considered final when invoking this method. When obtaining the URI for a + * resource, replacements will be parsed if + * {@link #getRelativeURIForDiagram(Diagram, String)} is used. + * + *

    + * To obtain a URI for the new resource you wish to create, invoke + * {@link #getRelativeURIForDiagram(Diagram, String)}. + * + * @see #getRelativeURIForDiagram(Diagram, String) + * + * @param uri + * the URI the resource should be saved to + * @param content + * a stream to the content for the resource + * @param overwriteFlag + * the flag for overwrite behavior + * @param monitor + * the progress monitor to use + */ + protected void saveResource(final URI uri, final InputStream content, final IProgressMonitor monitor) { + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + + final IFile file = workspace.getRoot().getFile(new Path(uri.toPlatformString(true))); + + // TODO + try { + if (file.exists()) { + // delete first + monitor.beginTask("update content", 10); + file.setContents(content, true, true, monitor); + } else { + monitor.beginTask("create", 10); + file.create(content, true, monitor); + } + file.refreshLocal(IResource.DEPTH_INFINITE, null); + monitor.worked(10); + } catch (CoreException e) { + // TODO + e.printStackTrace(); + // addProblemToDiagram(diagram, + // "A problem occured while exectuing the export marshaller: " + + // e.getMessage(), null); + } + } + + /** + * Extracts the process constructs from the provided list of {@link EObject}s + * in the diagram and places them in a Map. + * + * @param objects + * the list of {@link EObject}s in the diagram + * @param monitor + * the monitor to use to report progress + * + * @return a Map of process constructs, where the key is the type of the node + * and the value is a list of all constructs of that type found in the + * diagram. + */ + protected Map> extractProcessConstructs(final List objects, final IProgressMonitor monitor) { + + monitor.beginTask("Analyzing process constructs", objects.size() * EXTRACTION_WORK_UNIT); + + final Map> result = new HashMap>(); + + for (final EObject object : objects) { + + if (object instanceof FlowElement) { + String nodeType = null; + + // TODO: custom service tasks + // if (ExtensionUtil.isCustomServiceTask(object)) { + // + // final ServiceTask serviceTask = (ServiceTask) object; + // final CustomProperty customProperty = + // ExtensionUtil.getCustomProperty(serviceTask, + // ExtensionConstants.PROPERTY_ID_CUSTOM_SERVICE_TASK); + // + // if (customProperty != null) { + // final String nodeType = customProperty.getSimpleValue(); + // + // + // } + // } + + nodeType = object.getClass().getCanonicalName(); + + if (nodeType != null) { + if (!result.containsKey(nodeType)) { + result.put(nodeType, new ArrayList()); + } + result.get(nodeType).add(object); + } + } + + monitor.worked(EXTRACTION_WORK_UNIT); + } + + monitor.done(); + + return result; + } + /** + * Adds a marker to the {@link Diagram} provided that has an + * {@link IMarker#SEVERITY_INFO} severity (info). + */ + protected void addInfoToDiagram(Diagram diagram, String message, String nodeId) { + addMarkerToDiagram(diagram, message, nodeId, IMarker.SEVERITY_INFO); + } + + /** + * Adds a marker to the {@link Diagram} provided that has an + * {@link IMarker#SEVERITY_WARNING} severity (warning). + */ + protected void addWarningToDiagram(Diagram diagram, String message, String nodeId) { + addMarkerToDiagram(diagram, message, nodeId, IMarker.SEVERITY_WARNING); + } + + /** + * Adds a marker to the {@link Diagram} provided that has an + * {@link IMarker#SEVERITY_ERROR} severity (error). + */ + protected void addProblemToDiagram(Diagram diagram, String message, String nodeId) { + addMarkerToDiagram(diagram, message, nodeId, IMarker.SEVERITY_ERROR); + } + + private void addMarkerToDiagram(Diagram diagram, String message, String nodeId, final int severity) { + + final IWorkspace workspace = ResourcesPlugin.getWorkspace(); + + final IFile file = workspace.getRoot().getFile(new Path(getURIForDiagram(diagram).toPlatformString(true))); + + // Determine marker id + String markerId = ActivitiBPMNDiagramConstants.ACTIVITI_GENERAL_MARKER_ID; + if (this instanceof ExportMarshaller) { + markerId = ExportMarshaller.MARKER_ID; + } else if (this instanceof ProcessValidator) { + markerId = ProcessValidator.MARKER_ID; + } + + IMarker m; + try { + m = file.createMarker(markerId); + if (nodeId != null) { + m.setAttribute(ATTRIBUTE_NODE_ID, nodeId); + } + + m.setAttribute(ATTRIBUTE_WORKER_ID, this.getClass().getCanonicalName()); + + m.setAttribute(IMarker.MESSAGE, message); + m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); + m.setAttribute(IMarker.SEVERITY, severity); + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + protected void clearMarkers(IResource resource) { + + // Determine marker id + String markerId = ActivitiBPMNDiagramConstants.ACTIVITI_GENERAL_MARKER_ID; + if (this instanceof ExportMarshaller) { + markerId = ExportMarshaller.MARKER_ID; + } else if (this instanceof ProcessValidator) { + markerId = ProcessValidator.MARKER_ID; + } + + try { + final IMarker[] markers = resource.findMarkers(markerId, true, IResource.DEPTH_INFINITE); + for (final IMarker marker : markers) { + if (marker.getAttribute(ATTRIBUTE_WORKER_ID).equals(this.getClass().getCanonicalName())) { + marker.delete(); + } + } + } catch (CoreException e) { + e.printStackTrace(); + } + } + + protected IMarker[] getMarkers(IResource resource) { + IMarker[] markers = null; + try { + markers = resource.findMarkers(ActivitiBPMNDiagramConstants.ACTIVITI_GENERAL_MARKER_ID, true, IResource.DEPTH_INFINITE); + } catch (CoreException e) { + e.printStackTrace(); + } + return markers; + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/ExtensionConstants.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/ExtensionConstants.java new file mode 100644 index 0000000..59c2c58 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/ExtensionConstants.java @@ -0,0 +1,22 @@ +/** + * + */ +package org.activiti.designer.eclipse.extension; + +/** + * @author Tiese Barrell + * @since 0.5.1 + * @version 1 + * + */ +public final class ExtensionConstants { + + public static final String PROPERTY_ID_CUSTOM_SERVICE_TASK = "customServiceTaskId"; + + public static final String CUSTOM_PROPERTY_ID_SEPARATOR = "_"; + + private ExtensionConstants() { + + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/AbstractExportMarshaller.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/AbstractExportMarshaller.java new file mode 100644 index 0000000..53e93bd --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/AbstractExportMarshaller.java @@ -0,0 +1,96 @@ +/** + * + */ +package org.activiti.designer.eclipse.extension.export; + +import java.util.ArrayList; +import java.util.List; + +import org.activiti.designer.eclipse.extension.AbstractDiagramWorker; +import org.activiti.designer.eclipse.extension.validation.ProcessValidator; +import org.activiti.designer.eclipse.util.ExtensionPointUtil; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +/** + * Base class for {@link ExportMarshaller} implementations. + * + * @author Tiese Barrell + * @since 0.5.1 + * @version 3 + * + */ +public abstract class AbstractExportMarshaller extends AbstractDiagramWorker implements ExportMarshaller { + + private static final int WORK_INVOKE_VALIDATORS_VALIDATOR = 10; + + /** + * Invokes validators marked by the provided validatorIds. If no validator is + * registered by one of the validatorIds, that validator is skipped. Make sure + * to provide a fresh {@link SubProgressMonitor} as a monitor to properly + * incorporate progress reporting into that of the originating + * ExportMarshaller. + * + * @param validatorIds + * the list of ids of the validators to invoke + * @return true if *all* of the validators completed successfully or false + * otherwise + */ + protected boolean invokeValidators(final List validatorIds, final Diagram diagram, final IProgressMonitor monitor) { + + final int totalWork = WORK_INVOKE_VALIDATORS_VALIDATOR * validatorIds.size(); + + final IProgressMonitor activeMonitor = monitor == null ? new NullProgressMonitor() : monitor; + + activeMonitor.beginTask("Invoking validators", totalWork); + + boolean overallResult = true; + + try { + + if (validatorIds.size() > 0) { + + for (final String validatorId : validatorIds) { + + // get validator, else skip + final ProcessValidator processValidator = ExtensionPointUtil.getProcessValidator(validatorId); + + if (processValidator != null) { + + monitor.subTask("Invoking " + processValidator.getValidatorName()); + + if (!(processValidator.validateDiagram(diagram, new SubProgressMonitor(activeMonitor, WORK_INVOKE_VALIDATORS_VALIDATOR)))) { + // don't break if one result is false: keep validating to get + // all of the problems + overallResult = false; + } + } + } + } + + } finally { + monitor.done(); + } + + return overallResult; + } + /** + * Invokes validator marked by the provided validatorId. If no validator is + * registered by the validatorId, that validator is skipped. Make sure to + * provide a fresh {@link SubProgressMonitor} as a monitor to properly + * incorporate progress reporting into that of the originating + * ExportMarshaller. + * + * @param validatorId + * the id of the validator to invoke + * @return true if the validator completed successfully or false otherwise + */ + protected boolean invokeValidator(final String validatorId, final Diagram diagram, final IProgressMonitor monitor) { + final List validatorIds = new ArrayList(); + validatorIds.add(validatorId); + return invokeValidators(validatorIds, diagram, monitor); + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/ExportMarshaller.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/ExportMarshaller.java new file mode 100644 index 0000000..521d304 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/ExportMarshaller.java @@ -0,0 +1,78 @@ +/** + * + */ +package org.activiti.designer.eclipse.extension.export; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +/** + * @author Tiese Barrell + * @since 0.5.1 + * @version 1 + * + */ +public interface ExportMarshaller { + + /** + * Placeholder parsed when creating a filename that is substituted with the + * filename of the original file. + */ + public static final String PLACEHOLDER_ORIGINAL_FILENAME = "$originalFile"; + + /** + * Placeholder parsed when creating a filename that is substituted with the + * filename of the original file, stripped of the original file's extension. + */ + public static final String PLACEHOLDER_ORIGINAL_FILENAME_WITHOUT_EXTENSION = "$originalNameWithoutExtension"; + + /** + * Placeholder parsed when creating a filename that is substituted with the + * date and time at the moment of creation. + */ + public static final String PLACEHOLDER_DATE_TIME = "$dateTime"; + + /** + * Placeholder parsed when creating a filename that is substituted with the + * file extension of the original file. + */ + public static final String PLACEHOLDER_ORIGINAL_FILE_EXTENSION = "$originalExtension"; + + /** + * The identifier for problems created by the Activiti Designer for + * {@link ExportMarshaller}s. + */ + public static final String MARKER_ID = "org.activiti.designer.eclipse.activitiMarshallerMarker"; + + /** + * Gets a descriptive name for the marshaller. + * + * @return the marshaller's name + */ + String getMarshallerName(); + + /** + * Gets a descriptive name for the format the marshaller produces. + * + * @return the format's name + */ + String getFormatName(); + + /** + * Transforms content in the original diagram into this marshaller's own + * format. + * + *

    + * The {@link IProgressMonitor} provided should be used to indicate progress + * made in the marshaller and will be reported to the user. + * + * @param diagram + * the diagram to be marshalled + * @param monitor + * the monitor used to indicate progress of this marshaller + * + * @return the transformed diagram as a byte[] + */ + void marshallDiagram(Diagram diagram, IProgressMonitor monitor); + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/SequenceFlowSynchronizer.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/SequenceFlowSynchronizer.java new file mode 100644 index 0000000..a8eaf73 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/export/SequenceFlowSynchronizer.java @@ -0,0 +1,147 @@ +package org.activiti.designer.eclipse.extension.export; + +import java.util.List; + +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.FlowNode; +import org.eclipse.bpmn2.SequenceFlow; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.graphiti.mm.pictograms.Connection; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +// +import org.hamcrest.core.IsInstanceOf; +import org.eclipse.securebpmn2.SecurityFlow; +// + +/** + * Utility class to synchronize differences between the graphical representation and business model objects of a + * diagram. + * + * @author Tiese Barrell + * @since 0.5.1 + * @version 1 + * + */ +public class SequenceFlowSynchronizer { + + private SequenceFlowSynchronizer() { + } + + /** + * Synchronizes the provided list of {@link Connection}s by inspecting any differences between the graphical + * representation and business model objects. For any {@link Connection} where the ids of corresponding graphical + * and business objects don't match, the business objects are relinked in the model so they accurately reflect the + * graphical representation. + * + * @param connections + * the list of {@link Connection} objects to inspect. In most cases, this list would contain all + * connections of the diagram + * @param diagramEditor + * the {@link DiagramEditor} of which the diagram is currently being inspected + */ + public static void synchronize(final List connections, final DiagramEditor diagramEditor) { + + for (final Connection connection : connections) { + + final SyncObjects objects = new SyncObjects(connection, diagramEditor); + + if (objects.isOutOfSync()) { + objects.update(); + } + } + + } + + private static final class SyncObjects { + + private final DiagramEditor diagramEditor; + + private String graphicalStartId; + private String graphicalEndId; + private String businessStartId; + private String businessEndId; + + private FlowElement targetStartObject; + private FlowElement targetEndObject; + private SequenceFlow businessModelObjectToUpdate; + private Connection graphicalRepresentation; + + protected SyncObjects(final Connection connection, final DiagramEditor diagramEditor) { + this.graphicalRepresentation = connection; + this.diagramEditor = diagramEditor; + setup(); + } + + private void setup() { +// + if(this.graphicalRepresentation.getLink().getBusinessObjects().get(0) instanceof SecurityFlow)return; +// + + if(this.graphicalRepresentation == null) return; + + if(this.graphicalRepresentation.getStart() == null) return; + + if(this.graphicalRepresentation.getStart().getParent() == null) return; + + if(this.graphicalRepresentation.getStart().getParent().getLink().getBusinessObjects().size() == 0) return; + + final EObject startPE = this.graphicalRepresentation.getStart().getParent().getLink().getBusinessObjects().get(0); + targetStartObject = (FlowElement) startPE; + graphicalStartId = targetStartObject.getId(); + + if(this.graphicalRepresentation.getEnd() == null) return; + + if(this.graphicalRepresentation.getEnd().getParent() == null) return; + + if(this.graphicalRepresentation.getEnd().getParent().getLink().getBusinessObjects().size() == 0) return; + + final EObject endPE = this.graphicalRepresentation.getEnd().getParent().getLink().getBusinessObjects().get(0); + targetEndObject = (FlowElement) endPE; + graphicalEndId = targetEndObject.getId(); + + businessModelObjectToUpdate = (SequenceFlow) this.graphicalRepresentation.getLink().getBusinessObjects() + .get(0); + + if(businessModelObjectToUpdate.getSourceRef() != null) { + businessStartId = businessModelObjectToUpdate.getSourceRef().getId(); + } + if(businessModelObjectToUpdate.getTargetRef() != null) { + businessEndId = businessModelObjectToUpdate.getTargetRef().getId(); + } + } + + public boolean isOutOfSync() { + + if(graphicalStartId == null || graphicalEndId == null) return false; + + if (!graphicalStartId.equals(businessStartId) || !graphicalEndId.equals(businessEndId)) { + return true; + } + return false; + } + + public boolean update() { + if (isOutOfSync()) { + + System.out + .println(String + .format("Updating because the pictogram elements point from '%s' to '%s', but the business objects point from '%s' to '%s'. The difference must be corrected before saving the diagram", + graphicalStartId, graphicalEndId, businessStartId, businessEndId)); + + TransactionalEditingDomain editingDomain = this.diagramEditor.getEditingDomain(); + editingDomain.getCommandStack().execute(new RecordingCommand(editingDomain, "ConnectionUpdate") { + protected void doExecute() { + businessModelObjectToUpdate.setSourceRef((FlowNode) targetStartObject); + businessModelObjectToUpdate.setTargetRef((FlowNode) targetEndObject); + } + }); + + return true; + } + return false; + } + } + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/AbstractProcessValidator.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/AbstractProcessValidator.java new file mode 100644 index 0000000..320b810 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/AbstractProcessValidator.java @@ -0,0 +1,18 @@ +/** + * + */ +package org.activiti.designer.eclipse.extension.validation; + +import org.activiti.designer.eclipse.extension.AbstractDiagramWorker; + +/** + * Base class for {@link ProcessValidator} implementations. + * + * @author Tiese Barrell + * @since 0.6.1 + * @version 1 + * + */ +public abstract class AbstractProcessValidator extends AbstractDiagramWorker implements ProcessValidator { + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/ProcessValidator.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/ProcessValidator.java new file mode 100644 index 0000000..f974f6a --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/extension/validation/ProcessValidator.java @@ -0,0 +1,59 @@ +/** + * + */ +package org.activiti.designer.eclipse.extension.validation; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +/** + * @author Tiese Barrell + * @since 0.6.1 + * @version 1 + * + */ +public interface ProcessValidator { + + /** + * The identifier for problems created by the Activiti Designer for + * {@link ProcessValidator}s. + */ + public static final String MARKER_ID = "org.activiti.designer.eclipse.activitiValidatorMarker"; + + /** + * Gets an identifier for the validator. + * + * @return the validator's id + */ + String getValidatorId(); + + /** + * Gets a descriptive name for the validator. + * + * @return the validator's name + */ + String getValidatorName(); + + /** + * Gets a descriptive name for the format the validator validates. + * + * @return the format's name + */ + String getFormatName(); + + /** + * Validates the contents of the diagram. + * + *

    + * The {@link IProgressMonitor} provided should be used to indicate progress + * made in the validator and will be reported to the user. + * + * @param diagram + * the diagram to be validated + * @param monitor + * the monitor used to indicate progress of this validator + * @return true if validation was successful, false otherwise + */ + boolean validateDiagram(Diagram diagram, IProgressMonitor monitor); + +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnLabelProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnLabelProvider.java new file mode 100644 index 0000000..89a3b01 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnLabelProvider.java @@ -0,0 +1,129 @@ +package org.activiti.designer.eclipse.navigator; + +import org.activiti.designer.eclipse.common.ActivitiPlugin; +import org.activiti.designer.eclipse.navigator.nodes.BpmnElementsNode; +import org.activiti.designer.eclipse.navigator.nodes.base.IContainerNode; +import org.eclipse.bpmn2.BaseElement; +import org.eclipse.core.resources.IFile; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +public class BpmnLabelProvider extends LabelProvider { + private static final String IMPL = "Impl"; + + @Override + public String getText(Object element) { + String ret = ""; + if (element instanceof IContainerNode) { + IContainerNode icn = (IContainerNode) element; + ret = icn.getText(); + } + if (element instanceof IFile) { + IFile file = (IFile) element; + return file.getName(); + } + if (element instanceof Diagram) { + Diagram diagram = (Diagram) element; + if (diagram != null) { + ret = createTextForDiagram(diagram); + } + } + if (element instanceof BaseElement) { + String name = ((BaseElement) element).getId(); + if (name == null) { + name = "name not available"; + } + return name; + } + if (element instanceof EObject && ret.length() <= 0) { + EObject eObject = (EObject) element; + ret = ret + eObject.getClass().getSimpleName(); + if (ret.endsWith(IMPL)) { + ret = ret.substring(0, ret.length() - (IMPL.length())); + } + } + if (element instanceof GraphicsAlgorithm && ret.length() > 0) { + ret = ret + " - "; + ret = ret + super.getText(element); + } + return ret; + } + + private String createTextForDiagram(Diagram diagram) { + return "Diagram"; + } + + // private String createTextForDiagramFile(Diagram diagram) { + // return diagram.getName() + " (" + diagram.getDiagramTypeId() + ")"; + // } + + @Override + public Image getImage(Object element) { + if (element instanceof BpmnElementsNode) { + return getEClassesNodeImage(); + } + if (element instanceof IContainerNode) { + IContainerNode icn = (IContainerNode) element; + return icn.getImage(); + } + if (element instanceof IFile) { + String imageKey = ISharedImages.IMG_OBJ_ELEMENT; + return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); + } + if (element instanceof PictogramElement) { + String imageKey = ISharedImages.IMG_OBJ_ELEMENT; + return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); + } + if (element instanceof BaseElement) { + return getEClassImage(); + } + if (element instanceof EObject) { + return getEObjectImage(); + } + return super.getImage(element); + } + + private Image getEClassImage() { + ImageRegistry registry = ActivitiPlugin.getDefault().getImageRegistry(); + String key = "icons/full/obj16/EClass.gif"; //$NON-NLS-1$ + Image image = registry.get(key); + if (image == null) { + ImageDescriptor desc = ActivitiPlugin.imageDescriptorFromPlugin("org.eclipse.emf.ecore.edit", key); + registry.put(key, desc); + image = registry.get(key); + } + return image; + } + + private Image getEObjectImage() { + ImageRegistry registry = ActivitiPlugin.getDefault().getImageRegistry(); + String key = "icons/full/obj16/EObject.gif"; //$NON-NLS-1$ + Image image = registry.get(key); + if (image == null) { + ImageDescriptor desc = ActivitiPlugin.imageDescriptorFromPlugin("org.eclipse.emf.ecore.edit", key); + registry.put(key, desc); + image = registry.get(key); + } + return image; + } + + private Image getEClassesNodeImage() { + ImageRegistry registry = ActivitiPlugin.getDefault().getImageRegistry(); + String key = "icons/full/obj16/EPackage.gif"; //$NON-NLS-1$ + Image image = registry.get(key); + if (image == null) { + ImageDescriptor desc = ActivitiPlugin.imageDescriptorFromPlugin("org.eclipse.emf.ecore.edit", key); + registry.put(key, desc); + image = registry.get(key); + } + return image; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnTreeContentProvider.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnTreeContentProvider.java new file mode 100644 index 0000000..8c6f0e0 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/BpmnTreeContentProvider.java @@ -0,0 +1,155 @@ +package org.activiti.designer.eclipse.navigator; + +import java.util.HashMap; +import java.util.Map; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.common.ActivitiProjectNature; +import org.activiti.designer.eclipse.navigator.nodes.BpmnElementsNode; +import org.activiti.designer.eclipse.navigator.nodes.base.IContainerNode; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.ui.progress.UIJob; + +public class BpmnTreeContentProvider implements ITreeContentProvider, IResourceChangeListener { + + private Viewer viewer; + private Map projectToBpmn2ElementsNode = new HashMap(); + + public BpmnTreeContentProvider() { + super(); + ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); + + } + + @Override + public Object[] getChildren(Object parentElement) { + if (parentElement instanceof IContainerNode) { + IContainerNode icn = (IContainerNode) parentElement; + return icn.getChildren(); + } + if (parentElement instanceof IProject) { + IProject project = (IProject) parentElement; + try { + if (project.isAccessible() && project.hasNature(ActivitiProjectNature.NATURE_ID)) { + BpmnElementsNode bpmn2Node = projectToBpmn2ElementsNode.get(project); + if (bpmn2Node == null) { + bpmn2Node = new BpmnElementsNode(project, project, viewer); + projectToBpmn2ElementsNode.put(project, bpmn2Node); + } + return new Object[] { bpmn2Node }; + } + } catch (CoreException e) { + // Ignore. E.g., project was deleted. + } + } + if (parentElement instanceof EObject) { + EObject eObject = (EObject) parentElement; + return eObject.eContents().toArray(); + } + return new Object[0]; + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public boolean hasChildren(Object element) { + if (element instanceof IContainerNode) { + IContainerNode icn = (IContainerNode) element; + return icn.hasChildren(); + } + if (element instanceof EObject) { + return !((EObject) element).eContents().isEmpty(); + } + return true; + } + + @Override + public Object[] getElements(Object inputElement) { + return null; + } + + @Override + public void dispose() { + // do nothing + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + this.viewer = viewer; + } + + @Override + public void resourceChanged(IResourceChangeEvent event) { + IResourceDelta delta = event.getDelta(); + try { + delta.accept(new IResourceDeltaVisitor() { + + @Override + public boolean visit(IResourceDelta delta) throws CoreException { + IResource resource = delta.getResource(); + if (resource == null) + return false; + switch (resource.getType()) { + case IResource.ROOT: + return true; + case IResource.PROJECT: + IProject p = (IProject) resource; + try { + boolean hasNature = p.hasNature(ActivitiProjectNature.NATURE_ID); + return hasNature; + } catch (CoreException e) { + // Do nothing, e.g. project deleted. + } + return false; + case IResource.FOLDER: + return true; + case IResource.FILE: + final IFile file = (IFile) resource; + if (file.getName().endsWith(ActivitiBPMNDiagramConstants.DIAGRAM_EXTENSION) || file.getName().equals("Predefined.data")) { //$NON-NLS-1$ + UIJob job = new UIJob("Update Viewer") { //$NON-NLS-1$ + @Override + public IStatus runInUIThread(IProgressMonitor monitor) { + if (viewer != null && !viewer.getControl().isDisposed()) { + BpmnElementsNode bpmnNode = projectToBpmn2ElementsNode.get(file.getProject()); + if (viewer instanceof StructuredViewer && bpmnNode != null) { + ((StructuredViewer) viewer).refresh(bpmnNode, true); + } else { + viewer.refresh(); + } + } + return Status.OK_STATUS; + } + }; + job.setSystem(true); + job.schedule(); + } + return false; + } + return false; + + } + + }); + } catch (CoreException e1) { + return; + } + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/BpmnElementsNode.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/BpmnElementsNode.java new file mode 100644 index 0000000..db535d3 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/BpmnElementsNode.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.navigator.nodes; + +import org.activiti.designer.eclipse.navigator.nodes.base.AbstractInstancesOfTypeContainerNode; +import org.activiti.designer.eclipse.util.Util; +import org.eclipse.core.resources.IProject; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.graphics.Image; + +/** + * EClassesNode should display the EClasses of the currently activated diagram + * editor. + * + */ +public class BpmnElementsNode extends AbstractInstancesOfTypeContainerNode { + private static final String NAME = "Bpmn2Elements"; + + private ResourceSetImpl rSet; + + public BpmnElementsNode(Object parent, IProject project, Viewer viewer) { + super(parent, project); + rSet = new ResourceSetImpl(); + + } + + @Override + protected String getContainerName() { + return NAME; + } + + @Override + public Object[] getChildren() { + return Util.getAllBpmnElements(getProject(), rSet); + } + + @Override + public Image getImage() { + return super.getImage(); // ImagePool.getImage(ImagePool.ROOT_FOLDER_FOR_IMG); + } + + /** + * @return the rSet + */ + public ResourceSet getResourceSet() { + return rSet; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/DiagramsNode.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/DiagramsNode.java new file mode 100644 index 0000000..9433116 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/DiagramsNode.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.navigator.nodes; + +import java.util.ArrayList; +import java.util.List; + +import org.activiti.designer.eclipse.common.ActivitiBPMNDiagramConstants; +import org.activiti.designer.eclipse.navigator.nodes.base.AbstractInstancesOfTypeContainerNode; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.graphiti.mm.pictograms.Diagram; + +public class DiagramsNode extends AbstractInstancesOfTypeContainerNode { + + private static final String NAME = "Diagrams"; + + public DiagramsNode(Object parent, IProject project) { + super(parent, project); + } + + @Override + protected String getContainerName() { + return NAME; + } + + @Override + public Object[] getChildren() { + IProject project = getProject(); + if (project != null) { + ResourceSet rSet = new ResourceSetImpl(); + return getAllDiagramFiles(project, rSet).toArray(); + } + return null; + } + + private List getFiles(IContainer folder) { + List ret = new ArrayList(); + try { + IResource[] members = folder.members(); + for (IResource resource : members) { + if (resource instanceof IContainer) { + ret.addAll(getFiles((IContainer) resource)); + } else if (resource instanceof IFile) { + IFile file = (IFile) resource; + if (file.getName().endsWith(ActivitiBPMNDiagramConstants.DIAGRAM_EXTENSION)) { //$NON-NLS-1$ + ret.add(file); + } + } + } + } catch (CoreException e) { + e.printStackTrace(); + } + return ret; + } + + private List getAllDiagramFiles(IProject project, ResourceSet rSet) { + List files = getFiles(project); + + List ret = new ArrayList(); + for (IFile file : files) { + // The following call extracts the diagram from the + // given file. For the Tutorial, diagrams always reside + // in a file of their own and are the first root object. + // This may of course be different in a concrete tool + // implementation, so tool builders should use their own + // way of retrieval here + Diagram diagram = org.eclipse.graphiti.ui.internal.services.GraphitiUiInternal.getEmfService() + .getDiagramFromFile(file, rSet); + if (diagram != null) { + ret.add(file); + } + } + return ret; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractContainerNode.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractContainerNode.java new file mode 100644 index 0000000..d8a1f0d --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractContainerNode.java @@ -0,0 +1,39 @@ +package org.activiti.designer.eclipse.navigator.nodes.base; + +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +/** + * The Class AbstractContainerNode. + */ +public abstract class AbstractContainerNode implements IContainerNode { + + protected AbstractContainerNode() { + super(); + } + + @Override + public String getText() { + String ret = getContainerName(); + return ret; + } + + /** + * Gets the container name. + * + * @return the container name + */ + abstract protected String getContainerName(); + + @Override + public boolean hasChildren() { + return true; + } + + @Override + public Image getImage() { + String imageKey = ISharedImages.IMG_OBJ_ELEMENT; + return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractInstancesOfTypeContainerNode.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractInstancesOfTypeContainerNode.java new file mode 100644 index 0000000..4b0d798 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/AbstractInstancesOfTypeContainerNode.java @@ -0,0 +1,37 @@ +package org.activiti.designer.eclipse.navigator.nodes.base; + +import org.eclipse.core.resources.IProject; + +/** + * The Class AbstractInstancesOfTypeContainerNode. + */ +public abstract class AbstractInstancesOfTypeContainerNode extends AbstractContainerNode { + + private Object parent; + IProject project; + + /** + * The Constructor. + * + * @param parent + * the parent + */ + public AbstractInstancesOfTypeContainerNode(Object parent, IProject project) { + super(); + this.parent = parent; + this.project = project; + } + + public Object getParent() { + return parent; + } + + @Override + public boolean hasChildren() { + return super.hasChildren(); // getChildren().length > 0; + } + + public IProject getProject() { + return project; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/IContainerNode.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/IContainerNode.java new file mode 100644 index 0000000..1de5d21 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/navigator/nodes/base/IContainerNode.java @@ -0,0 +1,39 @@ +package org.activiti.designer.eclipse.navigator.nodes.base; + +import org.eclipse.swt.graphics.Image; + +/** + * The Interface IContainerNode. + */ +public interface IContainerNode { + + /** + * Gets the parent. + * + * @return the parent + */ + Object getParent(); + + /** + * Gets the children. + * + * @return the children + */ + Object[] getChildren(); + + /** + * Checks for children. + * + * @return true, if successful + */ + boolean hasChildren(); + + /** + * Gets the text. + * + * @return the text + */ + String getText(); + + Image getImage(); +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/ContentOutlinePageAdapterFactory.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/ContentOutlinePageAdapterFactory.java new file mode 100644 index 0000000..b989ef2 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/ContentOutlinePageAdapterFactory.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline; + +import org.eclipse.core.runtime.IAdapterFactory; +import org.eclipse.gef.editparts.ZoomManager; +import org.eclipse.gef.ui.parts.TreeViewer; +import org.eclipse.graphiti.internal.pref.GFPreferences; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +import org.eclipse.ui.views.contentoutline.IContentOutlinePage; + +// The generic outline uses internal functionality of Graphiti. For concrete +// tool implementations this should not be necessary +public class ContentOutlinePageAdapterFactory implements IAdapterFactory { + + private static final Class[] ADAPTERS = new Class[] { IContentOutlinePage.class }; + + @Override + public Object getAdapter(Object adaptableObject, @SuppressWarnings("rawtypes") Class adapterType) { + if (GFPreferences.getInstance().isGenericOutlineActive()) { + if (IContentOutlinePage.class.equals(adapterType)) { + if (adaptableObject instanceof DiagramEditor) { + DiagramEditor diagramEditor = (DiagramEditor) adaptableObject; + if (diagramEditor.getConfigurationProvider() != null) { // diagram editor initialized? + GraphicsEditorOutlinePage outlinePage = new GraphicsEditorOutlinePage(new TreeViewer(), diagramEditor + .getGraphicalViewer(), diagramEditor.getActionRegistryInternal(), diagramEditor.getEditDomain(), + diagramEditor.getCommonKeyHandler(), diagramEditor.getAdapter(ZoomManager.class), diagramEditor + .getSelectionSynchronizerInternal(), diagramEditor); + return outlinePage; + } + } + } + } + return null; + } + + @Override + @SuppressWarnings("rawtypes") + public Class[] getAdapterList() { + return ADAPTERS; + } +} diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/GraphicsEditorOutlinePage.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/GraphicsEditorOutlinePage.java new file mode 100644 index 0000000..4efdd44 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/GraphicsEditorOutlinePage.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline; + +import org.activiti.designer.eclipse.common.ISampleImageConstants; +import org.activiti.designer.eclipse.outline.tree.PictogramsTreeEditPartFactory; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.draw2d.LightweightSystem; +import org.eclipse.draw2d.MarginBorder; +import org.eclipse.draw2d.Viewport; +import org.eclipse.gef.ContextMenuProvider; +import org.eclipse.gef.EditDomain; +import org.eclipse.gef.EditPart; +import org.eclipse.gef.EditPartFactory; +import org.eclipse.gef.EditPartViewer; +import org.eclipse.gef.GraphicalViewer; +import org.eclipse.gef.KeyHandler; +import org.eclipse.gef.LayerConstants; +import org.eclipse.gef.editparts.ScalableFreeformRootEditPart; +import org.eclipse.gef.editparts.ZoomManager; +import org.eclipse.gef.ui.actions.ActionRegistry; +import org.eclipse.gef.ui.parts.ContentOutlinePage; +import org.eclipse.gef.ui.parts.SelectionSynchronizer; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +import org.eclipse.graphiti.ui.editor.DiagramEditorInput; +import org.eclipse.graphiti.ui.internal.fixed.FixedScrollableThumbnail; +import org.eclipse.graphiti.ui.services.GraphitiUi; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.part.IPageSite; +import org.eclipse.ui.part.PageBook; + +/** + * An outline page for the graphical modeling editor. It displays the contents + * of the editor either as a hierarchical Outline or as a graphical Thumbnail. + * There are buttons to switch between those displays. Subclasses should + * overwrite this outline page (and dependent classes), to change the + * default-behaviour. + */ +// The generic outline uses internal functionality of Graphiti. For concrete +// tool implementations this should not be necessary +public class GraphicsEditorOutlinePage extends ContentOutlinePage implements IAdaptable, IPropertyListener { + + // The IDs to identify the outline and the thunbnail + private static final int ID_OUTLINE = 0; + + private static final int ID_THUMBNAIL = 1; + + // Common instances of different Editors/Views, to synchronize their + // behaviour + private GraphicalViewer _graphicalViewer; + + private ActionRegistry _actionRegistry; + + private EditDomain _editDomain; + + private KeyHandler _keyHandler; + + private Object _zoomManagerAdapter; + + private SelectionSynchronizer _selectionSynchronizer; + + private DiagramEditor _diagramEditor; + + // The thumbnail to display + private FixedScrollableThumbnail _thumbnail; + + // Actions (buttons) to switch between outline and overview + private IAction _showOutlineAction; + + private IAction _showOverviewAction; + + // The pagebook, which displays either the outline or the overview + private PageBook _pageBook; + + // The outline-control and the thumbnail-control of the pagebook + private Control _outline; + + private Canvas _overview; + + /** + * Creates a new GraphicsEditorOutlinePage. It is important, that this + * outline page uses the same handlers (ActionRegistry, KeyHandler, + * ZoomManagerAdapter, ...) as the main editor, so that the behaviour is + * synchronized between them. + * + * @param viewer + * The viewer (typically a tree-viewer) for the hierarchical + * outline. + * @param graphicalViewer + * The GraphicalViewer for the Thumbnail. + * @param actionRegistry + * The ActionRegistry to find/register Actions. + * @param editDomain + * The EditDomain to use for Commands. + * @param keyHandler + * The KeyHandler to use. + * @param zoomManagerAdapter + * The ZoomManagerAdapter to use for the Thumbnail-Display. + * @param selectionSynchronizer + * The selection-synchronizer for the main-editor and this + * outline page. + * @param configurationProviderHolder + * the configuration provider holder + */ + public GraphicsEditorOutlinePage(EditPartViewer viewer, GraphicalViewer graphicalViewer, ActionRegistry actionRegistry, + EditDomain editDomain, KeyHandler keyHandler, Object zoomManagerAdapter, SelectionSynchronizer selectionSynchronizer, + DiagramEditor diagramEditor) { + super(viewer); + _graphicalViewer = graphicalViewer; + _actionRegistry = actionRegistry; + _editDomain = editDomain; + _keyHandler = keyHandler; + _zoomManagerAdapter = zoomManagerAdapter; + _selectionSynchronizer = selectionSynchronizer; + _diagramEditor = diagramEditor; + } + + // ========================= standard behaviour =========================== + + /** + * Is called to indicate, that the contents have changed. Causes a complete + * update of the contents of the outline page. + */ + public void initContents() { + EditPartFactory treeEditPartFactory = new PictogramsTreeEditPartFactory(); + getViewer().setEditPartFactory(treeEditPartFactory); + Diagram diagram = ((DiagramEditorInput) _diagramEditor.getEditorInput()).getDiagram(); + getViewer().setContents(diagram); + } + + /** + * Is used to register several global action handlers (UNDO, REDO, COPY, + * PASTE, ...) on initialization of this outline page. This activates for + * example the undo-action in the central Eclipse-Menu. + * + * @param pageSite + * the page site + * + * @see org.eclipse.ui.part.Page#init(IPageSite) + */ + @Override + public void init(IPageSite pageSite) { + super.init(pageSite); + IActionBars actionBars = pageSite.getActionBars(); + registerGlobalActionHandler(actionBars, ActionFactory.UNDO.getId()); + registerGlobalActionHandler(actionBars, ActionFactory.REDO.getId()); + registerGlobalActionHandler(actionBars, ActionFactory.COPY.getId()); + registerGlobalActionHandler(actionBars, ActionFactory.PASTE.getId()); + registerGlobalActionHandler(actionBars, ActionFactory.PRINT.getId()); + registerGlobalActionHandler(actionBars, ActionFactory.SAVE_AS.getId()); + actionBars.updateActionBars(); + } + + /** + * Creates the Control of this outline page. By default this is a PageBook, + * which can toggle between a hierarchical Outline and a graphical + * Thumbnail. + * + * @param parent + * the parent + * + * @see org.eclipse.gef.ui.parts.ContentOutlinePage#createControl(Composite) + */ + @Override + public void createControl(Composite parent) { + _pageBook = new PageBook(parent, SWT.NONE); + _outline = getViewer().createControl(_pageBook); + _overview = new Canvas(_pageBook, SWT.NONE); + _pageBook.showPage(_outline); + createOutlineViewer(); + + // register listeners + _selectionSynchronizer.addViewer(getViewer()); + _diagramEditor.addPropertyListener(this); + + initContents(); + } + + /** + * Deregisters all 'listeners' of the main-editor. + */ + @Override + public void dispose() { + // deregister listeners + _selectionSynchronizer.removeViewer(getViewer()); + _diagramEditor.removePropertyListener(this); + + if (_thumbnail != null) + _thumbnail.deactivate(); + + super.dispose(); + } + + /** + * Returns the Control of this outline page, which was created in + * createControl(). + * + * @return the control + * + * @see org.eclipse.gef.ui.parts.ContentOutlinePage#getControl() + */ + @Override + public Control getControl() { + return _pageBook; + } + + /** + * This implementation returns the ZoomManager for the ZoomManager.class. + * + * @param type + * the type + * + * @return the adapter + * + * @see org.eclipse.gef.ui.parts.GraphicalEditor#getAdapter(Class) + */ + @Override + public Object getAdapter(@SuppressWarnings("rawtypes") Class type) { + if (type == ZoomManager.class) + return _zoomManagerAdapter; + return null; + } + + /** + * Refreshes the outline on any change of the diagram editor. Most + * importantly, there is a property change event editor-dirty. + */ + @Override + public void propertyChanged(Object source, int propId) { + refresh(); + } + + /** + * Toggles the page to display between hierarchical Outline and graphical + * Thumbnail. + * + * @param id + * The ID of the page to display. It must be either ID_OUTLINE or + * ID_THUMBNAIL. + */ + protected void showPage(int id) { + if (id == ID_OUTLINE) { + _showOutlineAction.setChecked(true); + _showOverviewAction.setChecked(false); + _pageBook.showPage(_outline); + } else if (id == ID_THUMBNAIL) { + if (_thumbnail == null) + createThumbnailViewer(); + _showOutlineAction.setChecked(false); + _showOverviewAction.setChecked(true); + _pageBook.showPage(_overview); + } + } + + /** + * Creates the hierarchical Outline viewer. + */ + protected void createOutlineViewer() { + // set the standard handlers + getViewer().setEditDomain(_editDomain); + getViewer().setKeyHandler(_keyHandler); + + // add a context-menu + ContextMenuProvider contextMenuProvider = createContextMenuProvider(); + if (contextMenuProvider != null) + getViewer().setContextMenu(contextMenuProvider); + + // add buttons outline/overview to toolbar + IToolBarManager tbm = getSite().getActionBars().getToolBarManager(); + _showOutlineAction = new Action() { + + @Override + public void run() { + showPage(ID_OUTLINE); + } + }; + _showOutlineAction.setImageDescriptor(GraphitiUi.getImageService().getImageDescriptorForId(ISampleImageConstants.IMG_OUTLINE_TREE)); + tbm.add(_showOutlineAction); + _showOverviewAction = new Action() { + + @Override + public void run() { + showPage(ID_THUMBNAIL); + } + }; + _showOverviewAction.setImageDescriptor(GraphitiUi.getImageService().getImageDescriptorForId( + ISampleImageConstants.IMG_OUTLINE_THUMBNAIL)); + tbm.add(_showOverviewAction); + + // by default show the outline-page + showPage(ID_OUTLINE); + } + + /** + * Returns a new ContextMenuProvider. Can be null, if no context-menu shall + * be displayed. + * + * @return A new ContextMenuProvider. + */ + protected ContextMenuProvider createContextMenuProvider() { + return null; + } + + /** + * Creates the graphical Thumbnail viewer. + */ + protected void createThumbnailViewer() { + LightweightSystem lws = new LightweightSystem(_overview); + ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart) _graphicalViewer.getRootEditPart(); + _thumbnail = new FixedScrollableThumbnail((Viewport) rootEditPart.getFigure()); + _thumbnail.setBorder(new MarginBorder(3)); + _thumbnail.setSource(rootEditPart.getLayer(LayerConstants.PRINTABLE_LAYERS)); + lws.setContents(_thumbnail); + } + + // ========================= private helper methods ======================= + + private void registerGlobalActionHandler(IActionBars actionBars, String id) { + IAction action = _actionRegistry.getAction(id); + if (action != null) + actionBars.setGlobalActionHandler(id, action); + } + + /** + * Refresh. + */ + void refresh() { + final EditPartViewer viewer = getViewer(); + final EditPart contents = viewer.getContents(); + if (contents != null) { + contents.refresh(); + } + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/AbstractGraphicsTreeEditPart.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/AbstractGraphicsTreeEditPart.java new file mode 100644 index 0000000..9b45cf9 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/AbstractGraphicsTreeEditPart.java @@ -0,0 +1,274 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +/* + * Created on 28.06.2005 + */ +package org.activiti.designer.eclipse.outline.tree; + +import java.lang.reflect.Array; +import java.text.DateFormat; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.activiti.designer.eclipse.util.uiprovider.TwoObjectsContainer; +import org.eclipse.draw2d.geometry.Point; +import org.eclipse.draw2d.geometry.Rectangle; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.editparts.AbstractTreeEditPart; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; + +/** + * + */ +public class AbstractGraphicsTreeEditPart extends AbstractTreeEditPart { + + private Map _imageRegistry = new HashMap(); // ImageDescriptor + + /** + * The Constant TEXT_TYPE_DEFAULT. + */ + public static final String TEXT_TYPE_DEFAULT = null; + + /** + * The Constant ARRAY_TEXT_START. + */ + public static final String ARRAY_TEXT_START = "["; //$NON-NLS-1$ + + /** + * The Constant ARRAY_TEXT_END. + */ + public static final String ARRAY_TEXT_END = "]"; //$NON-NLS-1$ + + /** + * The Constant ARRAY_TEXT_SEPARATOR. + */ + public static final String ARRAY_TEXT_SEPARATOR = "; "; //$NON-NLS-1$ + + /** + * The Constant FORMAT_JAVA_SQL_DATE. + */ + public static final DateFormat FORMAT_JAVA_SQL_DATE = DateFormat.getDateInstance(DateFormat.SHORT); + + /** + * The Constant FORMAT_JAVA_SQL_TIME. + */ + public static final DateFormat FORMAT_JAVA_SQL_TIME = DateFormat.getTimeInstance(DateFormat.SHORT); + + /** + * The Constant FORMAT_JAVA_UTIL_DATE. + */ + public static final DateFormat FORMAT_JAVA_UTIL_DATE = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + + /** + * The Constant TUPLE_TEXT_END. + */ + public static final String TUPLE_TEXT_END = ")"; //$NON-NLS-1$ + + /** + * The Constant TUPLE_TEXT_SEPARATOR. + */ + public static final String TUPLE_TEXT_SEPARATOR = ", "; //$NON-NLS-1$ + + /** + * The Constant TUPLE_TEXT_START. + */ + public static final String TUPLE_TEXT_START = "("; //$NON-NLS-1$ + + + /** + * @param model + */ + public AbstractGraphicsTreeEditPart(Object model) { + super(model); + } + + /** + * This method is called from refreshVisuals(), to display the image of the + * TreeItem. + *

    + * By default this method displays the image of the FIRST attribute of the + * ModelObject as the TreeItem. + * + * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals() + */ + @Override + protected Image getImage() { + Image result = getImage(getModel(), null); + return result; + } + + /** + * This method is called by refreshVisuals(), to display the text of the + * TreeItem. + *

    + * By default this method displays the FIRST attribute of the model Object + * as the TreeItem. + * + * @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals() + */ + @Override + protected String getText() { + String text = getText(getModel(), TEXT_TYPE_DEFAULT); + return (text == null) ? "" : text; //$NON-NLS-1$ + } + + /** + * Adds the all elements if not null. + * + * @param resultList + * the result list + * @param collection + * the collection + */ + protected void addAllElementsIfNotNull(List resultList, Collection collection) { + for (Object element : collection) { + if (element != null) { + resultList.add(element); + } + } + } + + private String getText(Object element, Object textType) { + // get inner objects from 'own' wrappers + // if (element instanceof PropertyForAttribute) { + // PropertyForAttribute casted = (PropertyForAttribute) element; + // element = casted.getValue(); + // } + // if (element instanceof PropertyTypeForAttribute) { + // PropertyTypeForAttribute casted = (PropertyTypeForAttribute) element; + // element = casted.getAttribute(); + // } + + // // special handlings + // if (element instanceof Attribute) { + // Attribute casted = (Attribute) element; + // if (Util.equalsWithNull(textType, TEXT_TYPE_DEFAULT) || + // Util.equalsWithNull(textType, TEXT_TYPE_NAME)) + // return casted.getName(); + // if (Util.equalsWithNull(textType, TEXT_TYPE_TOOLTIP)) + // return "The attribute" + " " + casted.getName(); + // if (Util.equalsWithNull(textType, TEXT_TYPE_PROPERTYSHEET_CATEGORY)) + // { + // if + // (casted.refOutermostComposite().refGetValue("name").equals("pictograms")) + // { + // return "Graphics Extension"; + // } else { + // return "Business Model"; + // } + // } + // } + + if (element instanceof EObject) { + EObject casted = (EObject) element; + if (casted != null && casted.eResource() != null) { + final EObject eObject = casted.eClass(); + if (eObject instanceof EClass && eObject.eResource() != null) { + EClass eClass = (EClass) eObject; + String className = eClass.getName(); + return className + " (" + casted.toString() + ")"; + } + } + } + + if (element == null) + return ""; //$NON-NLS-1$ + + // Collection: convert to array and call recursively + if (element instanceof Collection) { + Collection collection = (Collection) element; + return getText(collection.toArray(), textType); + } + + // Array: build comma-separated List with recursive calls + if (element.getClass().isArray()) { + StringBuffer result = new StringBuffer(); + result.append(ARRAY_TEXT_START); + boolean afterFirstElement = false; + for (int i = 0; i < Array.getLength(element); i++) { + if (afterFirstElement) + result.append(ARRAY_TEXT_SEPARATOR); + Object next = Array.get(element, i); // this automatically + // converts primitive + // types to Object types + result.append(getText(next, textType)); + afterFirstElement = true; + } + result.append(ARRAY_TEXT_END); + return result.toString(); + } + + // Date/Time: use DateFormatter + if (element instanceof java.sql.Date) + return FORMAT_JAVA_SQL_DATE.format((java.sql.Date) element); + if (element instanceof java.sql.Time) + return FORMAT_JAVA_SQL_TIME.format((java.sql.Time) element); + if (element instanceof java.util.Date) // java.uti.Date must be the + // last, because the java.sql.* + // extend this class + return FORMAT_JAVA_UTIL_DATE.format((java.util.Date) element); + + // Rectangle/Point + if (element instanceof Rectangle) { + Rectangle casted = (Rectangle) element; + StringBuffer result = new StringBuffer(); + result.append(TUPLE_TEXT_START); + result.append(casted.x).append(TUPLE_TEXT_SEPARATOR).append(casted.y).append(TUPLE_TEXT_SEPARATOR).append(casted.width) + .append(TUPLE_TEXT_SEPARATOR).append(casted.height); + result.append(TUPLE_TEXT_END); + return result.toString(); + } + if (element instanceof Point) { + Point casted = (Point) element; + StringBuffer result = new StringBuffer(); + result.append(TUPLE_TEXT_START); + result.append(casted.x).append(TUPLE_TEXT_SEPARATOR).append(casted.y); + result.append(TUPLE_TEXT_END); + return result.toString(); + } + + // default + return element.toString(); + } + + private Image getImage(Object element, Object imageType) { + if (element != null) { + ImageDescriptor descriptor = getImageDescriptor(element, imageType); + TwoObjectsContainer container = new TwoObjectsContainer(descriptor, imageType); + if (descriptor != null) { + Image image = getImageRegistry().get(container); + if (image == null) { + image = descriptor.createImage(); + getImageRegistry().put(container, image); + } + return image; + } + } + return null; + } + + private ImageDescriptor getImageDescriptor(Object element, Object imageType) { + return null; + } + + private Map getImageRegistry() { + return _imageRegistry; + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ColorTreeEditPart.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ColorTreeEditPart.java new file mode 100644 index 0000000..25a0fe8 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ColorTreeEditPart.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline.tree; + +import org.eclipse.graphiti.mm.algorithms.styles.Color; + +/** + * A default-implementation for a TreeEditPart, which wraps a Shape. It can be + * overwritten to provide different behaviour. + */ +public class ColorTreeEditPart extends AbstractGraphicsTreeEditPart { + + /** + * Creates a new PictogramElementTreeEditPart for the given model Object. + * + * @param configurationProvider + * The IConfigurationProvider which defines the model + * @param shape + * The Shape of this EditPart. + */ + public ColorTreeEditPart(Color color) { + super(color); + } + + public Color getColor() { + return (Color) getModel(); + } + + // ======================= overwriteable behaviour ======================== + + /** + * Creates the EditPolicies of this EditPart. Subclasses often overwrite + * this method to change the behaviour of the editpart. + */ + @Override + protected void createEditPolicies() { + } + + @Override + protected String getText() { + return super.getText() + " - (" + getColor().getRed() + ", " + getColor().getGreen() + ", " + getColor().getBlue() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ConnectionDecoratorTreeEditPart.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ConnectionDecoratorTreeEditPart.java new file mode 100644 index 0000000..b844962 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/ConnectionDecoratorTreeEditPart.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline.tree; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator; + +/** + * A default-implementation for a TreeEditPart, which wraps a Shape. It can be + * overwritten to provide different behaviour. + */ +public class ConnectionDecoratorTreeEditPart extends AbstractGraphicsTreeEditPart { + + /** + * Creates a new PictogramElementTreeEditPart for the given model Object. + * + * @param configurationProvider + * The IConfigurationProvider which defines the model + * @param shape + * The Shape of this EditPart. + */ + public ConnectionDecoratorTreeEditPart(ConnectionDecorator connectionDecorator) { + super(connectionDecorator); + } + + /** + * Returns the Shape of this EditPart + * + * @return The Shape of this EditPart + */ + public ConnectionDecorator getConnectionDecorator() { + return (ConnectionDecorator) getModel(); + } + + // ======================= overwriteable behaviour ======================== + + /** + * Creates the EditPolicies of this EditPart. Subclasses often overwrite + * this method to change the behaviour of the editpart. + */ + @Override + protected void createEditPolicies() { + } + + /** + * Returns the children of this EditPart. + * + * @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren() + */ + @Override + protected List getModelChildren() { + List retList = new ArrayList(); + if (getConnectionDecorator() != null) { + ConnectionDecorator connectionDecorator = getConnectionDecorator(); + GraphicsAlgorithm ga = connectionDecorator.getGraphicsAlgorithm(); + if (ga != null) { + retList.add(ga); + } + } + + return retList; + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/GraphicsAlgorithmTreeEditPart.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/GraphicsAlgorithmTreeEditPart.java new file mode 100644 index 0000000..735a971 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/GraphicsAlgorithmTreeEditPart.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline.tree; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.algorithms.Polyline; + +/** + * A default-implementation for a TreeEditPart, which wraps a Shape. It can be + * overwritten to provide different behaviour. + */ +public class GraphicsAlgorithmTreeEditPart extends AbstractGraphicsTreeEditPart { + + /** + * Creates a new PictogramElementTreeEditPart for the given model Object. + * + * @param configurationProvider + * The IConfigurationProvider which defines the model + * @param shape + * The Shape of this EditPart. + */ + public GraphicsAlgorithmTreeEditPart(GraphicsAlgorithm graphicsAlgorithm) { + super(graphicsAlgorithm); + } + + /** + * Returns the Shape of this EditPart + * + * @return The Shape of this EditPart + */ + public GraphicsAlgorithm getGraphicsAlgorithm() { + return (GraphicsAlgorithm) getModel(); + } + + // ======================= overwriteable behaviour ======================== + + /** + * Creates the EditPolicies of this EditPart. Subclasses often overwrite + * this method to change the behaviour of the editpart. + */ + @Override + protected void createEditPolicies() { + } + + /** + * Returns the children of this EditPart. + * + * @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren() + */ + @Override + protected List getModelChildren() { + List retList = new ArrayList(); + GraphicsAlgorithm graphicsAlgorithm = getGraphicsAlgorithm(); + if (graphicsAlgorithm != null && graphicsAlgorithm.eResource() != null) { + final List graphicsAlgorithmChildren = graphicsAlgorithm.getGraphicsAlgorithmChildren(); + addAllElementsIfNotNull(retList, graphicsAlgorithmChildren); + if (graphicsAlgorithm instanceof Polyline) { + Polyline pl = (Polyline) graphicsAlgorithm; + addAllElementsIfNotNull(retList, pl.getPoints()); + } + } + return retList; + } +} \ No newline at end of file diff --git a/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PictogramElementTreeEditPart.java b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PictogramElementTreeEditPart.java new file mode 100644 index 0000000..9a92999 --- /dev/null +++ b/src/org.activiti.designer.eclipse/src/main/java/org/activiti/designer/eclipse/outline/tree/PictogramElementTreeEditPart.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.eclipse.outline.tree; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.graphiti.mm.StyleContainer; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.algorithms.styles.Color; +import org.eclipse.graphiti.mm.algorithms.styles.Point; +import org.eclipse.graphiti.mm.algorithms.styles.Style; +import org.eclipse.graphiti.mm.pictograms.AnchorContainer; +import org.eclipse.graphiti.mm.pictograms.Connection; +import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.FreeFormConnection; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; + +/** + * A default-implementation for a TreeEditPart, which wraps a Shape. It can be + * overwritten to provide different behaviour. + */ +public class PictogramElementTreeEditPart extends AbstractGraphicsTreeEditPart { + + /** + * Creates a new PictogramElementTreeEditPart for the given model Object. + * + * @param configurationProvider + * The IConfigurationProvider which defines the model + * @param shape + * The Shape of this EditPart. + */ + public PictogramElementTreeEditPart(PictogramElement pictogramElement) { + super(pictogramElement); + } + + /** + * Returns the Shape of this EditPart + * + * @return The Shape of this EditPart + */ + public PictogramElement getPictogramElement() { + return (PictogramElement) getModel(); + } + + // ======================= overwriteable behaviour ======================== + + /** + * Creates the EditPolicies of this EditPart. Subclasses often overwrite + * this method to change the behaviour of the editpart. + */ + @Override + protected void createEditPolicies() { + } + + /** + * Returns the children of this EditPart. + * + * @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren() + */ + @Override + protected List getModelChildren() { + List retList = new ArrayList(); + PictogramElement pictogramElement = getPictogramElement(); + + if (pictogramElement instanceof ContainerShape) { + ContainerShape containerShape = (ContainerShape) pictogramElement; + addAllElementsIfNotNull(retList, containerShape.getChildren()); + } + if (pictogramElement instanceof AnchorContainer) { + AnchorContainer notAnAnchorElement = (AnchorContainer) pictogramElement; + addAllElementsIfNotNull(retList, notAnAnchorElement.getAnchors()); + } + if (pictogramElement instanceof Connection) { + Connection connection = (Connection) pictogramElement; + Collection connectionDecorators = connection.getConnectionDecorators(); + addAllElementsIfNotNull(retList, connectionDecorators); + } + if (pictogramElement instanceof FreeFormConnection) { + FreeFormConnection connection = (FreeFormConnection) pictogramElement; + Collection bendpoints = connection.getBendpoints(); + addAllElementsIfNotNull(retList, bendpoints); + } + if (pictogramElement instanceof Diagram) { + Diagram diagram = (Diagram) pictogramElement; + addAllElementsIfNotNull(retList, diagram.getConnections()); + Collection colors = diagram.getColors(); + addAllElementsIfNotNull(retList, colors); + } + + if (pictogramElement instanceof StyleContainer) { + StyleContainer styleContainer = (StyleContainer) pictogramElement; + Collection + + +
    +
    +

    Activiti Eclipse BPMN 2.0 Designer Update Site

    +

    + Activiti Eclipse BPMN 2.0 Designer Update Site + +

    +

    Category: Activiti Eclipse BPMN 2.0 Designer [id: designer]

    +

    + Activiti Eclipse BPMN 2.0 Designer + Contains 1 feature. +

    + + + + + + + + + + + + + + + +
    + ID + + + Version + + + Download + +
    org.activiti.graphiti.bpmn.feature0.5.0download Download
    +
    +
    + + + \ No newline at end of file diff --git a/src/org.activiti.designer.updatesite/pom.xml b/src/org.activiti.designer.updatesite/pom.xml new file mode 100644 index 0000000..a8cab4b --- /dev/null +++ b/src/org.activiti.designer.updatesite/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + + org.activiti.designer.updatesite + eclipse-update-site + Activiti Designer - Update site + + \ No newline at end of file diff --git a/src/org.activiti.designer.updatesite/site.xml b/src/org.activiti.designer.updatesite/site.xml new file mode 100644 index 0000000..f41c157 --- /dev/null +++ b/src/org.activiti.designer.updatesite/site.xml @@ -0,0 +1,14 @@ + + + + Activiti Eclipse BPMN 2.0 Designer Update Site + + + + + + + Activiti BPMN Designer + + + diff --git a/src/org.activiti.designer.updatesite/web/assets/images/activiti_logo.png b/src/org.activiti.designer.updatesite/web/assets/images/activiti_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7ddbab60178ecea935cee120d6d9a730dac89a GIT binary patch literal 5241 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 UGkGjIO#lD@07*qoM6N<$f+^-cqW}N^ literal 0 HcmV?d00001 diff --git a/src/org.activiti.designer.updatesite/web/assets/styles/site.css b/src/org.activiti.designer.updatesite/web/assets/styles/site.css new file mode 100644 index 0000000..ddef75d --- /dev/null +++ b/src/org.activiti.designer.updatesite/web/assets/styles/site.css @@ -0,0 +1,101 @@ +body { + font-family: Helvetica,Arial,sans-serif; + text-align: center; + font-size: 11px; + line-height: 1.125em; + margin: 0; + padding: 0; +} + +div.contained { + width: 960px; + margin-left: auto; + margin-right: auto; + text-align: left; +} + +div#header { + background-color: #ffffff; + border-bottom: 1px solid #B9DDFA; + height: 100px; + width: 100%; + margin: 0; + padding: 0; +} + +div#header div.logo { + padding-top: 26px; +} + +div#footer { + +background-color: #FBFBFB; +border-top: 1px solid #DDDDDD; +height:100px; +margin-top:24px; +width:100%; + + /* height: 20px; + background-color: #ddd; + color: #fff; + border-top: 2px solid #DD1718; + margin-top: 4ex; + */ +} + +h1, h2 { + font-weight: bold; + color: #007DC3; +} + +h1 { + font-size: 150%; +} + +h2 { + font-size: 130%; +} + +p { + font-size: 110%; +} + +table { + font-size: 11px; +} + +table thead th { + background-color: #ddd; + font-weight: bold; + font-size: 110%; +} + +table tbody td { + font-size: 110%; +} + +tr.alternate1 td { + background: #EEEEFF; +} +tr.alternate2 td { + background: #FFFFFF; +} + +a { + color: #007DC3; + background-color: inherit; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +a:visited { + color: #007DC3; + background-color: inherit; +} + +a img { + border: none; +} \ No newline at end of file diff --git a/src/org.activiti.designer.updatesite/web/site.xsl b/src/org.activiti.designer.updatesite/web/site.xsl new file mode 100644 index 0000000..227e335 --- /dev/null +++ b/src/org.activiti.designer.updatesite/web/site.xsl @@ -0,0 +1,136 @@ + + + + + + + + + + + + <xsl:value-of select="description/@name" /> + + + + + + + +
    + +
    +

    + +

    + +

    + +

    + + + + + + + + + +

    + Category: + + [id: + + ] +

    + +

    + + Contains + + feature + + . +

    + + + + + + + + + + + + + + + + + + + + + alternate1 + + + alternate2 + + + + + + + + + + +
    + ID + + Version + + Download +
    + + + + + + download + Download + +
    +
    +
    +
    +
    + + + + + + +
    +
    diff --git a/src/org.activiti.designer.updatesite/work/site.css b/src/org.activiti.designer.updatesite/work/site.css new file mode 100644 index 0000000..62c6f9f --- /dev/null +++ b/src/org.activiti.designer.updatesite/work/site.css @@ -0,0 +1,12 @@ + diff --git a/src/org.activiti.designer.updatesite/work/site.xsl b/src/org.activiti.designer.updatesite/work/site.xsl new file mode 100644 index 0000000..6f060a6 --- /dev/null +++ b/src/org.activiti.designer.updatesite/work/site.xsl @@ -0,0 +1,214 @@ + + + + + + + + org.activiti.designer.update + + + +

    org.activiti.designer.update

    +

    + + + + + + + + + + + + + + + + dark-row + + + light-row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + dark-row + + + light-row + + + + + + + + + + + + + + + dark-row + + + light-row + + + + + + + + +
    + + + +
    + + + +
    +
    + ( - ) +
    +
    + + - + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    Operating Systems:
    Windows Systems:
    Languages:
    Architecture:
    +


    + Uncategorized +
    + + + +
    +
    + ( - ) +
    +
    + + - + +
    +

    +
    + + + + + + + + + + + + + + + + + + + + + +
    Operating Systems:
    Windows Systems:
    Languages:
    Architecture:
    +
    + + + +
    +
    + ( - ) +
    +
    + + - + +
    +

    +
    + + + + + + + + + + + + + + + + + + + + + +
    Operating Systems:
    Windows Systems:
    Languages:
    Architecture:
    +
    + + +
    +
    +
    diff --git a/src/org.activiti.designer.util/.settings/org.eclipse.jdt.core.prefs b/src/org.activiti.designer.util/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..9c0fb81 --- /dev/null +++ b/src/org.activiti.designer.util/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Wed May 18 09:20:57 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/src/org.activiti.designer.util/META-INF/MANIFEST.MF b/src/org.activiti.designer.util/META-INF/MANIFEST.MF new file mode 100644 index 0000000..489d57d --- /dev/null +++ b/src/org.activiti.designer.util/META-INF/MANIFEST.MF @@ -0,0 +1,33 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Activiti Designer - Util +Bundle-SymbolicName: org.activiti.designer.util;singleton:=true +Bundle-Version: 5.8.0 +Bundle-Activator: org.activiti.designer.util.Activator +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.graphiti, + org.activiti.designer.model, + org.apache.commons.lang, + org.eclipse.gef, + org.eclipse.jdt, + org.eclipse.graphiti.ui, + org.eclipse.jdt.core, + org.eclipse.ui.views.properties.tabbed, + org.eclipse.core.resources, + org.eclipse.emf.transaction +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.activiti.designer.util.eclipse, + org.activiti.designer.util.editor, + org.activiti.designer.util.features, + org.activiti.designer.util.platform, + org.activiti.designer.util.preferences, + org.activiti.designer.util.property, + org.activiti.designer.util.style, + org.activiti.designer.util.workspace +Bundle-ClassPath: ., + xalan-2.7.1.jar, + serializer-2.7.1.jar, + xml-apis-1.3.04.jar, + com.sun.xacml-0.1.jar diff --git a/src/org.activiti.designer.util/build.properties b/src/org.activiti.designer.util/build.properties new file mode 100644 index 0000000..f33db98 --- /dev/null +++ b/src/org.activiti.designer.util/build.properties @@ -0,0 +1,4 @@ +source.. = src/main/java/ +output.. = bin/ +bin.includes = META-INF/ + diff --git a/src/org.activiti.designer.util/pom.xml b/src/org.activiti.designer.util/pom.xml new file mode 100644 index 0000000..4cc5a40 --- /dev/null +++ b/src/org.activiti.designer.util/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + org.activiti.designer + org.activiti.designer.parent + 5.8.0 + ../org.activiti.designer.parent/pom.xml + + + org.activiti.designer.util + eclipse-plugin + Activiti Designer - Util + + \ No newline at end of file diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/Activator.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/Activator.java new file mode 100644 index 0000000..d1e9bd3 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/Activator.java @@ -0,0 +1,50 @@ +package org.activiti.designer.util; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.activiti.designer.util"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/eclipse/ActivitiUiUtil.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/eclipse/ActivitiUiUtil.java new file mode 100644 index 0000000..94570b0 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/eclipse/ActivitiUiUtil.java @@ -0,0 +1,273 @@ +package org.activiti.designer.util.eclipse; + +import java.util.List; + +import org.apache.commons.lang.ArrayUtils; +import org.eclipse.bpmn2.Activity; +import org.eclipse.bpmn2.BaseElement; +import org.eclipse.bpmn2.BoundaryEvent; +import org.eclipse.bpmn2.EventDefinition; +import org.eclipse.bpmn2.FlowElement; +import org.eclipse.bpmn2.SubProcess; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.gef.ui.actions.ActionRegistry; +import org.eclipse.graphiti.features.context.ICustomContext; +import org.eclipse.graphiti.mm.GraphicsAlgorithmContainer; +import org.eclipse.graphiti.mm.algorithms.AlgorithmsFactory; +import org.eclipse.graphiti.mm.algorithms.Ellipse; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.services.IGaService; +import org.eclipse.graphiti.ui.editor.DiagramEditor; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jface.action.IAction; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; + +public class ActivitiUiUtil { + + private static final String ID_PATTERN = "%s%s"; + + public static void runModelChange(final Runnable runnable, final TransactionalEditingDomain editingDomain, final String label) { + + editingDomain.getCommandStack().execute(new RecordingCommand(editingDomain, label) { + + protected void doExecute() { + runnable.run(); + } + }); + } + + @SuppressWarnings("rawtypes") + public static boolean contextPertainsToBusinessObject(final ICustomContext context, final Class businessClass) { + boolean result = false; + EList businessObjects = context.getInnerPictogramElement().getLink().getBusinessObjects(); + for (final EObject eobj : businessObjects) { + if (businessClass.equals(eobj.getClass())) { + result = true; + break; + } + } + return result; + } + + @SuppressWarnings("rawtypes") + public static Object getBusinessObjectFromContext(final ICustomContext context, final Class businessClass) { + Object result = null; + EList businessObjects = context.getInnerPictogramElement().getLink().getBusinessObjects(); + for (final EObject eobj : businessObjects) { + if (businessClass.equals(eobj.getClass())) { + result = eobj; + break; + } + } + return result; + } + + public static Ellipse createInvisibleEllipse(GraphicsAlgorithmContainer gaContainer, IGaService gaService) { + Ellipse ret = AlgorithmsFactory.eINSTANCE.createEllipse(); + ret.setX(0); + ret.setY(0); + ret.setWidth(0); + ret.setHeight(0); + ret.setFilled(false); + ret.setLineVisible(false); + if (gaContainer instanceof PictogramElement) { + PictogramElement pe = (PictogramElement) gaContainer; + pe.setGraphicsAlgorithm(ret); + } else if (gaContainer instanceof GraphicsAlgorithm) { + GraphicsAlgorithm parentGa = (GraphicsAlgorithm) gaContainer; + parentGa.getGraphicsAlgorithmChildren().add(ret); + } + return ret; + } + + public static org.eclipse.bpmn2.Process getProcessObject(Diagram diagram) { + for (EObject eObject : diagram.eResource().getContents()) { + if (eObject instanceof org.eclipse.bpmn2.Process) { + return (org.eclipse.bpmn2.Process) eObject; + } + } + return null; + } + + public static void doProjectReferenceChange(IProject currentProject, IJavaProject containerProject, String className) throws CoreException { + + if (currentProject.equals(containerProject.getProject())) { + return; + } + + IProjectDescription desc = currentProject.getDescription(); + IProject[] refs = desc.getReferencedProjects(); + IProject[] newRefs = new IProject[refs.length + 1]; + System.arraycopy(refs, 0, newRefs, 0, refs.length); + newRefs[refs.length] = containerProject.getProject(); + desc.setReferencedProjects(newRefs); + currentProject.setDescription(desc, new NullProgressMonitor()); + + IPath dependsOnPath = containerProject.getProject().getFullPath(); + + IJavaProject javaProject = (IJavaProject) currentProject.getNature(JavaCore.NATURE_ID); + IClasspathEntry prjEntry = JavaCore.newProjectEntry(dependsOnPath, true); + + boolean dependsOnPresent = false; + for (IClasspathEntry cpEntry : javaProject.getRawClasspath()) { + if (cpEntry.equals(prjEntry)) { + dependsOnPresent = true; + } + } + + if (!dependsOnPresent) { + IClasspathEntry[] entryList = new IClasspathEntry[1]; + entryList[0] = prjEntry; + IClasspathEntry[] newEntries = (IClasspathEntry[]) ArrayUtils.addAll(javaProject.getRawClasspath(), entryList); + javaProject.setRawClasspath(newEntries, null); + } + + } + + public static IProject getProjectFromDiagram(Diagram diagram) { + + IProject currentProject = null; + Resource resource = diagram.eResource(); + + URI uri = resource.getURI(); + URI uriTrimmed = uri.trimFragment(); + + if (uriTrimmed.isPlatformResource()) { + + String platformString = uriTrimmed.toPlatformString(true); + IResource fileResource = ResourcesPlugin.getWorkspace().getRoot().findMember(platformString); + + if (fileResource != null) { + currentProject = fileResource.getProject(); + } + } else { + IResource fileResource = ResourcesPlugin.getWorkspace().getRoot().findMember(uriTrimmed.toString()); + + if (fileResource != null) { + currentProject = fileResource.getProject(); + } + } + return currentProject; + } + + /** + * Gets the {@link ActionRegistry} for the currently active editor. + * + * @return the ActionRegistry or null + */ + public static final ActionRegistry getActionRegistry() { + IWorkbenchPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart(); + if (part instanceof DiagramEditor) { + DiagramEditor editor = (DiagramEditor) part; + return editor.getActionRegistryInternal(); + } + return null; + } + + /** + * Runs the action with the provided id for the currently active editor, if + * there is one. + * + * @param actionId + * the id of the action to run + */ + public static final void runAction(final String actionId) { + final ActionRegistry registry = getActionRegistry(); + if (registry != null) { + final IAction action = registry.getAction(actionId); + if (action != null) { + action.run(); + } + } + } + + public static final String getNextId(final Class featureClass, final String featureIdKey, final Diagram diagram) { + + int determinedId = 0; + + for (EObject contentObject : diagram.eResource().getContents()) { + + if(contentObject instanceof SubProcess) { + + for (FlowElement flowElement : ((SubProcess) contentObject).getFlowElements()) { + + if (flowElement.getClass() == featureClass) { + String contentObjectId = flowElement.getId().replace(featureIdKey, ""); + determinedId = getId(contentObjectId, determinedId); + } + if (flowElement instanceof Activity) { + List eventList = ((Activity) flowElement).getBoundaryEventRefs(); + for (BoundaryEvent boundaryEvent : eventList) { + List definitionList = boundaryEvent.getEventDefinitions(); + for (EventDefinition eventDefinition : definitionList) { + if(eventDefinition.getClass() == featureClass) { + String contentObjectId = boundaryEvent.getId().replace(featureIdKey, ""); + determinedId = getId(contentObjectId, determinedId); + } + } + } + } + } + } + + if (contentObject.getClass() == featureClass) { + BaseElement tempElement = (BaseElement) contentObject; + String contentObjectId = tempElement.getId().replace(featureIdKey, ""); + determinedId = getId(contentObjectId, determinedId); + } + if (contentObject instanceof Activity) { + List eventList = ((Activity) contentObject).getBoundaryEventRefs(); + for (BoundaryEvent boundaryEvent : eventList) { + List definitionList = boundaryEvent.getEventDefinitions(); + for (EventDefinition eventDefinition : definitionList) { + if(eventDefinition.getClass() == featureClass) { + String contentObjectId = boundaryEvent.getId().replace(featureIdKey, ""); + determinedId = getId(contentObjectId, determinedId); + } + } + } + } + } + determinedId++; + return String.format(ID_PATTERN, featureIdKey, determinedId); + + } + + private static int getId(String contentObjectId, int determinedId) { + int newdId = determinedId; + boolean isNumber = true; + if(contentObjectId != null && contentObjectId.length() > 0) { + + for(int i = 0; i < contentObjectId.length(); i++) { + if(Character.isDigit(contentObjectId.charAt(i)) == false) { + isNumber = false; + } + } + if(isNumber == true) { + Integer intNumber = Integer.valueOf(contentObjectId); + if (intNumber > newdId) { + newdId = intNumber; + } + } + } + return newdId; + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/editor/ModifiableListEditor.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/editor/ModifiableListEditor.java new file mode 100644 index 0000000..20fdcb6 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/editor/ModifiableListEditor.java @@ -0,0 +1,98 @@ +package org.activiti.designer.util.editor; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.preference.ListEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.List; + + +/** + * @author Tijs Rademakers + */ +public abstract class ModifiableListEditor extends ListEditor { + + public ModifiableListEditor(String name, String labelText, Composite parent) { + super(name, labelText, parent); + } + + /** + * The subclasses must override this to return the modified entry. + * + * @param original the new entry + * @return the modified entry. Return null to prevent modification. + */ + protected abstract String getModifiedEntry(String original); + + private Button editButton; + private List commandListControl; + + @Override + public Composite getButtonBoxControl(Composite parent) { + Composite buttonBoxControl = super.getButtonBoxControl(parent); + if (editButton == null) { + editButton = createPushButton(buttonBoxControl, "Edit..."); + editButton.setEnabled(false); + editButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (commandListControl.getSelectionCount() == 1) { + String modified = getModifiedEntry(commandListControl.getSelection()[0]); + if (modified != null) { + int selectedIndex = commandListControl.getSelectionIndex(); + commandListControl.remove(selectedIndex); + commandListControl.add(modified, selectedIndex); + } + } + } + }); + buttonBoxControl.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent event) { + editButton = null; + } + }); + } + return buttonBoxControl; + } + + /** + * Helper method to create a push button. + * + * @param parent the parent control + * @param key the resource name used to supply the button's label text + * @return Button + */ + private Button createPushButton(Composite parent, String key) { + Button button = new Button(parent, SWT.PUSH); + button.setText(key); + button.setFont(parent.getFont()); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + int widthHint = convertHorizontalDLUsToPixels(button, + IDialogConstants.BUTTON_WIDTH); + data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, + SWT.DEFAULT, true).x); + button.setLayoutData(data); + return button; + } + + @Override + public org.eclipse.swt.widgets.List getListControl(Composite parent) { + List listControl = super.getListControl(parent); + if (commandListControl == null) { + commandListControl = listControl; + commandListControl.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + editButton.setEnabled(commandListControl.getSelectionCount() == 1); + } + }); + } + return listControl; + } +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/features/AbstractCreateBPMNFeature.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/features/AbstractCreateBPMNFeature.java new file mode 100644 index 0000000..aa37965 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/features/AbstractCreateBPMNFeature.java @@ -0,0 +1,31 @@ +/** + * + */ +package org.activiti.designer.util.features; + +import org.activiti.designer.util.eclipse.ActivitiUiUtil; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.impl.AbstractCreateFeature; + +/** + * @author Tiese Barrell + * @version 2 + * @since 0.5.0 + * + */ +public abstract class AbstractCreateBPMNFeature extends AbstractCreateFeature { + + public AbstractCreateBPMNFeature(IFeatureProvider fp, String name, String description) { + super(fp, name, description); + } + + protected abstract String getFeatureIdKey(); + + @SuppressWarnings("rawtypes") + protected abstract Class getFeatureClass(); + + protected String getNextId() { + return ActivitiUiUtil.getNextId(getFeatureClass(), getFeatureIdKey(), getDiagram()); + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSEnum.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSEnum.java new file mode 100644 index 0000000..a7a0c35 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSEnum.java @@ -0,0 +1,7 @@ +package org.activiti.designer.util.platform; + +public enum OSEnum { + + Windows, Mac, Linux + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSUtil.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSUtil.java new file mode 100644 index 0000000..8bdc4a8 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/platform/OSUtil.java @@ -0,0 +1,18 @@ +package org.activiti.designer.util.platform; + +public class OSUtil { + + private static String osName = null; + + public static OSEnum getOperatingSystem() { + if(osName == null) { + osName = System.getProperty("os.name"); + } + if(osName.contains("Mac")) { + return OSEnum.Mac; + } else { + return OSEnum.Windows; + } + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/preferences/Preferences.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/preferences/Preferences.java new file mode 100644 index 0000000..ed10406 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/preferences/Preferences.java @@ -0,0 +1,43 @@ +/** + * + */ +package org.activiti.designer.util.preferences; + +/** + * Enumeration of preferences used in the designer. + * + * @author Tiese Barrell + * @since 0.5.1 + * @version 2 + * + */ +public enum Preferences { + + ECLIPSE_ACTIVITI_JAR_LOCATION("org.activiti.designer.preferences.eclipse.activitiJarLocation"), + ALFRESCO_ENABLE("com.alfresco.designer.preferences.enable"), + ALFRESCO_FORMTYPES_STARTEVENT("com.alfresco.designer.preferences.formtypes.startevent"), + ALFRESCO_FORMTYPES_USERTASK("com.alfresco.designer.preferences.formtypes.usertask"), + EDITOR_ADD_LABELS_TO_NEW_SEQUENCEFLOWS("org.activiti.designer.preferences.editor.addLabelsToNewSequenceFlows"), + EDITOR_ADD_DEFAULT_CONTENT_TO_DIAGRAMS("org.activiti.designer.preferences.editor.addDefaultContentToDiagrams"), + SAVE_TO_FORMAT("org.activiti.designer.preferences.save.saveToFormat"), + VALIDATE_ACTIVITI_BPMN_FORMAT("org.activiti.designer.preferences.validation.validateActivitiBPMNFormat"), + SKIP_BPMN_MARSHALLER_ON_VALIDATION_FAILURE("org.activiti.designer.preferences.validation.skipBPMNMarshallerOnValidationFailure"), + IMPORT_USE_BPMNDI("org.activiti.designer.preferences.import.useBPMNDI"), + + // + // Adding support for custom preferences. + PATH_TO_SATMC_BINARY("org.activiti.designer.preferences.pathToSATMC"), + ALL_TASKS_AS_HUMANTASKS("org.activiti.designer.preferences.analyzeAllTasksAsHumanTasks"); + // + + private String preferenceId; + + private Preferences(final String preferenceId) { + this.preferenceId = preferenceId; + } + + public String getPreferenceId() { + return preferenceId; + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/property/ActivitiPropertySection.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/property/ActivitiPropertySection.java new file mode 100644 index 0000000..9766860 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/property/ActivitiPropertySection.java @@ -0,0 +1,29 @@ +package org.activiti.designer.util.property; + +import org.eclipse.graphiti.platform.IDiagramEditor; +import org.eclipse.graphiti.ui.platform.GFPropertySection; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.part.IContributedContentsView; + +public abstract class ActivitiPropertySection extends GFPropertySection { + + /** + * @return the {@link IDiagramEditor} diagram editor. + */ + protected IDiagramEditor getDiagramEditor() { + IWorkbenchPart part = getPart(); + if (part instanceof IContributedContentsView) { + IContributedContentsView contributedView = (IContributedContentsView) part + .getAdapter(IContributedContentsView.class); + if (contributedView != null) { + part = contributedView.getContributingPart(); + } + } + + if (part instanceof IDiagramEditor) { + return (IDiagramEditor) part; + } + return null; + } + +} diff --git a/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/style/StyleUtil.java b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/style/StyleUtil.java new file mode 100644 index 0000000..3fcd964 --- /dev/null +++ b/src/org.activiti.designer.util/src/main/java/org/activiti/designer/util/style/StyleUtil.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * + * + * Copyright (c) 2005, 2010 SAP AG. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * SAP AG - initial API, implementation and documentation + * + * + * + *******************************************************************************/ +package org.activiti.designer.util.style; + +import java.util.Collection; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.graphiti.mm.StyleContainer; +import org.eclipse.graphiti.mm.algorithms.styles.AdaptedGradientColoredAreas; +import org.eclipse.graphiti.mm.algorithms.styles.GradientColoredArea; +import org.eclipse.graphiti.mm.algorithms.styles.GradientColoredAreas; +import org.eclipse.graphiti.mm.algorithms.styles.LocationType; +import org.eclipse.graphiti.mm.algorithms.styles.Style; +import org.eclipse.graphiti.mm.algorithms.styles.StylesFactory; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.services.Graphiti; +import org.eclipse.graphiti.services.IGaService; +import org.eclipse.graphiti.util.ColorConstant; +import org.eclipse.graphiti.util.ColorUtil; +import org.eclipse.graphiti.util.IColorConstant; +import org.eclipse.graphiti.util.IGradientType; +import org.eclipse.graphiti.util.IPredefinedRenderingStyle; + +public class StyleUtil { + + private static final IColorConstant BPMN_CLASS_FOREGROUND = new ColorConstant(0, 0, 0); + + public static Style getStyleForTask(Diagram diagram) { + final String styleId = "TASK"; //$NON-NLS-1$ + + Style style = findStyle(diagram, styleId); + if (style == null) { // style not found - create new style + IGaService gaService = Graphiti.getGaService(); + style = gaService.createStyle(diagram, styleId); + style.setForeground(gaService.manageColor(diagram, BPMN_CLASS_FOREGROUND)); + gaService.setRenderingStyle(style, getDefaultTaskColor()); + style.setLineWidth(20); + } + return style; + } + // + public static Style getStyleForSecurityNode(Diagram diagram) { + final String styleId = "SECURITYNODE"; //$NON-NLS-1$ + + Style style = findStyle(diagram, styleId); + if (style == null) { // style not found - create new style + IGaService gaService = Graphiti.getGaService(); + style = gaService.createStyle(diagram, styleId); + style.setForeground(gaService.manageColor(diagram,IColorConstant.LIGHT_BLUE)); + gaService.setRenderingStyle(style, getDefaultSecurityNodeColor()); + style.setLineWidth(20); + } + return style; + } + // + + public static Style getStyleForEvent(Diagram diagram) { + final String styleId = "EVENT"; //$NON-NLS-1$ + + Style style = findStyle(diagram, styleId); + if (style == null) { // style not found - create new style + IGaService gaService = Graphiti.getGaService(); + style = gaService.createStyle(diagram, styleId); + style.setForeground(gaService.manageColor(diagram, BPMN_CLASS_FOREGROUND)); + gaService.setRenderingStyle(style, getDefaultEventColor()); + style.setLineWidth(20); + } + return style; + } + + public static Style getStyleForPolygon(Diagram diagram) { + final String styleId = "BPMN-POLYGON-ARROW"; //$NON-NLS-1$ + + Style style = findStyle(diagram, styleId); + + if (style == null) { // style not found - create new style + IGaService gaService = Graphiti.getGaService(); + style = gaService.createStyle(diagram, styleId); + style.setForeground(gaService.manageColor(diagram, IColorConstant.BLACK)); + style.setBackground(gaService.manageColor(diagram, IColorConstant.BLACK)); + style.setLineWidth(1); + } + return style; + } + + // find the style with a given id in the style-container, can return null + private static Style findStyle(StyleContainer styleContainer, String id) { + // find and return style + Collection