| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.zest.library.rest.client; |
| |
| import org.hamcrest.CoreMatchers; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.apache.zest.api.common.Optional; |
| import org.apache.zest.api.injection.scope.Structure; |
| import org.apache.zest.api.property.Property; |
| import org.apache.zest.api.structure.Application; |
| import org.apache.zest.api.structure.ApplicationDescriptor; |
| import org.apache.zest.api.structure.Module; |
| import org.apache.zest.api.value.ValueBuilder; |
| import org.apache.zest.api.value.ValueComposite; |
| import org.apache.zest.bootstrap.AssemblyException; |
| import org.apache.zest.bootstrap.ModuleAssembly; |
| import org.apache.zest.library.rest.client.api.ContextResourceClient; |
| import org.apache.zest.library.rest.client.api.ContextResourceClientFactory; |
| import org.apache.zest.library.rest.client.api.ErrorHandler; |
| import org.apache.zest.library.rest.client.api.HandlerCommand; |
| import org.apache.zest.library.rest.client.spi.ResponseHandler; |
| import org.apache.zest.library.rest.client.spi.ResultHandler; |
| import org.apache.zest.library.rest.common.Resource; |
| import org.apache.zest.library.rest.common.ValueAssembler; |
| import org.apache.zest.library.rest.common.link.Link; |
| import org.apache.zest.library.rest.common.link.Links; |
| import org.apache.zest.library.rest.common.link.LinksBuilder; |
| import org.apache.zest.library.rest.common.link.LinksUtil; |
| import org.apache.zest.library.rest.server.api.ContextResource; |
| import org.apache.zest.library.rest.server.api.ContextRestlet; |
| import org.apache.zest.library.rest.server.assembler.RestServerAssembler; |
| import org.apache.zest.library.rest.server.restlet.NullCommandResult; |
| import org.apache.zest.library.rest.server.spi.CommandResult; |
| import org.apache.zest.test.AbstractQi4jTest; |
| import org.apache.zest.valueserialization.orgjson.OrgJsonValueSerializationAssembler; |
| import org.restlet.Client; |
| import org.restlet.Request; |
| import org.restlet.Response; |
| import org.restlet.Server; |
| import org.restlet.Uniform; |
| import org.restlet.data.ChallengeScheme; |
| import org.restlet.data.Form; |
| import org.restlet.data.MediaType; |
| import org.restlet.data.Protocol; |
| import org.restlet.data.Reference; |
| import org.restlet.resource.ResourceException; |
| import org.restlet.security.ChallengeAuthenticator; |
| import org.restlet.security.MapVerifier; |
| import org.restlet.security.User; |
| import org.restlet.service.MetadataService; |
| |
| import static org.apache.zest.bootstrap.ImportedServiceDeclaration.NEW_OBJECT; |
| import static org.apache.zest.library.rest.client.api.HandlerCommand.command; |
| import static org.apache.zest.library.rest.client.api.HandlerCommand.query; |
| import static org.apache.zest.library.rest.client.api.HandlerCommand.refresh; |
| |
| /** |
| * ReST Client libraries documentation source snippets. |
| */ |
| public class ContinuousIntegrationTest |
| extends AbstractQi4jTest |
| { |
| private Server server; |
| private ContextResourceClient crc; |
| |
| @Override |
| public void assemble( ModuleAssembly module ) |
| throws AssemblyException |
| { |
| // General setup of client and server |
| new OrgJsonValueSerializationAssembler().assemble( module ); |
| new ClientAssembler().assemble( module ); |
| new ValueAssembler().assemble( module ); |
| new RestServerAssembler().assemble( module ); |
| |
| module.objects( NullCommandResult.class ); |
| module.importedServices( CommandResult.class ).importedBy( NEW_OBJECT ); |
| |
| module.importedServices( MetadataService.class ).importedBy( NEW_OBJECT ); |
| module.objects( MetadataService.class ); |
| |
| // Test specific setup |
| module.values( BuildSpec.class, BuildResult.class, ServerStatus.class, TagBuildCommand.class, RunBuildCommand.class ); |
| |
| module.objects( RootRestlet.class, RootResource.class, RootContext.class ); |
| } |
| |
| @Override |
| protected void initApplication( Application app ) |
| throws Exception |
| { |
| } |
| |
| @Before |
| public void startWebServer() |
| throws Exception |
| { |
| server = new Server( Protocol.HTTP, 8888 ); |
| ContextRestlet restlet = module.newObject( ContextRestlet.class, new org.restlet.Context() ); |
| |
| ChallengeAuthenticator guard = new ChallengeAuthenticator( null, ChallengeScheme.HTTP_BASIC, "testRealm" ); |
| MapVerifier mapVerifier = new MapVerifier(); |
| mapVerifier.getLocalSecrets().put( "rickard", "secret".toCharArray() ); |
| guard.setVerifier( mapVerifier ); |
| |
| guard.setNext( restlet ); |
| |
| server.setNext( guard ); |
| server.start(); |
| |
| //START SNIPPET: client-create1 |
| Client client = new Client( Protocol.HTTP ); |
| |
| ContextResourceClientFactory contextResourceClientFactory = module.newObject( ContextResourceClientFactory.class, client ); |
| contextResourceClientFactory.setAcceptedMediaTypes( MediaType.APPLICATION_JSON ); |
| //END SNIPPET: client-create1 |
| |
| //START SNIPPET: client-create2 |
| contextResourceClientFactory.setErrorHandler( new ErrorHandler().onError( ErrorHandler.AUTHENTICATION_REQUIRED, new ResponseHandler() |
| { |
| boolean tried = false; |
| |
| @Override |
| public HandlerCommand handleResponse( Response response, ContextResourceClient client ) |
| { |
| if( tried ) |
| { |
| throw new ResourceException( response.getStatus() ); |
| } |
| |
| tried = true; |
| client.getContextResourceClientFactory().getInfo().setUser( new User( "rickard", "secret" ) ); |
| |
| // Try again |
| return refresh(); |
| } |
| } ).onError( ErrorHandler.RECOVERABLE_ERROR, new ResponseHandler() |
| { |
| @Override |
| public HandlerCommand handleResponse( Response response, ContextResourceClient client ) |
| { |
| // Try to restart |
| return refresh(); |
| } |
| } ) ); |
| //END SNIPPET: client-create2 |
| |
| //START SNIPPET: client-create3 |
| Reference ref = new Reference( "http://localhost:8888/" ); |
| crc = contextResourceClientFactory.newClient( ref ); |
| //END SNIPPET: client-create3 |
| } |
| |
| @After |
| public void stopWebServer() |
| throws Exception |
| { |
| server.stop(); |
| } |
| |
| @Override |
| protected Application newApplicationInstance( ApplicationDescriptor applicationModel ) |
| { |
| return applicationModel.newInstance( qi4j.api(), new MetadataService() ); |
| } |
| |
| @Test |
| public void testServerStatus() |
| { |
| //START SNIPPET: query-without-value |
| crc.onResource( new ResultHandler<Resource>() |
| { |
| @Override |
| public HandlerCommand handleResult( Resource result, ContextResourceClient client ) |
| { |
| return query( "status" ); |
| } |
| } ).onQuery( "status", new ResultHandler<ServerStatus>() |
| { |
| @Override |
| public HandlerCommand handleResult( ServerStatus result, ContextResourceClient client ) |
| { |
| Assert.assertThat( result.currentStatus().get(), CoreMatchers.equalTo( "Idle" ) ); |
| return null; |
| } |
| } ); |
| |
| crc.start(); |
| //END SNIPPET: query-without-value |
| } |
| |
| @Test |
| public void testBuildStatusAndTag() |
| { |
| //START SNIPPET: query-and-command |
| crc.onResource( new ResultHandler<Resource>() |
| { |
| @Override |
| public HandlerCommand handleResult( Resource result, ContextResourceClient client ) |
| { |
| return query( "buildstatus", null ); |
| } |
| } ).onProcessingError( "buildstatus", new ResultHandler<BuildSpec>() |
| { |
| @Override |
| public HandlerCommand handleResult( BuildSpec result, ContextResourceClient client ) |
| { |
| ValueBuilder<BuildSpec> builder = module.newValueBuilderWithPrototype( result ); |
| |
| builder.prototype().buildNo().set( "#28" ); |
| |
| return query( "buildstatus", builder.newInstance() ); |
| } |
| } ).onQuery( "buildstatus", new ResultHandler<BuildResult>() |
| { |
| @Override |
| public HandlerCommand handleResult( BuildResult result, ContextResourceClient client ) |
| { |
| return command( "tagbuild", null ); |
| } |
| } ).onProcessingError( "tagbuild", new ResultHandler<Form>() |
| { |
| @Override |
| public HandlerCommand handleResult( Form result, ContextResourceClient client ) |
| { |
| result.set( "tag", "RC1" ); |
| result.set( "buildNo", "#28" ); |
| |
| return command( "tagbuild", result ); |
| } |
| } ); |
| |
| crc.start(); |
| //END SNIPPET: query-and-command |
| } |
| |
| @Test |
| public void testRunBuild() |
| { |
| //START SNIPPET: query-list-and-command |
| crc.onResource( new ResultHandler<Resource>() |
| { |
| @Override |
| public HandlerCommand handleResult( Resource result, ContextResourceClient client ) |
| { |
| return query( "runbuild" ); |
| } |
| } ).onQuery( "runbuild", new ResultHandler<Links>() |
| { |
| @Override |
| public HandlerCommand handleResult( Links result, ContextResourceClient client ) |
| { |
| Link link = LinksUtil.withId( "any", result ); |
| |
| return command( link ); |
| } |
| } ).onCommand( "runbuild", new ResponseHandler() |
| { |
| @Override |
| public HandlerCommand handleResponse( Response response, ContextResourceClient client ) |
| { |
| System.out.println( "Done" ); |
| return null; |
| } |
| } ); |
| |
| crc.start(); |
| //END SNIPPET: query-list-and-command |
| } |
| |
| @Test |
| public void testRunBuildProgressive() |
| { |
| //START SNIPPET: query-list-and-command-progressive |
| crc.onResource( new ResultHandler<Resource>() |
| { |
| @Override |
| public HandlerCommand handleResult( Resource result, ContextResourceClient client ) |
| { |
| return query( "runbuild" ).onSuccess( new ResultHandler<Links>() |
| { |
| @Override |
| public HandlerCommand handleResult( Links result, ContextResourceClient client ) |
| { |
| Link link = LinksUtil.withId( "any", result ); |
| |
| return command( link ).onSuccess( new ResponseHandler() |
| { |
| @Override |
| public HandlerCommand handleResponse( Response response, ContextResourceClient client ) |
| { |
| System.out.println( "Done" ); |
| return null; |
| } |
| } ); |
| } |
| } ); |
| } |
| } ); |
| |
| crc.start(); |
| //END SNIPPET: query-list-and-command-progressive |
| } |
| |
| public interface TagBuildCommand |
| extends ValueComposite |
| { |
| Property<String> buildNo(); |
| |
| Property<String> tag(); |
| |
| @Optional |
| Property<String> comment(); |
| } |
| |
| public interface BuildResult |
| extends ValueComposite |
| { |
| Property<String> buildNo(); |
| |
| Property<Integer> testsPassed(); |
| |
| Property<Integer> testsFailed(); |
| } |
| |
| public interface BuildSpec |
| extends ValueComposite |
| { |
| @Optional |
| Property<String> buildNo(); |
| |
| @Optional |
| Property<String> tag(); |
| } |
| |
| public interface ServerStatus |
| extends ValueComposite |
| { |
| Property<String> currentStatus(); |
| |
| Property<Integer> availableAgents(); |
| } |
| |
| public interface RunBuildCommand |
| extends ValueComposite |
| { |
| Property<String> entity(); |
| } |
| |
| public static class RootRestlet |
| extends ContextRestlet |
| { |
| @Override |
| protected Uniform createRoot( Request request, Response response ) |
| { |
| return module.newObject( RootResource.class, this ); |
| } |
| } |
| |
| public static class RootResource |
| extends ContextResource |
| { |
| |
| private RootContext rootContext() |
| { |
| return context( RootContext.class ); |
| } |
| |
| public RootResource() |
| { |
| } |
| |
| public BuildResult buildstatus( BuildSpec build ) |
| throws Throwable |
| { |
| return rootContext().buildStatus( build ); |
| } |
| |
| public ServerStatus status() |
| throws Throwable |
| { |
| return rootContext().serverStatus(); |
| } |
| |
| public void tagbuild( TagBuildCommand command ) |
| throws Throwable |
| { |
| rootContext().tagBuild( command ); |
| } |
| |
| public void runbuild( RunBuildCommand run ) |
| { |
| rootContext().runBuildOn( run.entity().get() ); |
| } |
| |
| public Links runbuild() |
| { |
| return new LinksBuilder( module ). |
| command( "runbuild" ). |
| addLink( "On available agent", "any" ). |
| addLink( "On LinuxAgent", "LinuxAgent" ). |
| addLink( "On WinAgent", "WinAgent" ).newLinks(); |
| } |
| } |
| |
| public static class RootContext |
| { |
| |
| @Structure |
| Module module; |
| |
| public BuildResult buildStatus( BuildSpec build ) |
| { |
| String buildNo = build.buildNo().get(); // or lookup by tag |
| return module.newValueFromSerializedState( BuildResult.class, "{ 'buildNo':'" + buildNo + "', 'testsPassed': 37, 'testsFailed': 1}" ); |
| } |
| |
| public ServerStatus serverStatus() |
| { |
| return module.newValueFromSerializedState( ServerStatus.class, "{'currentStatus':'Idle', 'availableAgents': 2 }" ); |
| } |
| |
| public void tagBuild( TagBuildCommand command ) |
| { |
| // tagged |
| } |
| |
| public void runBuildOn( String agent ) |
| { |
| // build started |
| } |
| } |
| } |