Java tutorial
/****************************************************************************** Copyright 2014 Mark Wigmans 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 com.chessix.vas.web; import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.dispatch.OnComplete; import akka.dispatch.OnFailure; import akka.dispatch.OnSuccess; import akka.pattern.Patterns; import com.chessix.vas.actors.messages.Balance; import com.chessix.vas.actors.messages.CreateAccount; import com.chessix.vas.dto.AccountCreated; import com.chessix.vas.dto.SaldoDTO; import com.chessix.vas.service.AccountService; import com.chessix.vas.service.ClasService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; import scala.concurrent.Future; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * @author Mark Wigmans */ @RestController @RequestMapping(value = "/account") @Slf4j public class AccountController { private static final int MAX_ACCOUNTS_IN_BATCH = 50000; private final ActorSystem system; private final ClasService clasService; private final AccountService accountService; private final long timeout = 30000L; /** * Auto wired constructor */ @Autowired public AccountController(final ActorSystem system, final ClasService clasService, final AccountService accountService) { this.system = system; this.clasService = clasService; this.accountService = accountService; } @RequestMapping(value = "/{clasId}", method = RequestMethod.POST) public DeferredResult<Object> createAccount(@PathVariable final String clasId) { return createAccount(clasId, null); } @RequestMapping(value = "/{clasId}/{accountId}", method = RequestMethod.POST) public DeferredResult<Object> createAccount(@PathVariable final String clasId, @PathVariable final String accountId) { log.info("createAccount({},{})", clasId, accountId); final ActorRef clas = clasService.getClas(clasId); final DeferredResult<Object> deferredResult = new DeferredResult<Object>(); if (clas != null) { final Future<Object> future = Patterns.ask(clas, new CreateAccount.RequestBuilder(clasId).accountId(accountId).build(), timeout); future.onSuccess(new OnSuccess<Object>() { @Override public void onSuccess(final Object result) { log.info("createAccount({}) : result: {}", clasId, result); final CreateAccount.Response response = (CreateAccount.Response) result; deferredResult.setResult( new AccountCreated(clasId, response.getAccountId(), true, "Account created")); } }, system.dispatcher()); future.onFailure(new OnFailure() { @Override public void onFailure(final Throwable arg) throws Throwable { log.error("onFailure", arg); deferredResult .setErrorResult(new AccountCreated(clasId, null, false, arg.getLocalizedMessage())); } }, system.dispatcher()); } else { deferredResult.setErrorResult(new AccountCreated(clasId, null, false, "CLAS does not exist")); } return deferredResult; } @RequestMapping(value = "/{clasId}/range/from/{start}/count/{count}", method = RequestMethod.POST) public DeferredResult<Object> createAccounts(@PathVariable final String clasId, @PathVariable final String start, @PathVariable final String count) { log.info("createAccounts({},{},{})", clasId, start, count); final ActorRef clas = clasService.getClas(clasId); final DeferredResult<Object> deferredResult = new DeferredResult<Object>(); final int countValue = Integer.parseInt(count); if (countValue > MAX_ACCOUNTS_IN_BATCH) { deferredResult .setErrorResult(String.format("count %s is to large (> %d)", count, MAX_ACCOUNTS_IN_BATCH)); return deferredResult; } if (clas != null) { final List<AccountCreated> results = Collections.synchronizedList(new LinkedList<AccountCreated>()); final AtomicInteger resultsCounter = new AtomicInteger(0); for (int i = Integer.parseInt(start); i < Integer.parseInt(start) + countValue; i++) { final String accountId = Integer.toString(i); log.debug("createAccounts() : create {}", accountId); final Future<Object> future = Patterns.ask(clas, new CreateAccount.RequestBuilder(clasId).accountId(accountId).build(), timeout * countValue); future.onSuccess(new OnSuccess<Object>() { @Override public void onSuccess(final Object result) { log.info("createAccount({}) : result: {}", clasId, result); final CreateAccount.Response response = (CreateAccount.Response) result; results.add(new AccountCreated(clasId, response.getAccountId(), true, String.format("Account %s created", accountId))); // check if all values are received if (resultsCounter.incrementAndGet() >= countValue) { deferredResult.setResult(results); } } }, system.dispatcher()); future.onFailure(new OnFailure() { @Override public void onFailure(final Throwable arg) throws Throwable { log.error("onFailure", arg); deferredResult .setErrorResult(new AccountCreated(clasId, null, false, arg.getLocalizedMessage())); } }, system.dispatcher()); } } else { deferredResult.setErrorResult(new AccountCreated(clasId, null, false, "CLAS does not exist")); } return deferredResult; } @RequestMapping(value = "/{clasId}/{accountId}/balance", method = RequestMethod.GET) public DeferredResult<Object> balance(@PathVariable final String clasId, @PathVariable final String accountId) { log.debug("balance({},{})", clasId, accountId); final ActorRef clas = clasService.getClas(clasId); final DeferredResult<Object> deferredResult = new DeferredResult<Object>(); if (clas != null) { final Future<Object> future = Patterns.ask(clas, new Balance.RequestBuilder(accountService.getAccountId(accountId)).build(), timeout); future.onComplete(new OnComplete<Object>() { @Override public void onComplete(final Throwable failure, final Object result) { if (failure != null) { // We got a failure, handle it here deferredResult.setErrorResult(failure); } else { // We got a result, do something with it deferredResult.setResult(result); } } }, system.dispatcher()); } else { deferredResult.setErrorResult(new SaldoDTO(clasId, accountId, null, false, "CLAS does not exist")); } return deferredResult; } }