/*******************************************************************************
* Copyright (c) 2013 Zend Technologies Ltd.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.zend.sdklib.application;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Random;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.bind.JAXBException;
import org.apache.commons.io.FileUtils;
import org.zend.sdklib.descriptor.pkg.Package;
import org.zend.sdklib.descriptor.pkg.Version;
import org.zend.sdklib.internal.application.ZendConnection;
import org.zend.sdklib.internal.project.ProjectResourcesWriter;
import org.zend.sdklib.internal.utils.JaxbHelper;
import org.zend.sdklib.mapping.IMappingLoader;
import org.zend.sdklib.mapping.IVariableResolver;
import org.zend.sdklib.target.ITargetLoader;
import org.zend.webapi.core.WebApiClient;
import org.zend.webapi.core.WebApiException;
import org.zend.webapi.core.connection.data.ApplicationsList;
import org.zend.webapi.core.connection.data.LibraryList;
import org.zend.webapi.core.connection.request.NamedInputStream;
import org.zend.webapi.core.progress.BasicStatus;
import org.zend.webapi.core.progress.StatusCode;
/**
* Utility class which provides methods to perform operations on library.
*
* @author Wojciech Galanciak, 2013
*
*/
public class ZendLibrary extends ZendConnection {
public static final String TEMP_PREFIX = "ZendStudioDeployment";
private IVariableResolver variableResolver;
public ZendLibrary() {
super();
}
public ZendLibrary(IMappingLoader mappingLoader) {
super(mappingLoader);
}
public ZendLibrary(ITargetLoader loader) {
super(loader);
}
public ZendLibrary(ITargetLoader loader, IMappingLoader mappingLoader) {
super(loader, mappingLoader);
}
public void setVariableResolver(IVariableResolver variableResolver) {
this.variableResolver = variableResolver;
}
/**
* Provides status of specified library/libraries in selected target.
*
* @param targetId
* @param libaryId
* - array of library id(s) for which status should be checked
* @return instance of {@link ApplicationsList} or <code>null</code> if
* there where problems with connections or target with specified id
* does not exist
*/
public LibraryList getStatus(String targetId, String... libaryId) {
try {
WebApiClient client = getClient(targetId);
libaryId = libaryId == null ? new String[0] : libaryId;
notifier.statusChanged(new BasicStatus(StatusCode.STARTING,
"Library Status",
"Retrieving library status(es) from selected server...", -1));
LibraryList result = client.libraryGetStatus(libaryId);
notifier.statusChanged(new BasicStatus(StatusCode.STOPPING,
"Library Status",
"Library status(es) retrievied successfully. "));
return result;
} catch (MalformedURLException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR,
"Library Status",
"Error during retrieving library status from '" + targetId
+ "'", e));
log.error(e);
} catch (WebApiException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR,
"Library Status",
"Library during retrieving library status from '"
+ targetId + "'", e));
log.error("Error during retrieving library status from '"
+ targetId + "'.");
log.error("\tpossible error: " + e.getMessage());
}
return null;
}
public LibraryList deploy(String path, String configLocation, String targetId, boolean zpkPackage) {
if (path != null) {
File zendPackage = createPackage(path, configLocation);
try {
if (zendPackage != null) {
WebApiClient client = getClient(targetId);
notifier.statusChanged(new BasicStatus(StatusCode.STARTING, "Deploying",
"Deploying library to the server...", -1));
LibraryList result = client.libraryVersionDeploy(new NamedInputStream(zendPackage));
notifier.statusChanged(
new BasicStatus(StatusCode.STOPPING, "Deploying", "Library deployed successfully"));
return result;
}
} catch (MalformedURLException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR, "Deploying",
"Error during deploying library to '" + targetId + "'", e));
log.error(e);
} catch (WebApiException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR, "Deploying",
"Error during deploying library to '" + targetId + "'", e));
log.error("Error during deploying library to '" + targetId + "':");
log.error("\tpossible error: " + e.getMessage());
} finally {
if (zendPackage != null)
deleteDirectory(zendPackage.getParentFile());
}
return null;
}
return null;
}
public LibraryList deploy(String path, String targetId, boolean zpkPackage) {
return deploy(path, path, targetId, zpkPackage);
}
public LibraryList synchronize(String path, String configLocation, int id,
String targetId) {
if (path != null) {
File zendPackage = createPackage(path, configLocation);
try {
if (zendPackage != null) {
WebApiClient client = getClient(targetId);
notifier.statusChanged(new BasicStatus(StatusCode.STARTING,
"Synchronizing",
"Synchronizing library to the target...", -1));
LibraryList result = client.librarySynchronize(id,
new NamedInputStream(zendPackage));
notifier.statusChanged(new BasicStatus(StatusCode.STOPPING,
"Synchronizing",
"Library synchronized successfully"));
deleteFile(getTempFile(path));
return result;
}
} catch (MalformedURLException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR,
"Synchronizing",
"Error during synchronizing library to '" + targetId
+ "'", e));
log.error(e);
deleteFile(getTempFile(path));
} catch (WebApiException e) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR,
"Synchronizing",
"Error during synchronizing library to '" + targetId
+ "'", e));
log.error("Error during synchronizing library to '" + targetId
+ "':");
log.error("\tpossible error: " + e.getMessage());
}
return null;
}
return null;
}
public LibraryList synchronize(String path, int id, String targetId) {
return synchronize(path, path, id, targetId);
}
private File createPackage(String path, String configLocation) {
File file = new File(path);
if (!file.exists()) {
notifier.statusChanged(new BasicStatus(StatusCode.ERROR, "Deploying", "Path does not exist: " + file));
log.error("Path does not exist: " + file);
return null;
}
if (file.isDirectory()) {
File tempFile = getTempFile(path);
return getPackageBuilder(path, configLocation, variableResolver)
.createDeploymentPackage(tempFile);
} else if (file.getName().endsWith(".zip")) {
File tempUnzipped = null;
try {
tempUnzipped = unzip(file);
File tempFile = getTempFile("/" + new Random().nextInt());
return getPackageBuilder(tempUnzipped.getAbsolutePath(),
configLocation, variableResolver)
.createDeploymentPackage(tempFile);
} finally {
if (tempUnzipped != null) {
deleteDirectory(tempUnzipped);
}
}
} else if (file.getName().endsWith(".zpk")) {
File tempFile = null;
try {
tempFile = getTempFile("/" + new Random().nextInt());
FileUtils.copyFileToDirectory(file, tempFile);
return new File(tempFile, file.getName());
} catch (IOException e) {
String message = "Could not copy " + file.getAbsolutePath() + " to " + tempFile.getAbsolutePath();
notifier.statusChanged(new BasicStatus(StatusCode.ERROR, "Deploying", message));
log.error(message);
log.error("\tpossible error: " + e.getMessage());
}
return null;
}
return file;
}
public File unzip(File zipFile) {
byte[] buffer = new byte[4096];
try {
File folder = getTempFile("/" + new Random().nextInt());
ZipInputStream zipInput = new ZipInputStream(new FileInputStream(
zipFile));
ZipEntry entry = zipInput.getNextEntry();
while (entry != null) {
String fileName = entry.getName();
File newFile = new File(folder, fileName);
if (fileName.endsWith("/")) {
newFile.mkdirs();
} else {
new File(newFile.getParent()).mkdirs();
FileOutputStream out = new FileOutputStream(newFile);
int length = 0;
while ((length = zipInput.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
out.close();
}
entry = zipInput.getNextEntry();
}
zipInput.closeEntry();
zipInput.close();
return folder;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private String getDeploymentPackageName(File directory, File configLocation) {
if (directory == null || !directory.isDirectory()) {
log.error(new IllegalArgumentException(
"Location cannot be null or non-existing directory"));
return null;
}
configLocation = configLocation.getAbsoluteFile();
String name = getPackageName(configLocation);
if (name == null) {
return null;
}
return name + ".zpk";
}
private String getPackageName(File container) {
String result = null;
Package p = getPackage(container);
if (p != null) {
String name = p.getName();
final Version version2 = p.getVersion();
if (version2 == null) {
throw new IllegalStateException(
"Error, missing <version> element in deployment descriptor");
}
String version = version2.getRelease();
if (name != null && version != null) {
result = name + "-" + version;
}
}
return result;
}
private Package getPackage(File container) {
File descriptorFile = new File(container,
ProjectResourcesWriter.DESCRIPTOR);
if (!descriptorFile.exists()) {
log.error(descriptorFile.getAbsoluteFile() + " does not exist.");
return null;
}
FileInputStream pkgStream = null;
Package p = null;
try {
pkgStream = new FileInputStream(descriptorFile);
p = JaxbHelper.unmarshalPackage(pkgStream);
} catch (IOException e) {
throw new IllegalStateException(e);
} catch (JAXBException e) {
throw new IllegalStateException(e);
} finally {
try {
pkgStream.close();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return p;
}
private File getTempFile(String path) {
String tempDir = System.getProperty("java.io.tmpdir");
path = path.replace("\\", "/");
String suffix = path.substring(path.lastIndexOf("/") + 1);
File tempFile = new File(tempDir + File.separator + TEMP_PREFIX
+ suffix);
if (!tempFile.exists()) {
tempFile.mkdir();
}
return tempFile;
}
private boolean deleteFile(File file) {
if (file == null || !file.exists()) {
return true;
}
if (file.isDirectory()) {
String[] children = file.list();
for (int i = 0; i < children.length; i++) {
boolean result = deleteFile(new File(file, children[i]));
if (!result) {
return false;
}
}
}
return file.delete();
}
private void deleteDirectory(File dir) {
try {
FileUtils.deleteDirectory(dir);
} catch (IOException e) {
log.error("Could not delete folder: " + dir.getAbsolutePath());
log.error(e.getLocalizedMessage());
}
}
}