Java tutorial
/******************************************************************************* * Copyright (c) 2011 neXtep Software and contributors. * All rights reserved. * * This file is part of neXtep designer. * * NeXtep designer is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either * version 3 of the License, or any later version. * * NeXtep designer is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * neXtep Softwares - initial API and implementation *******************************************************************************/ package com.nextep.designer.repository.services.impl; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.nextep.datadesigner.exception.ErrorException; import com.nextep.designer.core.model.IConnection; import com.nextep.designer.repository.DeliveryRegistry; import com.nextep.designer.repository.RepositoryMessages; import com.nextep.designer.repository.RepositoryStatus; import com.nextep.designer.repository.exception.NoRepositoryConnectionException; import com.nextep.designer.repository.exception.NoRepositoryException; import com.nextep.designer.repository.services.IRepositoryUpdaterService; import com.nextep.installer.NextepInstaller; import com.nextep.installer.exception.InstallerException; import com.nextep.installer.factories.InstallerFactory; import com.nextep.installer.impl.req.DeliveryRequirement; import com.nextep.installer.impl.req.NextepAdminRequirement; import com.nextep.installer.impl.req.TargetUserRequirement; import com.nextep.installer.model.DBVendor; import com.nextep.installer.model.IDatabaseTarget; import com.nextep.installer.model.IInstallConfigurator; import com.nextep.installer.model.IInstallerMonitor; import com.nextep.installer.model.IRelease; import com.nextep.installer.model.IRequirement; import com.nextep.installer.model.InstallerOption; import com.nextep.installer.services.IAdminService; import com.nextep.installer.services.IConnectionService; import com.nextep.installer.services.IInstallerService; import com.nextep.installer.services.ILoggingService; /** * @author Christophe Fondacci * @author Bruno Gautier */ public class RepositoryUpdaterService implements IRepositoryUpdaterService { private static final Log LOGGER = LogFactory.getLog(RepositoryUpdaterService.class); private static final long DESIGNER_REPOSITORY_MODULE_ID = 100000000033l; private static final IRelease DESIGNER_REPOSITORY_VERSION = InstallerFactory.buildRelease(1, 0, 7, 4, 0); private IInstallerService installerService; private ILoggingService loggingService; private IAdminService adminService; private IConnectionService connectionService; /** * Returns the release number of the specified module in the specified repository. * * @param moduleId id of the module for which we need to retrieve the release number * @param repoConn a connection to the repository * @return a {@link IRelease} object representing the release number of the specified module */ public IRelease getRelease(long moduleId, IConnection repoConn) throws NoRepositoryConnectionException { // Defining target final String user = repoConn.getLogin(); final String password = repoConn.getPassword(); final String database = repoConn.getDatabase(); final String schema = repoConn.getSchema(); final String host = repoConn.getServerIP(); final String port = String.valueOf(repoConn.getServerPort()); final String serviceName = repoConn.getTnsAlias(); /* * We need to "translate" the com.nextep.designer.core.model.DBVendor enum value returned by * the IConnection#getDBVendor() method into a com.nextep.installer.model.DBVendor enum * value. */ final DBVendor vendor = DBVendor.valueOf(repoConn.getDBVendor().name()); IDatabaseTarget repoTarget = InstallerFactory.createTarget(user, password, database, schema, host, port, vendor, serviceName); // Building installer configurator IInstallConfigurator conf = InstallerFactory.createConfigurator(); conf.setTarget(repoTarget); conf.setAdminInTarget(true); try { Connection conn = connectionService.connect(repoTarget); try { IRelease currentRel = adminService.getRelease(conf, conn, moduleId, true); // Compatibility : assuming 1.0.2.7 if (currentRel == null) { currentRel = InstallerFactory.buildRelease(1, 0, 2, 7, 0); } return currentRel; } finally { conn.close(); } } catch (SQLException e) { LOGGER.error(e); throw new NoRepositoryConnectionException("Unable to connect to repository: " + e.getMessage(), e); } catch (InstallerException e) { LOGGER.error(e); return null; } } @Override public RepositoryStatus checkRepository(IConnection repoConn) throws NoRepositoryException, NoRepositoryConnectionException { IRelease currentRel = getRelease(DESIGNER_REPOSITORY_MODULE_ID, repoConn); if (currentRel == null) { throw new NoRepositoryException("No installed repository"); //$NON-NLS-1$ } else { final int comparisonResult = currentRel.compareTo(DESIGNER_REPOSITORY_VERSION); if (comparisonResult == 0) { return RepositoryStatus.OK; } else if (comparisonResult < 0) { return RepositoryStatus.REPOSITORY_TOO_OLD; } else { return RepositoryStatus.CLIENT_TOO_OLD; } } } @Override public void upgrade(final IInstallerMonitor monitor, final IConnection repoConn) { /* * We need to "translate" the com.nextep.designer.core.model.DBVendor enum value returned by * the IConnection#getDBVendor() method into a com.nextep.installer.model.DBVendor enum * value. */ final DBVendor vendor = DBVendor.valueOf(repoConn.getDBVendor().name()); final List<String> deliveries = DeliveryRegistry.listDeliveriesForUpgrade(null, null, vendor); monitor.mainStart(RepositoryMessages.getString("repositoryUpdater.title"), deliveries.size() * 2); //$NON-NLS-1$ loggingService.setMonitor(monitor); // Setting flag new Thread(new Runnable() { @Override public void run() { // Otherwise we enter a deadlock (Maybe a RCP bug within startup / splashscreen) // UISynchronizer.overrideThread.set(Boolean.TRUE); NextepInstaller.printLaunchHeader(); IInstallConfigurator configurator = InstallerFactory.createConfigurator(); try { // Preparing install configuration configurator.setOption(InstallerOption.USER, repoConn.getLogin()); configurator.setOption(InstallerOption.PASSWORD, repoConn.getPassword()); configurator.setOption(InstallerOption.DATABASE, repoConn.getDatabase()); configurator.setOption(InstallerOption.SCHEMA, repoConn.getSchema()); configurator.setOption(InstallerOption.HOST, repoConn.getServerIP()); configurator.setOption(InstallerOption.PORT, repoConn.getServerPort()); configurator.setOption(InstallerOption.TNS, repoConn.getTnsAlias()); configurator.setOption(InstallerOption.VENDOR, repoConn.getDBVendor().name()); configurator.defineOption(InstallerOption.FULL_INSTALL); List<IRequirement> requirements = new ArrayList<IRequirement>(); requirements.add(new TargetUserRequirement()); requirements.add(new NextepAdminRequirement()); installerService.checkRequirements(configurator, requirements); for (String dlv : deliveries) { submitDelivery(dlv, monitor, configurator); } // Full check adminService.checkAllForce(configurator, false); monitor.done(); // What to do on failure ? Maybe we should warn the user, // but we should let him // try to connect to repository... } catch (Throwable e) { LOGGER.error("Unexpected installer exception raised", e); monitor.log( RepositoryMessages.getString("repositoryUpdater.unexpectedException") + e.getMessage()); //$NON-NLS-1$ monitor.mainWork(RepositoryMessages.getString("repositoryUpdater.installationFailed")); //$NON-NLS-1$ monitor.done(); } finally { if (configurator != null) { try { installerService.release(configurator); } catch (InstallerException e) { LOGGER.error("Unable to release installator resources: " + e.getMessage(), e); } } } } }).start(); } @Override public void install(IInstallerMonitor monitor, IConnection repoConn) { upgrade(monitor, repoConn); } private void submitDelivery(String dlv, IInstallerMonitor monitor, IInstallConfigurator configurator) throws InstallerException { monitor.mainWork(RepositoryMessages.getString("repositoryUpdater.submittingDelivery") //$NON-NLS-1$ + dlv.substring(dlv.lastIndexOf('/') + 1) + "..."); //$NON-NLS-1$ try { String tempDlvLoc = createTempDelivery(dlv); List<IRequirement> req = new ArrayList<IRequirement>(); req.add(new DeliveryRequirement()); installerService.install(configurator, tempDlvLoc, req); } catch (RuntimeException e) { monitor.log(RepositoryMessages.getString("repositoryUpdater.unableToLoadDelivery") //$NON-NLS-1$ + dlv + RepositoryMessages.getString("repositoryUpdater.pleaseContactNextep")); //$NON-NLS-1$ LOGGER.error("Exception occurred", e); monitor.done(); throw e; } monitor.mainWork(RepositoryMessages.getString("repositoryUpdater.delivery") //$NON-NLS-1$ + dlv.substring(dlv.lastIndexOf('/') + 1) + RepositoryMessages.getString("repositoryUpdater.installed")); //$NON-NLS-1$ } /** * Creates the specified delivery (ZIP resource file) on the temporary directory of the local * file system. * * @param deliveryResource java resource zip file * @return a <code>String</code> representing the absolute path to the delivery root directory. */ private static String createTempDelivery(String deliveryResource) { InputStream is = RepositoryUpdaterService.class.getResourceAsStream(deliveryResource); if (is == null) { throw new ErrorException("Unable to load delivery file: " + deliveryResource); //$NON-NLS-1$ } final String exportLoc = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$ ZipInputStream zipInput = new ZipInputStream(is); ZipEntry entry = null; String rootDeliveryDir = null; try { while ((entry = zipInput.getNextEntry()) != null) { File targetFile = new File(exportLoc, entry.getName()); if (rootDeliveryDir == null) { /* * Initialize the delivery root directory value by searching recursively for the * shallowest directory in the path. */ rootDeliveryDir = getDeliveryRootPath(targetFile, new File(exportLoc)); } if (entry.isDirectory()) { targetFile.mkdirs(); } else { File targetDir = targetFile.getParentFile(); if (!targetDir.exists()) { /* * Creates the directory including any necessary but nonexistent parent * directories. */ targetDir.mkdirs(); } FileOutputStream outFile = new FileOutputStream(targetFile); copyStreams(zipInput, outFile); outFile.close(); } zipInput.closeEntry(); } } catch (IOException e) { throw new ErrorException(e); } finally { try { zipInput.close(); } catch (IOException e) { throw new ErrorException(e); } } return rootDeliveryDir; } /** * Recursively search for the directory whose parent is the specified export directory in the * absolute path of the specified archive file. If no such directory is found, return the parent * directory of the specified archive file. * * @param archiveFile the delivery file for which we need to find the delivery root directory * @param exportDir the directory in which the delivery is exported * @return the root path of the delivery */ private static String getDeliveryRootPath(File archiveFile, File exportDir) { String currPath = archiveFile.getParent(); File parent = archiveFile; while (parent != null && !parent.equals(exportDir)) { currPath = parent.getAbsolutePath(); parent = parent.getParentFile(); } return (parent == null ? archiveFile.getParent() : currPath); } private static void copyStreams(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[10240]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { out.write(buffer, 0, bytesRead); } } public void setInstallerService(IInstallerService installerService) { this.installerService = installerService; } public void setLoggingService(ILoggingService loggingService) { this.loggingService = loggingService; } public void setAdminService(IAdminService adminService) { this.adminService = adminService; } public void setConnectionService(IConnectionService connectionService) { this.connectionService = connectionService; } @Override public String createNeXtepAdminTempDelivery() { return createTempDelivery(DeliveryRegistry.ADMIN_DELIVERY); } }