/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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.asakusafw.windgate.core;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.asakusafw.runtime.core.context.RuntimeContext;
import com.asakusafw.runtime.core.context.SimulationSupport;
import com.asakusafw.windgate.core.resource.ResourceProfile;
import com.asakusafw.windgate.core.resource.ResourceProvider;
import com.asakusafw.windgate.core.session.SessionException;
import com.asakusafw.windgate.core.session.SessionException.Reason;
import com.asakusafw.windgate.core.session.SessionMirror;
import com.asakusafw.windgate.core.session.SessionProfile;
import com.asakusafw.windgate.core.session.SessionProvider;
import com.asakusafw.windgate.core.util.SafeCloser;
/**
* Aborts a session or sessions.
* @since 0.2.2
*/
@SimulationSupport
public class AbortTask {
static final WindGateLogger WGLOG = new WindGateCoreLogger(AbortTask.class);
static final Logger LOG = LoggerFactory.getLogger(AbortTask.class);
final GateProfile profile;
private final String sessionId;
private final SessionProvider sessionProvider;
private final Map<String, ResourceProvider> resourceProviders;
/**
* Creates a new instance.
* @param profile the target profile
* @param sessionId the target session ID to abort, or {@code null} if aborts all sessions
* @throws IOException if failed to initialize the task
* @throws IllegalArgumentException if any parameter is {@code null}
*/
public AbortTask(GateProfile profile, String sessionId) throws IOException {
if (profile == null) {
throw new IllegalArgumentException("profile must not be null"); //$NON-NLS-1$
}
this.profile = profile;
this.sessionId = sessionId;
this.sessionProvider = loadSessionProvider(profile.getSession());
this.resourceProviders = loadResourceProviders(profile.getResources());
}
private SessionProvider loadSessionProvider(SessionProfile session) throws IOException {
assert session != null;
LOG.debug("Loading session provider: {}",
session.getProviderClass().getName());
SessionProvider result = session.createProvider();
return result;
}
private Map<String, ResourceProvider> loadResourceProviders(
List<ResourceProfile> resources) throws IOException {
assert resources != null;
Map<String, ResourceProvider> results = new TreeMap<>();
for (ResourceProfile resourceProfile : resources) {
LOG.debug("Loading resource provider \"{}\": {}",
resourceProfile.getName(),
resourceProfile.getProviderClass().getName());
ResourceProvider provider = resourceProfile.createProvider();
results.put(resourceProfile.getName(), provider);
}
return results;
}
/**
* Executes WindGate process.
* @throws IOException if failed
* @throws InterruptedException if interrupted
*/
public void execute() throws IOException, InterruptedException {
WGLOG.info("I01000",
sessionId,
profile.getName());
long start = System.currentTimeMillis();
try {
if (sessionId != null) {
doAbortSingle(sessionId);
} else {
int failureCount = 0;
List<String> sessionIds;
if (RuntimeContext.get().canExecute(sessionProvider)) {
sessionIds = sessionProvider.getCreatedIds();
} else {
sessionIds = Collections.emptyList();
}
for (String sid : sessionIds) {
try {
doAbortSingle(sid);
} catch (IOException e) {
failureCount++;
WGLOG.warn(e, "W01001",
sid,
profile.getName());
}
}
if (failureCount > 0) {
throw new IOException("Failed to abort some sessions");
}
}
WGLOG.info("I01005",
sessionId,
profile.getName());
} finally {
long end = System.currentTimeMillis();
WGLOG.info("I01999",
sessionId,
profile.getName(),
end - start);
}
}
private boolean doAbortSingle(String targetSessionId) throws IOException {
assert targetSessionId != null;
try (SafeCloser<SessionMirror> session = new SafeCloser<SessionMirror>() {
@Override
protected void handle(IOException exception) throws IOException {
WGLOG.warn(exception, "W01003",
targetSessionId,
profile.getName());
}
}) {
WGLOG.info("I01001",
targetSessionId,
profile.getName());
boolean executable = RuntimeContext.get().canExecute(sessionProvider);
if (executable) {
session.set(sessionProvider.open(targetSessionId));
} else {
session.set(new SessionMirror.Null(targetSessionId));
}
WGLOG.info("I01003",
targetSessionId,
profile.getName());
int failureCount = 0;
for (Map.Entry<String, ResourceProvider> entry : resourceProviders.entrySet()) {
String name = entry.getKey();
ResourceProvider provider = entry.getValue();
LOG.debug("Attempting to abort resource {} (session={})",
name,
targetSessionId);
try {
if (RuntimeContext.get().isSimulation() == false) {
provider.abort(session.get().getId());
}
} catch (IOException e) {
failureCount++;
WGLOG.warn(e, "W01002",
targetSessionId,
profile.getName(),
name);
}
}
if (failureCount > 0) {
throw new IOException(MessageFormat.format(
"Failed to abort some resources for the session \"{0}\"",
targetSessionId));
}
WGLOG.info("I01004",
targetSessionId,
profile.getName());
session.get().abort();
return true;
} catch (SessionException e) {
if (e.getReason() == Reason.NOT_EXIST) {
WGLOG.info("I01002",
targetSessionId,
profile.getName());
return false;
}
throw e;
}
}
}