Java tutorial
package com.sap.prd.mobile.ios.mios; /* * #%L * Xcode Maven Plugin * %% * Copyright (C) 2012 SAP AG * %% * 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. * #L% */ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import org.apache.commons.io.IOUtils; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.sonatype.aether.transfer.TransferCancelledException; import org.sonatype.aether.transfer.TransferEvent; import org.sonatype.aether.transfer.TransferListener; /** * Registers a TransferListener on Aether that reacts on successful deployments. For each ipa file * deployed successfully a pointer file is written. This pointer file redirects to XXX * * * @goal pre-deploy * */ public class PreDeployMojo extends AbstractDeployMojo { /** * The folder used for hudson archiving * * @parameter expression="${archive.dir}" default-value="${project.build.directory}" */ private File archiveFolder; private final static String HTML_TEMPLATE = "<html><head><meta http-equiv=\"refresh\" content=\"0; URL=$LOCATION\">" + "<body>You will be redirected within the next few seconds.<br />" + "In case this does not work click <a href=\"$LOCATION\">here</a></body></html>"; /** * Returns the unique archive folder for this specific project (containing folders with groupId * and artifactId) * * @param rootArchiveFolder * @param project * @return */ static File getProjectArchiveFolder(File rootArchiveFolder, MavenProject project) { return new File(new File(new File(rootArchiveFolder, "artifacts"), project.getGroupId()), project.getArtifactId()); } @Override public void execute() throws MojoExecutionException, MojoFailureException { try { archiveFolder = archiveFolder.getCanonicalFile(); } catch (IOException ex) { throw new MojoExecutionException(ex.getMessage(), ex); } createArchiveFolder(archiveFolder); getLog().info("Using archive directory: '" + archiveFolder + "'."); try { // // [Q] Why do we use reflection here? What about a simple downcast to DefaultRepositorySystemSession? // [A] We cannot downcast since the downcast fails. The DefaultRepositorySystemSession that is available // here is loaded by another class loader than the DefaultRepositorySystemSession used by the actual class. // Hence we are in different runtime packages and the downcast is not possible. final TransferListener transferListener = getTransferListener(); final TransferListener prepareIpaPointerFileTransferListener = new PrepareIpaPointerFileTransferListener( transferListener); setTransferListener(prepareIpaPointerFileTransferListener); getLog().info("The previously used transfer listener was: '" + toString(transferListener) + "'."); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new MojoExecutionException( "Cannot set transfer listener for creating artifact redirect HTML files: " + e.getMessage(), e); } } private static void createArchiveFolder(File archiveFolder) throws MojoExecutionException { if (archiveFolder.isFile()) throw new MojoExecutionException( "Archive folder '" + archiveFolder + "' is a file rather than a directory."); if (!archiveFolder.exists() && !archiveFolder.mkdirs()) throw new MojoExecutionException("Cannot create archive folder '" + archiveFolder + "'."); } class PrepareIpaPointerFileTransferListener implements TransferListener { private TransferListener forward; PrepareIpaPointerFileTransferListener(TransferListener forward) { this.forward = forward; } TransferListener getForward() { return this.forward; } @Override public void transferSucceeded(TransferEvent event) { if (forward != null) forward.transferSucceeded(event); if (event.getRequestType().equals(TransferEvent.RequestType.GET)) return; if (event.getResource().getResourceName().endsWith("maven-metadata.xml")) { getLog().debug("No redirect html file will be created for '" + event.getResource().getResourceName() + "'."); return; } try { final String url = event.getResource().getRepositoryUrl() + event.getResource().getResourceName(); final String html = HTML_TEMPLATE.replaceAll("\\$LOCATION", url); final File projectArchiveFolder = getProjectArchiveFolder(archiveFolder, project); final File redirect = new File(projectArchiveFolder, getArtifactRedirectHtmlFileName(url)); writeArtifactRedirectHtmlFile(redirect, url, html); getLog().info("Redirect file '" + redirect + "' written for '" + url + "'."); } catch (RuntimeException ex) { getLog().error("Could not create artifact redirect HTML file for '" + event.getResource().getResourceName(), ex); } } @Override public void transferStarted(TransferEvent event) throws TransferCancelledException { if (forward != null) forward.transferStarted(event); } @Override public void transferProgressed(TransferEvent event) throws TransferCancelledException { if (forward != null) forward.transferProgressed(event); } @Override public void transferInitiated(TransferEvent event) throws TransferCancelledException { if (forward != null) forward.transferInitiated(event); } @Override public void transferFailed(TransferEvent event) { if (forward != null) forward.transferFailed(event); } @Override public void transferCorrupted(TransferEvent event) throws TransferCancelledException { if (forward != null) forward.transferCorrupted(event); } private void writeArtifactRedirectHtmlFile(final File redirect, final String url, final String html) { FileOutputStream fos = null; try { if (!redirect.getParentFile().exists() && !redirect.getParentFile().mkdirs()) throw new IOException("Cannot create folder '" + redirect.getParentFile() + "'."); fos = new FileOutputStream(redirect); IOUtils.write(html, fos, "UTF-8"); } catch (IOException ex) { throw new RuntimeException(ex); } finally { IOUtils.closeQuietly(fos); } } private String getArtifactRedirectHtmlFileName(final String url) { //E.g. MyApp-1.0.0-20120821.132955-1-Release-iphoneos-ota.htm String artifactFileName = url.substring(url.lastIndexOf("/") + 1); return getRedirectHtmlFilename(artifactFileName, project.getArtifactId()); } } static String getRedirectHtmlFilename(String artifactFileName, String artifactId) { String search = "-"; int nthElement = 0; if (artifactFileName.endsWith(XCodeOtaHtmlGeneratorMojo.OTA_CLASSIFIER_APPENDIX + "." + XCodeOtaHtmlGeneratorMojo.OTA_HTML_FILE_APPENDIX)) { nthElement = 3; } else if (artifactFileName.endsWith("-AppStoreMetaData.zip")) { nthElement = 1; } else if (artifactFileName.endsWith("-app.dSYM.zip")) { nthElement = 3; } else if (artifactFileName.endsWith("-app.zip")) { nthElement = 3; } else if (artifactFileName.endsWith(".ipa")) { nthElement = 2; } else if (artifactFileName.endsWith("versions.xml")) { nthElement = 1; } else if (artifactFileName.endsWith(".pom")) { nthElement = 1; search = "."; } else if (artifactFileName.endsWith("-fat-binary.a")) { nthElement = 3; } else if (artifactFileName.endsWith(".a")) { nthElement = 2; } else if (artifactFileName.endsWith(".headers.tar")) { nthElement = 2; } else if (artifactFileName.endsWith(".tar")) { nthElement = 1; search = "."; } int idx = getNthIndexFromBack(artifactFileName, search, nthElement); if (idx >= 0) { String name = artifactId + artifactFileName.substring(idx); if (!name.endsWith(".htm")) { name = name + ".htm"; } return name; } return artifactId + "-" + artifactFileName + ".htm"; } static int getNthIndexFromBack(String string, String searchString, int countFromBack) { if (countFromBack <= 0) return -1; int idx = string.length(); for (int i = 0; i < countFromBack; i++) { idx = string.substring(0, idx).lastIndexOf(searchString); if (idx <= 0) return idx; } return idx; } }