Java tutorial
/* * Copyright 2014,2015 agwlvssainokuni * * 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 cherry.spring.common.foundation.impl; import static cherry.foundation.querydsl.QueryDslUtil.adjustSize; import static com.google.common.base.Preconditions.checkState; import static com.mysema.query.types.expr.DateTimeExpression.currentTimestamp; import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.joda.time.LocalDateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jdbc.query.QueryDslJdbcOperations; import org.springframework.data.jdbc.query.SqlInsertCallback; import org.springframework.data.jdbc.query.SqlInsertWithKeyCallback; import org.springframework.data.jdbc.query.SqlUpdateCallback; import org.springframework.transaction.annotation.Transactional; import cherry.foundation.async.AsyncProcessStore; import cherry.foundation.async.AsyncStatus; import cherry.foundation.async.AsyncType; import cherry.foundation.async.FileProcessResult; import cherry.foundation.async.FileRecordInfo; import cherry.foundation.type.DeletedFlag; import cherry.goods.command.CommandResult; import cherry.goods.util.ToMapUtil; import cherry.sqlapp.db.gen.query.QAsyncProcess; import cherry.sqlapp.db.gen.query.QAsyncProcessCommand; import cherry.sqlapp.db.gen.query.QAsyncProcessCommandArg; import cherry.sqlapp.db.gen.query.QAsyncProcessCommandResult; import cherry.sqlapp.db.gen.query.QAsyncProcessException; import cherry.sqlapp.db.gen.query.QAsyncProcessFile; import cherry.sqlapp.db.gen.query.QAsyncProcessFileArg; import cherry.sqlapp.db.gen.query.QAsyncProcessFileResult; import cherry.sqlapp.db.gen.query.QAsyncProcessFileResultDetail; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.mysema.query.sql.dml.SQLInsertClause; import com.mysema.query.sql.dml.SQLUpdateClause; public class AsyncProcessStoreImpl implements AsyncProcessStore { @Autowired private QueryDslJdbcOperations queryDslJdbcOperations; @Autowired private ObjectMapper objectMapper; @Transactional(value = "jtaTransactionManager", propagation = REQUIRES_NEW) @Override public long createFileProcess(String launcherId, LocalDateTime dtm, final String description, final String name, final String originalFilename, final String contentType, final long size, final String handlerName, String... args) { final long asyncId = createAsyncProcess(launcherId, description, AsyncType.FILE, dtm); final QAsyncProcessFile a = new QAsyncProcessFile("a"); long count = queryDslJdbcOperations.insert(a, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(a.asyncId, asyncId); insert.set(a.paramName, adjustSize(name, a.paramName)); insert.set(a.originalFilename, adjustSize(originalFilename, a.originalFilename)); insert.set(a.contentType, adjustSize(contentType, a.contentType)); insert.set(a.fileSize, size); insert.set(a.handlerName, adjustSize(handlerName, a.handlerName)); return insert.execute(); } }); checkState(count == 1L, "failed to create QAsyncProcessFile: asyncId={0}, paramName={1}, originalFilename={2}, contentType={3}, fileSize={4}, handlerName={5}", asyncId, name, originalFilename, contentType, size, handlerName); final QAsyncProcessFileArg b = new QAsyncProcessFileArg("b"); for (final String arg : args) { long c = queryDslJdbcOperations.insert(b, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(b.asyncId, asyncId); insert.set(b.argument, adjustSize(arg, b.argument)); return insert.execute(); } }); checkState(c == 1L, "failed to create QAsyncProcessFileArg: asyncId={0}, arg={1}", asyncId, arg); } return asyncId; } @Transactional(value = "jtaTransactionManager", propagation = REQUIRES_NEW) public long createCommand(String launcherId, LocalDateTime dtm, final String description, final String command, String... args) { final long asyncId = createAsyncProcess(launcherId, description, AsyncType.COMMAND, dtm); final QAsyncProcessCommand a = new QAsyncProcessCommand("a"); long count = queryDslJdbcOperations.insert(a, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(a.asyncId, asyncId); insert.set(a.command, adjustSize(command, a.command)); return insert.execute(); } }); checkState(count == 1L, "failed to create QAsyncProcessCommand: asyncId={0}, command={1}", asyncId, command); final QAsyncProcessCommandArg b = new QAsyncProcessCommandArg("b"); for (final String arg : args) { long c = queryDslJdbcOperations.insert(b, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(b.asyncId, asyncId); insert.set(b.argument, adjustSize(arg, b.argument)); return insert.execute(); } }); checkState(c == 1L, "failed to create QAsyncProcessCommandArg: asyncId={0}, arg={1}", asyncId, arg); } return asyncId; } @Transactional("jtaTransactionManager") public void updateToLaunched(final long asyncId, final LocalDateTime dtm) { final QAsyncProcess a = new QAsyncProcess("a"); long count = queryDslJdbcOperations.update(a, new SqlUpdateCallback() { @Override public long doInSqlUpdateClause(SQLUpdateClause update) { update.set(a.asyncStatus, AsyncStatus.LAUNCHED.code()); update.set(a.launchedAt, dtm); update.set(a.updatedAt, currentTimestamp(LocalDateTime.class)); update.set(a.lockVersion, a.lockVersion.add(1)); update.where(a.id.eq(asyncId)); update.where(a.deletedFlg.eq(DeletedFlag.NOT_DELETED.code())); return update.execute(); } }); checkState(count == 1L, "failed to update QAsyncProcess: id={0}, asyncStatus={1}, launchedAt={2}, count={3}", asyncId, AsyncStatus.LAUNCHED.code(), dtm, count); } @Transactional(propagation = REQUIRES_NEW) @Override public void updateToProcessing(final long asyncId, final LocalDateTime dtm) { final QAsyncProcess a = new QAsyncProcess("a"); long count = queryDslJdbcOperations.update(a, new SqlUpdateCallback() { @Override public long doInSqlUpdateClause(SQLUpdateClause update) { update.set(a.asyncStatus, AsyncStatus.PROCESSING.code()); update.set(a.startedAt, dtm); update.set(a.updatedAt, currentTimestamp(LocalDateTime.class)); update.set(a.lockVersion, a.lockVersion.add(1)); update.where(a.id.eq(asyncId)); update.where(a.deletedFlg.eq(DeletedFlag.NOT_DELETED.code())); return update.execute(); } }); checkState(count == 1L, "failed to update QAsyncProcess: id={0}, asyncStatus={1}, startedAt={2}, count={3}", asyncId, AsyncStatus.PROCESSING.code(), dtm, count); } @Transactional(propagation = REQUIRES_NEW) @Override public void finishFileProcess(final long asyncId, final LocalDateTime dtm, final AsyncStatus status, final FileProcessResult result) { finishAsyncProcess(asyncId, dtm, status); final QAsyncProcessFileResult a = new QAsyncProcessFileResult("a"); long count = queryDslJdbcOperations.insert(a, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(a.asyncId, asyncId); insert.set(a.totalCount, result.getTotalCount()); insert.set(a.okCount, result.getOkCount()); insert.set(a.ngCount, result.getNgCount()); return insert.execute(); } }); checkState(count == 1L, "failed to create QAsyncProcessFileResult: asyncId={0}, totalCount={1}, okCount={2}, ngCount={3}", asyncId, result.getTotalCount(), result.getOkCount(), result.getNgCount()); final QAsyncProcessFileResultDetail b = new QAsyncProcessFileResultDetail("b"); List<FileRecordInfo> list = (result.getNgRecordInfoList() == null ? new ArrayList<FileRecordInfo>() : result.getNgRecordInfoList()); for (final FileRecordInfo r : list) { if (r.isOk()) { continue; } long c = queryDslJdbcOperations.insert(b, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(b.asyncId, asyncId); insert.set(b.recordNumber, r.getNumber()); insert.set(b.description, adjustSize(r.getDescription(), b.description)); return insert.execute(); } }); checkState(c == 1L, "failed to create QAsyncProcessFileResultDetail: asyncId={0}, recordNumber={1}, description={2}", asyncId, r.getNumber(), r.getDescription()); } } @Transactional(propagation = REQUIRES_NEW) @Override public void finishCommand(final long asyncId, final LocalDateTime dtm, final AsyncStatus status, final CommandResult result) { finishAsyncProcess(asyncId, dtm, status); final QAsyncProcessCommandResult a = new QAsyncProcessCommandResult("a"); long count = queryDslJdbcOperations.insert(a, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(a.asyncId, asyncId); insert.set(a.exitValue, result.getExitValue()); insert.set(a.stdout, adjustSize(result.getStdout(), a.stdout)); insert.set(a.stderr, adjustSize(result.getStderr(), a.stderr)); return insert.execute(); } }); checkState(count == 1L, "failed to create QAsyncProcessCommandResult: asyncId={0}, exitValue={1}, stdout={2}, stderr={3}", asyncId, result.getExitValue(), result.getStdout(), result.getStderr()); } @Transactional(propagation = REQUIRES_NEW) @Override public void finishWithException(final long asyncId, final LocalDateTime dtm, final Throwable th) { finishAsyncProcess(asyncId, dtm, AsyncStatus.EXCEPTION); final QAsyncProcessException a = new QAsyncProcessException("a"); long count = queryDslJdbcOperations.insert(a, new SqlInsertCallback() { @Override public long doInSqlInsertClause(SQLInsertClause insert) { insert.set(a.asyncId, asyncId); insert.set(a.exception, adjustSize(throwableToString(th), a.exception)); return insert.execute(); } }); checkState(count == 1L, "failed to create QAsyncProcessException: asyncId={0}, exception={1}", asyncId, th.getMessage()); } private long createAsyncProcess(final String launcherId, final String description, final AsyncType asyncType, final LocalDateTime dtm) { final QAsyncProcess a = new QAsyncProcess("a"); SqlInsertWithKeyCallback<Long> callback = new SqlInsertWithKeyCallback<Long>() { @Override public Long doInSqlInsertWithKeyClause(SQLInsertClause insert) { insert.set(a.launchedBy, launcherId); insert.set(a.description, adjustSize(description, a.description)); insert.set(a.asyncType, asyncType.code()); insert.set(a.asyncStatus, AsyncStatus.LAUNCHING.code()); insert.set(a.registeredAt, dtm); return insert.executeWithKey(Long.class); } }; Long id = queryDslJdbcOperations.insertWithKey(a, callback); checkState(id != null, "failed to create QAsyncProcess: launchedBy={0}, description={1}, asyncType={2}, asyncStatus={3}, registeredAt={4}", launcherId, description, asyncType.code(), AsyncStatus.LAUNCHING.code(), dtm); return id.longValue(); } private void finishAsyncProcess(final long asyncId, final LocalDateTime dtm, final AsyncStatus status) { final QAsyncProcess a = new QAsyncProcess("a"); long count = queryDslJdbcOperations.update(a, new SqlUpdateCallback() { @Override public long doInSqlUpdateClause(SQLUpdateClause update) { update.set(a.asyncStatus, status.code()); update.set(a.finishedAt, dtm); update.set(a.updatedAt, currentTimestamp(LocalDateTime.class)); update.set(a.lockVersion, a.lockVersion.add(1)); update.where(a.id.eq(asyncId)); update.where(a.deletedFlg.eq(DeletedFlag.NOT_DELETED.code())); return update.execute(); } }); checkState(count == 1L, "failed to update QAsyncProcess: id={0}, asyncStatus={1}, finishedAt={2}, count={3}", asyncId, status.code(), dtm, count); } private String throwableToString(Throwable th) { try { Map<String, Object> map = ToMapUtil.fromThrowable(th, Integer.MAX_VALUE); return objectMapper.writeValueAsString(map); } catch (JsonProcessingException ex) { throw new IllegalStateException(); } } }