diff --git a/source/HOP-Core-Tests/HOPRouteHanderWrapperTest.class.st b/source/HOP-Core-Tests/HOPRouteHanderWrapperTest.class.st index 0367abc..12115f0 100644 --- a/source/HOP-Core-Tests/HOPRouteHanderWrapperTest.class.st +++ b/source/HOP-Core-Tests/HOPRouteHanderWrapperTest.class.st @@ -45,3 +45,34 @@ HOPRouteHanderWrapperTest >> testRetryHandlerExceeded [ should: [ uriSpace asZincDelegate handleRequest: (ZnRequest get: #first) ] raise: HOPMaximumRetriesExceeded ] + +{ #category : 'tests' } +HOPRouteHanderWrapperTest >> testHandlerOfASegmentLeavesItsSiblingsAlone [ + | other | + other := uriSpace /+ #other. + other @@ (#GET -> (HOPPluggableHandler new block: [ :req | Error signal ])). + (uriSpace / #first) addHandler: HOPExceptionHandlerWrapper new. + self + should: [ uriSpace asZincDelegate handleRequest: (ZnRequest get: #other) ] + raise: Error +] + +{ #category : 'tests' } +HOPRouteHanderWrapperTest >> testHandlerOfASegmentWrapsItsChildren [ + | response | + uriSpace / #first / #second @@ (#GET -> (HOPPluggableHandler new block: [ :req | Error signal ])). + (uriSpace / #first) addHandler: HOPExceptionHandlerWrapper new. + response := uriSpace asZincDelegate handleRequest: (ZnRequest get: '/first/second'). + self assert: response status equals: 500 +] + +{ #category : 'tests' } +HOPRouteHanderWrapperTest >> testHandlerOfASegmentWrapsItsOwnMethod [ + "a segment that carries handlers answers a method on its own path, it is not only a + prefix for the segments below it" + | response | + uriSpace / #first @@ (#GET -> (HOPPluggableHandler new block: [ :req | Error signal ])). + (uriSpace / #first) addHandler: HOPExceptionHandlerWrapper new. + response := uriSpace asZincDelegate handleRequest: (ZnRequest get: #first). + self assert: response status equals: 500 +] diff --git a/source/HOP-Core-Tests/HOPUriBuilderTest.class.st b/source/HOP-Core-Tests/HOPUriBuilderTest.class.st index a848d81..d1b68eb 100644 --- a/source/HOP-Core-Tests/HOPUriBuilderTest.class.st +++ b/source/HOP-Core-Tests/HOPUriBuilderTest.class.st @@ -36,3 +36,23 @@ HOPUriBuilderTest >> testBuildUriForResource [ uri := uriSpace buildUriForResource: object. self assert: uri equals: '/api/objects/1/children/2' ] + +{ #category : 'tests' } +HOPUriBuilderTest >> testBuildUriForResourceInAMountedUriSpace [ + "a uri space mounted under a name is a named segment of the space it hangs in" + | uriSpace mounted objectSegment childSegment object uri | + objectSegment := HOPVariableSegment new + name: #objectId; + segmentNameSelector: #id. + childSegment := HOPVariableSegment new + name: #childId; + segmentNameSelector: #id. + mounted := HOPUriSpace new + name: #mounted; + yourself. + uriSpace := (HOPUriSpace /+ mounted) root. + mounted /+ #objects /+ objectSegment --> HOPUriBuildObject /+ #children /+ childSegment --> HOPUriBuildChildObject. + object := HOPUriBuildChildObject new container: HOPUriBuildObject new. + uri := uriSpace buildUriForResource: object. + self assert: uri equals: '/mounted/objects/1/children/2' +] diff --git a/source/HOP-Core/HOPCatchAllSegment.class.st b/source/HOP-Core/HOPCatchAllSegment.class.st index 80173f8..e5b788e 100644 --- a/source/HOP-Core/HOPCatchAllSegment.class.st +++ b/source/HOP-Core/HOPCatchAllSegment.class.st @@ -34,7 +34,7 @@ HOPCatchAllSegment >> matches: aString [ ] { #category : 'testing' } -HOPCatchAllSegment >> matchesNode: aHOPSpaceZone [ +HOPCatchAllSegment >> matchesNode: aHOPNode [ ^ false ] diff --git a/source/HOP-Core/HOPNamedSegment.class.st b/source/HOP-Core/HOPNamedSegment.class.st index 5006a1d..39de7c6 100644 --- a/source/HOP-Core/HOPNamedSegment.class.st +++ b/source/HOP-Core/HOPNamedSegment.class.st @@ -10,14 +10,6 @@ HOPNamedSegment >> acceptHOP: aHOPVisitor [ ^ aHOPVisitor visitNamedSegment: self ] -{ #category : 'converting' } -HOPNamedSegment >> asHOPSpaceZone [ - ^ HOPSpaceZone new - name: name; - mergeNode: self root; - yourself -] - { #category : 'as yet unclassified' } HOPNamedSegment >> canonicalUriFor: aResource [ ^ (super canonicalUriFor: aResource) diff --git a/source/HOP-Core/HOPNode.class.st b/source/HOP-Core/HOPNode.class.st index c87ba98..fb09de3 100644 --- a/source/HOP-Core/HOPNode.class.st +++ b/source/HOP-Core/HOPNode.class.st @@ -169,11 +169,6 @@ HOPNode >> isRoot [ ^ parent isNil ] -{ #category : 'testing' } -HOPNode >> isSpaceZone [ - ^ false -] - { #category : 'accessing' } HOPNode >> label [ ^ self name diff --git a/source/HOP-Core/HOPRouteMatcher.class.st b/source/HOP-Core/HOPRouteMatcher.class.st index cf05f66..c89d053 100644 --- a/source/HOP-Core/HOPRouteMatcher.class.st +++ b/source/HOP-Core/HOPRouteMatcher.class.st @@ -43,8 +43,7 @@ HOPRouteMatcher >> matchRoute [ currentSegment ifNil: [ currentSegment := self startSegment ]. - currentSegment isSpaceZone ifTrue: [ - self routeMatch addHandlers: currentSegment handlers ]. + self routeMatch addHandlers: currentSegment handlers. [ self atEnd ] whileFalse: [ currentSegment := currentSegment diff --git a/source/HOP-Core/HOPSegment.class.st b/source/HOP-Core/HOPSegment.class.st index d9052e9..c4dda3b 100644 --- a/source/HOP-Core/HOPSegment.class.st +++ b/source/HOP-Core/HOPSegment.class.st @@ -2,7 +2,8 @@ Class { #name : 'HOPSegment', #superclass : 'HOPNode', #instVars : [ - 'methods' + 'methods', + 'handlers' ], #category : 'HOP-Core', #package : 'HOP-Core' @@ -18,9 +19,18 @@ HOPSegment >> @@ anAssociation [ anAssociation addMethodsTo: self ] +{ #category : 'adding' } +HOPSegment >> addHandler: aHandler [ + handlers add: aHandler +] + { #category : 'services' } HOPSegment >> addSegment: key routeMatch: routeMatch [ - ^ routeMatch addSegment: self + "the handlers of a segment wrap everything that is reached through it, the + methods of the segment itself included" + routeMatch + addSegment: self; + addHandlers: handlers ] { #category : 'adding' } @@ -64,6 +74,16 @@ HOPSegment >> atMethod: aString put: anObject [ put: anObject ] +{ #category : 'accessing' } +HOPSegment >> handlers [ + ^ handlers +] + +{ #category : 'testing' } +HOPSegment >> hasHandlers [ + ^ handlers notEmpty +] + { #category : 'testing' } HOPSegment >> hasMethods [ ^ methods notEmpty @@ -72,7 +92,8 @@ HOPSegment >> hasMethods [ { #category : 'initialization' } HOPSegment >> initialize [ super initialize. - methods := Dictionary new + methods := Dictionary new. + handlers := OrderedCollection new ] { #category : 'as yet unclassified' } diff --git a/source/HOP-Core/HOPSpaceZone.class.st b/source/HOP-Core/HOPSpaceZone.class.st deleted file mode 100644 index 956403c..0000000 --- a/source/HOP-Core/HOPSpaceZone.class.st +++ /dev/null @@ -1,112 +0,0 @@ -Class { - #name : 'HOPSpaceZone', - #superclass : 'HOPNode', - #instVars : [ - 'handlers' - ], - #category : 'HOP-Core', - #package : 'HOP-Core' -} - -{ #category : 'converting' } -HOPSpaceZone class >> asHOPSegment [ - ^ self new - build; - asHOPSegment -] - -{ #category : 'visiting' } -HOPSpaceZone >> acceptHOP: aHOPVisitor [ - aHOPVisitor visitSpaceZone: self -] - -{ #category : 'adding' } -HOPSpaceZone >> addHandler: aHandler [ - handlers add: aHandler -] - -{ #category : 'testing' } -HOPSpaceZone >> addSegment: segment routeMatch: routeMatch [. - routeMatch addSegment: self. - - handlers ifNotNil: [ - routeMatch addHandlers: handlers ] -] - -{ #category : 'converting' } -HOPSpaceZone >> asHOPSegment [ - ^ self -] - -{ #category : 'as yet unclassified' } -HOPSpaceZone >> canonicalUriFor: aResource [ - | path | - path := super canonicalUriFor: aResource. - parent ifNotNil: [ - "if we are not the root space we add our name to be - part of the URI" - path add: name ]. - ^ path -] - -{ #category : 'accessing' } -HOPSpaceZone >> handlers [ - ^ handlers -] - -{ #category : 'testing' } -HOPSpaceZone >> hasHandlers [ - ^ handlers notEmpty -] - -{ #category : 'testing' } -HOPSpaceZone >> hasMethods [ - ^ false -] - -{ #category : 'initialization' } -HOPSpaceZone >> initialize [ - super initialize. - handlers := OrderedCollection new -] - -{ #category : 'testing' } -HOPSpaceZone >> isSpaceZone [ - ^ true -] - -{ #category : 'testing' } -HOPSpaceZone >> matches: segment [ - ^ name = segment -] - -{ #category : 'testing' } -HOPSpaceZone >> matchesNode: aHOPNode [ - (aHOPNode class == self class) ifFalse: [ ^ false ]. - ^ aHOPNode name = name -] - -{ #category : 'testing' } -HOPSpaceZone >> matchesScope: aResource in: requestContext [ - ^ false -] - -{ #category : 'printing' } -HOPSpaceZone >> nodeLabel [ - ^ 'zone' -] - -{ #category : 'accessing' } -HOPSpaceZone >> priority [ - ^ 1 -] - -{ #category : 'as yet unclassified' } -HOPSpaceZone >> uriFor: aResource resourceRoute: resourceRoute [ - | path | - path := super uriFor: aResource resourceRoute: resourceRoute. - parent ifNotNil: [ - path add: name ]. - ^ path - -] diff --git a/source/HOP-Core/HOPUriBuilder.class.st b/source/HOP-Core/HOPUriBuilder.class.st index 9a38aa1..037aeb2 100644 --- a/source/HOP-Core/HOPUriBuilder.class.st +++ b/source/HOP-Core/HOPUriBuilder.class.st @@ -65,16 +65,12 @@ HOPUriBuilder >> visitSegment: aHOPSegment [ self visit: aHOPSegment parent ] ] -{ #category : 'visiting' } -HOPUriBuilder >> visitSpaceZone: aSpaceZone [ - aSpaceZone hasParent ifTrue: [ - segments add: aSpaceZone name ]. - super visitSpaceZone: aSpaceZone -] - { #category : 'visiting' } HOPUriBuilder >> visitUriSpace: aUriSpace [ - + "the root is the empty path and adds nothing. A space mounted under a name is a + named segment of the space it is mounted in" + aUriSpace isRoot ifFalse: [ + self visitNamedSegment: aUriSpace ] ] { #category : 'visiting' } diff --git a/source/HOP-Core/HOPUriSpace.class.st b/source/HOP-Core/HOPUriSpace.class.st index 0b91eb5..25b215c 100644 --- a/source/HOP-Core/HOPUriSpace.class.st +++ b/source/HOP-Core/HOPUriSpace.class.st @@ -1,6 +1,6 @@ Class { #name : 'HOPUriSpace', - #superclass : 'HOPSpaceZone', + #superclass : 'HOPNamedSegment', #instVars : [ 'operationSegments', 'behaviorSegments' @@ -14,6 +14,14 @@ HOPUriSpace class >> /+ aSegment [ ^ self new /+ aSegment ] +{ #category : 'converting' } +HOPUriSpace class >> asHOPSegment [ + "a uri space class mounted under a name, as in #auth -> OIDCUriSpace" + ^ self new + build; + asHOPSegment +] + { #category : 'visiting' } HOPUriSpace >> acceptHOP: aHOPVisitor [ ^ aHOPVisitor visitUriSpace: self @@ -79,6 +87,13 @@ HOPUriSpace >> buildUriForResource: anObject [ build ] +{ #category : 'as yet unclassified' } +HOPUriSpace >> canonicalUriFor: aResource [ + "the root is the empty path and adds no segment, a mounted space adds its name" + self isRoot ifTrue: [ ^ OrderedCollection new ]. + ^ super canonicalUriFor: aResource +] + { #category : 'as yet unclassified' } HOPUriSpace >> canonicalUriForResource: resource [ @@ -203,6 +218,13 @@ HOPUriSpace >> uriBuilderClass [ ^ HOPUriBuilder ] +{ #category : 'as yet unclassified' } +HOPUriSpace >> uriFor: aResource resourceRoute: resourceRoute [ + "the root is the empty path and adds no segment, a mounted space adds its name" + self isRoot ifTrue: [ ^ OrderedCollection new ]. + ^ super uriFor: aResource resourceRoute: resourceRoute +] + { #category : 'as yet unclassified' } HOPUriSpace >> zincServerDelegate [ ^ HOPServerDelegate new diff --git a/source/HOP-Core/HOPVisitor.class.st b/source/HOP-Core/HOPVisitor.class.st index 73cd0e6..3959241 100644 --- a/source/HOP-Core/HOPVisitor.class.st +++ b/source/HOP-Core/HOPVisitor.class.st @@ -28,14 +28,9 @@ HOPVisitor >> visitSegment: aHOPSegment [ ] -{ #category : 'visiting' } -HOPVisitor >> visitSpaceZone: aHOSpaceZone [ - self visitSegment: aHOSpaceZone -] - { #category : 'visiting' } HOPVisitor >> visitUriSpace: aHOPUriSpace [ - self visitSpaceZone: aHOPUriSpace + self visitNamedSegment: aHOPUriSpace ] { #category : 'visiting' }