blob: 9d8caf663526b892fa4cfccebb188edfe85debc6 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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.android.jack.server.tasks;
import com.android.jack.api.JackProvider;
import com.android.jack.server.JackHttpServer;
import com.android.jack.server.JackHttpServer.Program;
import com.android.jack.server.NoSuchVersionException;
import com.android.jack.server.type.ExactCodeVersionFinder;
import com.android.sched.util.SubReleaseKind;
import com.android.sched.util.Version;
import com.android.sched.util.findbugs.SuppressFBWarnings;
import com.android.sched.util.stream.ByteStreamSucker;
import org.simpleframework.http.Part;
import org.simpleframework.http.Request;
import org.simpleframework.http.Response;
import org.simpleframework.http.Status;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
/**
* Administrative task: Install new Jack.
*/
public class InstallJack extends SynchronousAdministrativeTask {
@Nonnull
private static Logger logger = Logger.getLogger(InstallJack.class.getName());
public InstallJack(@Nonnull JackHttpServer jackServer) {
super(jackServer);
}
// The ClassLoader does not need privileged handling
@SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
@Override
protected void handle(long taskId, @Nonnull Request request, @Nonnull Response response) {
response.setContentLength(0);
String programName = request.getPath().getName();
Part jarPart = request.getPart("jar");
assert jarPart != null && jarPart.getContentType() != null
&& jarPart.getContentType().getType().equals("application/octet-stream");
Part forcePart = request.getPart("force");
assert forcePart != null;
InputStream jarIn = null;
FileOutputStream out = null;
File tmpJack = null;
File jackDir = new File(jackServer.getServerDir(), programName);
try {
boolean force = "true".equals(forcePart.getContent());
jarIn = jarPart.getInputStream();
tmpJack = File.createTempFile("jack.jar", ".tmp", jackDir);
out = new FileOutputStream(tmpJack);
new ByteStreamSucker(jarIn, out).suck();
out.close();
out = null;
URLClassLoader tmpLoader;
try {
tmpLoader = new URLClassLoader(new URL[] {tmpJack.toURI().toURL()},
this.getClass().getClassLoader());
} catch (MalformedURLException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
throw new AssertionError();
}
Version version = new Version("jack", tmpLoader);
if ((version.getSubReleaseCode() < 0
|| version.getSubReleaseKind() == SubReleaseKind.ENGINEERING)
&& !force) {
logger.log(Level.WARNING, "Refused to install jack version '" + version.getVerboseVersion()
+ "' without force request");
response.setStatus(Status.BAD_REQUEST);
return;
}
try {
Program<JackProvider> alreadyInstalled = jackServer.selectJack(
new ExactCodeVersionFinder(version.getReleaseCode(), version.getSubReleaseCode(),
SubReleaseKind.ENGINEERING));
if (alreadyInstalled.getVersion().getSubReleaseKind() != SubReleaseKind.ENGINEERING) {
logger.log(Level.INFO,
"Jack version " + version.getVerboseVersion() + " was already installed");
response.setStatus(Status.OK);
return;
} else {
logger.log(Level.INFO, "Overriding Jack " + version.getVerboseVersion()
+ " with newly uploaded jar of the same version");
}
} catch (NoSuchVersionException e) {
// expected
}
File newInstalledJack = File.createTempFile("jack-", ".jar", jackDir);
if (!tmpJack.renameTo(newInstalledJack)) {
logger.log(Level.SEVERE, "Failed to rename '" + tmpJack
+ "' to '" + newInstalledJack + "'");
if (!newInstalledJack.delete()) {
logger.log(Level.WARNING, "Failed to delete empty file '" + newInstalledJack + "'");
}
response.setStatus(Status.INTERNAL_SERVER_ERROR);
return;
}
jackServer.addInstalledJack(
new Program<JackProvider>(version, newInstalledJack, null));
} catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
response.setStatus(Status.INTERNAL_SERVER_ERROR);
return;
} finally {
if (jarIn != null) {
try {
jarIn.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Exception during close", e);
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Exception during close", e);
}
}
if (tmpJack != null) {
if (!tmpJack.delete()) {
if (tmpJack.exists()) {
logger.log(Level.SEVERE,
"Failed to delete temp file '" + tmpJack + "'");
}
}
}
}
response.setStatus(Status.OK);
}
}