001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.server.plugins; 021 022 import com.google.common.annotations.VisibleForTesting; 023 import com.google.common.base.Function; 024 import org.apache.commons.io.FileUtils; 025 import org.apache.commons.lang.StringUtils; 026 import org.slf4j.Logger; 027 import org.slf4j.LoggerFactory; 028 import org.sonar.api.platform.PluginMetadata; 029 import org.sonar.api.platform.PluginRepository; 030 import org.sonar.api.platform.ServerFileSystem; 031 import org.sonar.server.plugins.ClassLoaderUtils; 032 033 import javax.annotation.Nullable; 034 import java.io.File; 035 import java.io.IOException; 036 037 /** 038 * Ruby on Rails requires the files to be on filesystem but not in Java classpath (JAR). This component extracts 039 * all the needed files from plugins and copy them to $SONAR_HOME/temp 040 * 041 * @since 3.0 042 */ 043 public class ApplicationDeployer { 044 private static final Logger LOG = LoggerFactory.getLogger(ApplicationDeployer.class); 045 private static final String ROR_PATH = "org/sonar/ror/"; 046 047 private ServerFileSystem fileSystem; 048 private PluginRepository pluginRepository; 049 050 public ApplicationDeployer(ServerFileSystem fileSystem, PluginRepository pluginRepository) { 051 this.fileSystem = fileSystem; 052 this.pluginRepository = pluginRepository; 053 } 054 055 public void start() throws IOException { 056 deployRubyRailsApps(); 057 } 058 059 private void deployRubyRailsApps() { 060 LOG.info("Deploy Ruby on Rails applications"); 061 File appsDir = prepareRubyRailsRootDirectory(); 062 063 for (PluginMetadata pluginMetadata : pluginRepository.getMetadata()) { 064 String pluginKey = pluginMetadata.getKey(); 065 try { 066 deployRubyRailsApp(appsDir, pluginKey, pluginRepository.getPlugin(pluginKey).getClass().getClassLoader()); 067 } catch (Exception e) { 068 throw new IllegalStateException("Fail to deploy Ruby on Rails application: " + pluginKey, e); 069 } 070 } 071 } 072 073 @VisibleForTesting 074 File prepareRubyRailsRootDirectory() { 075 File appsDir = new File(fileSystem.getTempDir(), "ror"); 076 prepareDir(appsDir); 077 return appsDir; 078 } 079 080 @VisibleForTesting 081 static void deployRubyRailsApp(File appsDir, final String pluginKey, ClassLoader appClassLoader) { 082 if (hasRubyRailsApp(pluginKey, appClassLoader)) { 083 LOG.info("Deploy app: " + pluginKey); 084 File appDir = new File(appsDir, pluginKey); 085 ClassLoaderUtils.copyResources(appClassLoader, pathToRubyInitFile(pluginKey), appDir, new Function<String, String>() { 086 public String apply(@Nullable String relativePath) { 087 // Relocate the deployed files : 088 // relativePath format is: org/sonar/ror/sqale/app/controllers/foo_controller.rb 089 // app path is: org/sonar/ror/sqale 090 // -> deployed file is app/controllers/foo_controller.rb 091 return StringUtils.substringAfter(relativePath, pluginKey + "/"); 092 } 093 }); 094 } 095 } 096 097 private static String pathToRubyInitFile(String pluginKey) { 098 return ROR_PATH + pluginKey + "/init.rb"; 099 } 100 101 @VisibleForTesting 102 static boolean hasRubyRailsApp(String pluginKey, ClassLoader classLoader) { 103 return classLoader.getResource(pathToRubyInitFile(pluginKey)) != null; 104 105 } 106 107 private void prepareDir(File appsDir) { 108 if (appsDir.exists() && appsDir.isDirectory()) { 109 try { 110 FileUtils.deleteDirectory(appsDir); 111 } catch (IOException e) { 112 throw new IllegalStateException("Fail to delete temp directory: " + appsDir); 113 } 114 } 115 try { 116 FileUtils.forceMkdir(appsDir); 117 } catch (IOException e) { 118 throw new IllegalStateException("Fail to create temp directory: " + appsDir); 119 } 120 } 121 }