You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by cs...@apache.org on 2012/06/22 17:50:22 UTC
svn commit: r1352937 - in /karaf/trunk:
deployer/kar/src/main/java/org/apache/karaf/deployer/kar/
kar/command/src/main/java/org/apache/karaf/kar/command/
kar/command/src/main/java/org/apache/karaf/kar/command/completers/
kar/core/ kar/core/src/main/jav...
Author: cschneider
Date: Fri Jun 22 15:50:19 2012
New Revision: 1352937
URL: http://svn.apache.org/viewvc?rev=1352937&view=rev
Log:
KARAF-1551 Install kar repos into separate folders
Added:
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/FeatureDetector.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kar.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/MavenRepoManager.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/NoSubstProperties.java
karaf/trunk/kar/core/src/test/
karaf/trunk/kar/core/src/test/java/
karaf/trunk/kar/core/src/test/java/org/
karaf/trunk/kar/core/src/test/java/org/apache/
karaf/trunk/kar/core/src/test/java/org/apache/karaf/
karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/
karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/
karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/MavenRepoManagerTest.java
Modified:
karaf/trunk/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/KarArtifactInstaller.java
karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
karaf/trunk/kar/core/pom.xml
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarService.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarsMBean.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java
karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kars.java
karaf/trunk/kar/core/src/main/resources/OSGI-INF/blueprint/kar-core.xml
karaf/trunk/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
Modified: karaf/trunk/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/KarArtifactInstaller.java
URL: http://svn.apache.org/viewvc/karaf/trunk/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/KarArtifactInstaller.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/KarArtifactInstaller.java (original)
+++ karaf/trunk/deployer/kar/src/main/java/org/apache/karaf/deployer/kar/KarArtifactInstaller.java Fri Jun 22 15:50:19 2012
@@ -50,15 +50,22 @@ public class KarArtifactInstaller implem
}
public void uninstall(File file) throws Exception {
- LOGGER.info("Uninstalling KAR {}", file.getName());
- karService.uninstall(file.getName(), true);
+ String karName = getKarName(file);
+ LOGGER.info("Uninstalling KAR {}", karName);
+ karService.uninstall(karName);
}
public void update(File file) throws Exception {
LOGGER.warn("Karaf archive {}' has been updated; redeploying.", file);
- karService.uninstall(file.getName(), true);
+ karService.uninstall(getKarName(file));
karService.install(file.toURI());
}
+
+ private String getKarName(File karFile) {
+ String karName = karFile.getName();
+ karName = karName.substring(0, karName.lastIndexOf("."));
+ return karName;
+ }
public boolean canHandle(File file) {
// If the file ends with .kar, then we can handle it!
Modified: karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java (original)
+++ karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java Fri Jun 22 15:50:19 2012
@@ -18,7 +18,6 @@ package org.apache.karaf.kar.command;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
@Command(scope = "kar", name = "uninstall", description = "Uninstall a KAR file.")
public class UninstallKarCommand extends KarCommandSupport {
@@ -26,11 +25,8 @@ public class UninstallKarCommand extends
@Argument(index = 0, name = "name", description = "The name of the KAR file to uninstall.", required = true, multiValued = false)
private String name;
- @Option(name = "-c", aliases = { "--clean" }, description = "Uninstall features and cleanup the system repository from the KAR content", required = false, multiValued = false)
- private boolean clean = false;
-
public Object doExecute() throws Exception {
- this.getKarService().uninstall(name, clean);
+ this.getKarService().uninstall(name);
return null;
}
Modified: karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java (original)
+++ karaf/trunk/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java Fri Jun 22 15:50:19 2012
@@ -29,7 +29,7 @@ public class KarCompleter implements Com
private KarService karService;
- public int complete(String buffer, int cursor, List candidates) {
+ public int complete(String buffer, int cursor, @SuppressWarnings("rawtypes") List candidates) {
StringsCompleter delegate = new StringsCompleter();
try {
for (String karName : karService.list()) {
Modified: karaf/trunk/kar/core/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/pom.xml?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/pom.xml (original)
+++ karaf/trunk/kar/core/pom.xml Fri Jun 22 15:50:19 2012
@@ -39,6 +39,20 @@
<dependencies>
<dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
</dependency>
@@ -80,7 +94,8 @@
org.apache.karaf.kar
</Export-Package>
<Private-Package>
- org.apache.karaf.kar.internal
+ org.apache.karaf.kar.internal,
+ org.apache.felix.utils.properties
</Private-Package>
</instructions>
</configuration>
Modified: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarService.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarService.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarService.java (original)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarService.java Fri Jun 22 15:50:19 2012
@@ -16,6 +16,7 @@
*/
package org.apache.karaf.kar;
+import java.io.File;
import java.io.PrintStream;
import java.net.URI;
import java.util.List;
@@ -26,30 +27,35 @@ import java.util.List;
public interface KarService {
/**
- * Install KAR from a given URL.
+ * Install KAR from a given URI
+ *
+ * Resources will be copied to the karaf base dir
+ * Repository contents will be copied to a subdir in the
+ * karaf data directory
*
- * @param url the KAR URL.
+ * @param karUri Uri of the kar to be installed
* @throws Exception in case of installation failure.
*/
- void install(URI url) throws Exception;
-
+ void install(URI karUri) throws Exception;
+
/**
- * Uninstall the given KAR.
- * NB: the system folder is not cleaned.
- *
- * @param name the name of the KAR.
- * @throws Exception in case of uninstall failure.
+ * Install a kar with manually given repository and
+ * resource directories.
+ *
+ * @param karUri Uri of the kar to be installed
+ * @param repoDir destination for the repository contents of the kar
+ * @param resourceDir destination for the resource contents of the kar
+ * @throws Exception
*/
- void uninstall(String name) throws Exception;
+ void install(URI karUri, File repoDir, File resourceDir) throws Exception;
/**
- * Uninstall the given KAR and, eventually, cleanup the repository from the KAR content.
+ * Uninstall the given KAR
*
- * @param name the name of the KAR.
- * @param clean true to cleanup the repository folder, false else.
- * @throws Exception in case of uninstall failure.
+ * @param name the name of the KAR
+ * @throws Exception in case of failure
*/
- void uninstall(String name, boolean clean) throws Exception;
+ void uninstall(String name) throws Exception;
/**
* List the KAR stored in the data folder.
@@ -69,5 +75,6 @@ public interface KarService {
* @param console
*/
void create(String repoName, List<String> features, PrintStream console);
+
}
Modified: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarsMBean.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarsMBean.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarsMBean.java (original)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/KarsMBean.java Fri Jun 22 15:50:19 2012
@@ -44,13 +44,4 @@ public interface KarsMBean {
*/
void uninstall(String name) throws Exception;
- /**
- * Uninstall a KAR file and clean the system repository with the KAR content.
- *
- * @param name the KAR name.
- * @param clean true to cleanup the system repository, false else.
- * @throws Exception in case of uninstall failure.
- */
- void uninstall(String name, boolean clean) throws Exception;
-
}
Added: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/FeatureDetector.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/FeatureDetector.java?rev=1352937&view=auto
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/FeatureDetector.java (added)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/FeatureDetector.java Fri Jun 22 15:50:19 2012
@@ -0,0 +1,70 @@
+package org.apache.karaf.kar.internal;
+
+import java.io.File;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * Simple helper to determine if a file is a feature repo
+ *
+ */
+class FeatureDetector {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FeatureDetector.class);
+
+ private DocumentBuilderFactory dbf;
+
+ FeatureDetector() {
+ dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ }
+ /**
+ * Check if a file is a features XML.
+ *
+ * @param artifact the file to check.
+ * @return true if the artifact is a features XML, false else.
+ */
+ boolean isFeaturesRepository(File artifact) {
+ try {
+ if (artifact.isFile() && artifact.getName().endsWith(".xml")) {
+ Document doc = parse(artifact);
+ String name = doc.getDocumentElement().getLocalName();
+ String uri = doc.getDocumentElement().getNamespaceURI();
+ if ("features".equals(name) && (uri == null || "".equals(uri) || uri.startsWith("http://karaf.apache.org/xmlns/features/v"))) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ LOGGER.debug("File '{}' is not a features file.", artifact.getName(), e);
+ }
+ return false;
+ }
+
+ /**
+ * Parse a features XML.
+ *
+ * @param artifact the features XML to parse.
+ * @return the parsed document.
+ * @throws Exception in case of parsing failure.
+ */
+ private Document parse(File artifact) throws Exception {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ db.setErrorHandler(new ErrorHandler() {
+ public void warning(SAXParseException exception) throws SAXException {
+ }
+ public void error(SAXParseException exception) throws SAXException {
+ }
+ public void fatalError(SAXParseException exception) throws SAXException {
+ throw exception;
+ }
+ });
+ return db.parse(artifact);
+ }
+}
Added: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kar.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kar.java?rev=1352937&view=auto
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kar.java (added)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kar.java Fri Jun 22 15:50:19 2012
@@ -0,0 +1,189 @@
+package org.apache.karaf.kar.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Representation of a Karaf Kar archive
+ *
+ * A Kar archive is a jar file with a special structure that can be used
+ * to deploy feature repositories, maven repo contents and resources for the
+ * karaf installation.
+ *
+ * meta-inf/Manifest:
+ * Karaf-Feature-Start: (true|false) Controls if the features in the feature repos should be started on deploy
+ * Karaf-Feature-Repos: (uri)* If present then only the given feature repo urls are added to karaf if it is not
+ * present then the karaf file is scanned for repo files
+ *
+ * repository/
+ * Everything below this directory is treated as a maven repository. On deploy the contents
+ * will be copied to a directory below data. This directory will then be added to the
+ * maven repos of pax url maven
+ *
+ * resource/
+ * Everything below this directory will be copied to the karaf base dir on deploy
+ *
+ */
+public class Kar {
+ public static final Logger LOGGER = LoggerFactory.getLogger(KarServiceImpl.class);
+ public static final String MANIFEST_ATTR_KARAF_FEATURE_START = "Karaf-Feature-Start";
+ public static final String MANIFEST_ATTR_KARAF_FEATURE_REPOS = "Karaf-Feature-Repos";
+ private final URI karUri;
+ private boolean shouldInstallFeatures;
+ private List<URI> featureRepos;
+
+ public Kar(URI karUri) {
+ this.karUri = karUri;
+ }
+
+ /**
+ * Extract a kar from a given URI into a repository dir and resource dir
+ * and populate shouldInstallFeatures and featureRepos
+ *
+ * @param karUri uri to read the kar from
+ * @param repoDir directory to write the repository contents of the kar to
+ * @param resourceDir directory to write the resource contents of the kar to
+ */
+ public void extract(File repoDir, File resourceDir) {
+ InputStream is = null;
+ JarInputStream zipIs = null;
+ FeatureDetector featureDetector = new FeatureDetector();
+ this.featureRepos = new ArrayList<URI>();
+ this.shouldInstallFeatures = true;
+
+ try {
+ is = karUri.toURL().openStream();
+ repoDir.mkdirs();
+
+ if (!repoDir.isDirectory()) {
+ throw new RuntimeException("The KAR file " + karUri + " is already installed");
+ }
+
+ LOGGER.debug("Uncompress the KAR file {} into directory {}", karUri, repoDir);
+ zipIs = new JarInputStream(is);
+ boolean scanForRepos = true;
+
+ Manifest manifest = zipIs.getManifest();
+ if (manifest != null) {
+ Attributes attr = manifest.getMainAttributes();
+ String featureStartSt = (String)attr
+ .get(new Attributes.Name(MANIFEST_ATTR_KARAF_FEATURE_START));
+ if ("false".equals(featureStartSt)) {
+ shouldInstallFeatures = false;
+ }
+ String featureReposAttr = (String)attr
+ .get(new Attributes.Name(MANIFEST_ATTR_KARAF_FEATURE_REPOS));
+ if (featureReposAttr != null) {
+ featureRepos.add(new URI(featureReposAttr));
+ scanForRepos = false;
+ }
+ }
+
+ ZipEntry entry = zipIs.getNextEntry();
+ while (entry != null) {
+ if (entry.getName().startsWith("repository")) {
+ String path = entry.getName().substring("repository/".length());
+ File destFile = new File(repoDir, path);
+ extract(zipIs, entry, destFile);
+ if (scanForRepos && featureDetector.isFeaturesRepository(destFile)) {
+ featureRepos.add(destFile.toURI());
+ }
+ }
+
+ if (entry.getName().startsWith("resource")) {
+ String path = entry.getName().substring("resource/".length());
+ File destFile = new File(resourceDir, path);
+ extract(zipIs, entry, destFile);
+ }
+ entry = zipIs.getNextEntry();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Error extracting kar file " + karUri + " into dir " + repoDir + ": " + e.getMessage(), e);
+ } finally {
+ closeStream(zipIs);
+ closeStream(is);
+ }
+ }
+
+ /**
+ * Extract an entry from a KAR file
+ *
+ * @param is
+ * @param zipEntry
+ * @param dest
+ * @return
+ * @throws Exception
+ */
+ private static File extract(InputStream is, ZipEntry zipEntry, File dest) throws Exception {
+ if (zipEntry.isDirectory()) {
+ LOGGER.debug("Creating directory {}", dest.getName());
+ dest.mkdirs();
+ } else {
+ dest.getParentFile().mkdirs();
+ FileOutputStream out = new FileOutputStream(dest);
+ copyStream(is, out);
+ out.close();
+ }
+ return dest;
+ }
+
+ private static void closeStream(InputStream is) {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ LOGGER.warn("Error closing stream", e);
+ }
+ }
+ }
+
+ static long copyStream(InputStream input, OutputStream output) throws IOException {
+ byte[] buffer = new byte[10000];
+ long count = 0;
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ count += n;
+ }
+ return count;
+ }
+
+
+ public String getKarName() {
+ try {
+ String karName = new File(karUri.toURL().getFile()).getName();
+ karName = karName.substring(0, karName.lastIndexOf("."));
+ return karName;
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Invalid kar URI " + karUri, e);
+ }
+ }
+
+ public URI getKarUri() {
+ return karUri;
+ }
+
+ public boolean isShouldInstallFeatures() {
+ return shouldInstallFeatures;
+ }
+
+ public List<URI> getFeatureRepos() {
+ return featureRepos;
+ }
+
+
+}
Modified: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java (original)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/KarServiceImpl.java Fri Jun 22 15:50:19 2012
@@ -19,9 +19,11 @@
package org.apache.karaf.kar.internal;
import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -31,21 +33,14 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.EnumSet;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.karaf.features.BundleInfo;
import org.apache.karaf.features.ConfigFileInfo;
@@ -57,297 +52,139 @@ import org.apache.karaf.kar.KarService;
import org.ops4j.pax.url.mvn.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
/**
* Implementation of the KAR service.
*/
public class KarServiceImpl implements KarService {
+ private static final String FEATURE_CONFIG_FILE = "features.cfg";
+ private static final Logger LOGGER = LoggerFactory.getLogger(KarServiceImpl.class);
- private static final String MANIFEST_ATTR_KARAF_FEATURE_START = "Karaf-Feature-Start";
-
- public static final Logger LOGGER = LoggerFactory.getLogger(KarServiceImpl.class);
-
- private String storage = "./target/data/kar"; // ${KARAF.DATA}/kar
- private String base = "./";
- private String localRepo = "./target/local-repo"; // ${KARAF.BASE}/system
+ private File storage;
+ private File base;
private FeaturesService featuresService;
-
- private DocumentBuilderFactory dbf;
+ private final MavenRepoManager mavenRepoManager;
- /**
- * Init method.
- *
- * @throws Exception in case of init failure.
- */
- public void init() throws Exception {
- dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
-
- File karStorageDir = new File(storage);
- if (!karStorageDir.exists()) {
- LOGGER.debug("Create the KAR storage directory");
- karStorageDir.mkdirs();
- }
- if (!karStorageDir.isDirectory()) {
+ public KarServiceImpl(String karafBase, FeaturesService featuresService, MavenRepoManager mavenRepoManager) {
+ this.base = new File(karafBase);
+ this.storage = new File(this.base, "data" + File.separator + "kar");
+ this.featuresService = featuresService;
+ this.mavenRepoManager = mavenRepoManager;
+ this.storage.mkdirs();
+ if (!storage.isDirectory()) {
throw new IllegalStateException("KAR storage " + storage + " is not a directory");
}
}
- public void install(URI url) throws Exception {
- File file = new File(url.toURL().getFile());
- String karName = file.getName();
-
- LOGGER.debug("Installing KAR {} from {}", karName, url);
-
- LOGGER.debug("Check if the KAR file already exists in the storage directory");
- File karStorage = new File(storage);
- File karFile = new File(karStorage, karName);
-
- if (karFile.exists()) {
- LOGGER.warn("The KAR file " + karName + " is already installed. Override it.");
- }
-
- LOGGER.debug("Copy the KAR file from {} to {}", url, karFile.getParent());
- copy(url, karFile);
-
- LOGGER.debug("Uncompress the KAR file {} into the system repository", karName);
- ZipFile zipFile = new ZipFile(karFile);
-
- List<URI> featuresRepositoriesInKar = new ArrayList<URI>();
- boolean shouldInstallFeatures = true;
-
- @SuppressWarnings("unchecked")
- Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
-
- String repoEntryName = getRepoEntryName(entry);
-
- if (repoEntryName != null) {
- File extract = extract(zipFile, entry, repoEntryName, localRepo);
- if (isFeaturesRepository(extract)) {
- addToFeaturesRepositories(extract.toURI());
- featuresRepositoriesInKar.add(extract.toURI());
- }
- }
-
- if ("meta-inf/manifest.mf".equals(entry.getName().toLowerCase())) {
- InputStream is = zipFile.getInputStream(entry);
- Manifest manifest = new Manifest(is);
- Attributes attr = manifest.getMainAttributes();
- String featureStartSt = (String)attr.get(new Attributes.Name(MANIFEST_ATTR_KARAF_FEATURE_START));
- if ("false".equals(featureStartSt)) {
- shouldInstallFeatures = false;
- }
- is.close();
- }
-
- if (entry.getName().startsWith("resource")) {
- String resourceEntryName = entry.getName().substring("resource/".length());
- extract(zipFile, entry, resourceEntryName, base);
- }
+ @Override
+ public void install(URI karUri) throws Exception {
+ String karName = new Kar(karUri).getKarName();
+ LOGGER.debug("Installing KAR {} from {}", karName, karUri);
+ File karDir = new File(storage, karName);
+ install(karUri, karDir, base);
+ }
+
+ @Override
+ public void install(URI karUri, File repoDir, File resourceDir) throws Exception {
+ Kar kar = new Kar(karUri);
+ kar.extract(repoDir, resourceDir);
+ writeToFile(kar.getFeatureRepos(), new File(repoDir, FEATURE_CONFIG_FILE));
+ for (URI uri : kar.getFeatureRepos()) {
+ addToFeaturesRepositories(uri);
}
-
- if (shouldInstallFeatures) {
- installFeatures(featuresRepositoriesInKar);
+ if (kar.isShouldInstallFeatures()) {
+ installFeatures(kar.getFeatureRepos());
}
-
- zipFile.close();
- }
- public void uninstall(String karName) throws Exception {
- uninstall(karName, false);
+ if (mavenRepoManager != null) {
+ mavenRepoManager.addRepo(repoDir.toURI());
+ }
}
- public void uninstall(String karName, boolean clean) throws Exception {
- File karStorage = new File(storage);
- File karFile = new File(karStorage, karName);
-
- if (!karFile.exists()) {
- throw new IllegalArgumentException("The KAR " + karName + " is not installed");
- }
- if (clean) {
- LOGGER.debug("Looking for KAR entries to purge the local repository");
- List<URI> featuresRepositories = new ArrayList<URI>();
- ZipFile zipFile = new ZipFile(karFile);
- @SuppressWarnings("unchecked")
- Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zipFile.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- String repoEntryName = getRepoEntryName(entry);
- if (repoEntryName != null) {
- File toDelete = new File(localRepo + File.separator + repoEntryName);
- if (isFeaturesRepository(toDelete)) {
- featuresRepositories.add(toDelete.toURI());
- } else {
- if (toDelete.isFile() && toDelete.exists()) {
- toDelete.delete();
- }
- }
- }
- if (entry.getName().startsWith("resource")) {
- String resourceEntryName = entry.getName().substring("resource/".length());
- File toDelete = new File(base + File.separator + resourceEntryName);
- if (toDelete.isFile() && toDelete.exists()) {
- toDelete.delete();
- }
- }
+ private List<URI> readFromFile(File repoListFile) {
+ ArrayList<URI> uriList = new ArrayList<URI>();
+ FileReader fr = null;
+ try {
+ fr = new FileReader(repoListFile);
+ BufferedReader br = new BufferedReader(fr);
+ String line;
+ while ((line = br.readLine()) != null) {
+ uriList.add(new URI(line));
}
- zipFile.close();
-
- uninstallFeatures(featuresRepositories);
- for (URI featuresRepository : featuresRepositories) {
- featuresService.removeRepository(featuresRepository);
- File toDelete = new File(featuresRepository);
- if (toDelete.exists() && toDelete.isFile()) {
- toDelete.delete();
- }
+ } catch (Exception e) {
+ throw new RuntimeException("Error reading repo list from file " + repoListFile.getAbsolutePath(), e);
+ } finally {
+ try {
+ fr.close();
+ } catch (IOException e) {
+ LOGGER.warn("Error closing reader for file " + repoListFile, e);
}
}
-
- karFile.delete();
+ return uriList;
}
- public List<String> list() throws Exception {
- File karStorage = new File(storage);
- List<String> kars = new ArrayList<String>();
- for (File kar : karStorage.listFiles()) {
- kars.add(kar.getName());
- }
- return kars;
- }
-
- /**
- * Create a destination file using a source URL.
- *
- * @param url the source URL.
- * @param file the destination file
- * @throws Exception in case of copy failure
- */
- private void copy(URI url, File file) throws Exception {
- InputStream is = null;
+ private void writeToFile(List<URI> featuresRepositoriesInKar, File repoListFile) {
FileOutputStream fos = null;
+ PrintStream ps = null;
try {
- is = url.toURL().openStream();
- fos = new FileOutputStream(file);
- copyStream(is, fos);
- } finally {
- if (is != null) {
- is.close();
- }
- if (fos != null) {
- fos.flush();
- fos.close();
+ fos = new FileOutputStream(repoListFile);
+ ps = new PrintStream(fos);
+ for (URI uri : featuresRepositoriesInKar) {
+ ps.println(uri);
}
+ ps.close();
+ fos.close();
+ } catch (Exception e) {
+ throw new RuntimeException("Error writing feature repo list to file " + repoListFile.getAbsolutePath(), e);
+ } finally {
+ closeStream(ps);
+ closeStream(fos);
}
}
- /**
- * Get the entry name filtering the repository folder.
- *
- * @param entry the "normal" entry name.
- * @return the entry with the repository folder filtered.
- */
- private String getRepoEntryName(ZipEntry entry) {
- String entryName = entry.getName();
- if (entryName.startsWith("repository")) {
- return entryName.substring("repository/".length());
- }
- if (entryName.startsWith("META-INF") || entryName.startsWith("resources")) {
- return null;
+ private void deleteRecursively(File dir) {
+ if (dir.isDirectory()) {
+ File[] children = dir.listFiles();
+ for (File child : children) {
+ deleteRecursively(child);
+ }
}
- return entryName;
+ dir.delete();
}
- /**
- * Extract an entry from a KAR file.
- *
- * @param zipFile the KAR file (zip file).
- * @param zipEntry the entry in the KAR file.
- * @param repoEntryName the target extract name.
- * @param base the base directory where to extract the file.
- * @return the extracted file.
- * @throws Exception in the extraction fails.
- */
- private File extract(ZipFile zipFile, ZipEntry zipEntry, String repoEntryName, String base) throws Exception {
- File extract;
- if (zipEntry.isDirectory()) {
- extract = new File(base + File.separator + repoEntryName);
- LOGGER.debug("Creating directory {}", extract.getName());
- extract.mkdirs();
- } else {
- extract = new File(base + File.separator + repoEntryName);
- extract.getParentFile().mkdirs();
-
- InputStream in = zipFile.getInputStream(zipEntry);
- FileOutputStream out = new FileOutputStream(extract);
-
- byte[] buffer = new byte[8192];
- int count = in.read(buffer);
- int totalBytes = 0;
-
- while (count >= 0) {
- out.write(buffer, 0, count);
- totalBytes += count;
- count = in.read(buffer);
- }
+ @Override
+ public void uninstall(String karName) throws Exception {
+ File karDir = new File(storage, karName);
- LOGGER.debug("Extracted {} bytes to {}", totalBytes, extract);
+ if (!karDir.exists()) {
+ throw new IllegalArgumentException("The KAR " + karName + " is not installed");
+ }
- in.close();
- out.flush();
- out.close();
+ List<URI> featuresRepositories = readFromFile(new File(karDir, FEATURE_CONFIG_FILE));
+ uninstallFeatures(featuresRepositories);
+ for (URI featuresRepository : featuresRepositories) {
+ featuresService.removeRepository(featuresRepository);
}
- return extract;
+
+ // Creating the URI before deleting the dir to get a "/" at the end
+ URI karURI = karDir.toURI();
+ mavenRepoManager.removeRepo(karURI);
+ deleteRecursively(karDir);
}
-
- /**
- * Check if a file is a features XML.
- *
- * @param artifact the file to check.
- * @return true if the artifact is a features XML, false else.
- */
- private boolean isFeaturesRepository(File artifact) {
- try {
- if (artifact.isFile() && artifact.getName().endsWith(".xml")) {
- Document doc = parse(artifact);
- String name = doc.getDocumentElement().getLocalName();
- String uri = doc.getDocumentElement().getNamespaceURI();
- if ("features".equals(name) && (uri == null || "".equals(uri) || uri.startsWith("http://karaf.apache.org/xmlns/features/v"))) {
- return true;
- }
+
+ @Override
+ public List<String> list() throws Exception {
+ List<String> kars = new ArrayList<String>();
+ for (File kar : storage.listFiles()) {
+ if (kar.isDirectory()) {
+ kars.add(kar.getName());
}
- } catch (Exception e) {
- LOGGER.debug("File '{}' is not a features file.", artifact.getName(), e);
}
- return false;
+ return kars;
}
- /**
- * Parse a features XML.
- *
- * @param artifact the features XML to parse.
- * @return the parsed document.
- * @throws Exception in case of parsing failure.
- */
- private Document parse(File artifact) throws Exception {
- DocumentBuilder db = dbf.newDocumentBuilder();
- db.setErrorHandler(new ErrorHandler() {
- public void warning(SAXParseException exception) throws SAXException {
- }
- public void error(SAXParseException exception) throws SAXException {
- }
- public void fatalError(SAXParseException exception) throws SAXException {
- throw exception;
- }
- });
- return db.parse(artifact);
- }
+
/**
* Add an URI to the list of features repositories.
@@ -403,7 +240,7 @@ public class KarServiceImpl implements K
File karFile = new File(karPath);
karFile.getParentFile().mkdirs();
fos = new FileOutputStream(karFile);
- Manifest manifest = createNonAutoStartManifest();
+ Manifest manifest = createNonAutoStartManifest(repo.getURI());
jos = new JarOutputStream(new BufferedOutputStream(fos, 100000), manifest);
Map<URI, Integer> locationMap = new HashMap<URI, Integer>();
@@ -459,9 +296,10 @@ public class KarServiceImpl implements K
return featureSet;
}
- private Manifest createNonAutoStartManifest() throws UnsupportedEncodingException, IOException {
+ private Manifest createNonAutoStartManifest(URI repoUri) throws UnsupportedEncodingException, IOException {
String manifestSt = "Manifest-Version: 1.0\n" +
- MANIFEST_ATTR_KARAF_FEATURE_START +": false\n";
+ Kar.MANIFEST_ATTR_KARAF_FEATURE_START +": false\n" +
+ Kar.MANIFEST_ATTR_KARAF_FEATURE_REPOS + ": " + repoUri.toString() + "\n";
InputStream manifestIs = new ByteArrayInputStream(manifestSt.getBytes("UTF-8"));
Manifest manifest = new Manifest(manifestIs);
return manifest;
@@ -499,25 +337,13 @@ public class KarServiceImpl implements K
InputStream is = location.toURL().openStream();
String path = "repository/" + parser.getArtifactPath();
jos.putNextEntry(new JarEntry(path));
- copyStream(is, jos);
+ Kar.copyStream(is, jos);
is.close();
locationMap.put(location, 1);
} catch (Exception e) {
LOGGER.error("Error adding " + location, e);
}
}
-
- public static long copyStream(InputStream input, OutputStream output)
- throws IOException {
- byte[] buffer = new byte[10000];
- long count = 0;
- int n = 0;
- while (-1 != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- count += n;
- }
- return count;
- }
/**
* Uninstall all features contained in the list of features XML.
@@ -544,20 +370,4 @@ public class KarServiceImpl implements K
}
}
- public void setFeaturesService(FeaturesService featuresService) {
- this.featuresService = featuresService;
- }
-
- public void setStorage(String storage) {
- this.storage = storage;
- }
-
- public void setBase(String base) {
- this.base = base;
- }
-
- public void setLocalRepo(String localRepo) {
- this.localRepo = localRepo;
- }
-
}
Modified: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kars.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kars.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kars.java (original)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/Kars.java Fri Jun 22 15:50:19 2012
@@ -43,10 +43,6 @@ public class Kars extends StandardMBean
public void uninstall(String name) throws Exception {
karService.uninstall(name);
}
-
- public void uninstall(String name, boolean clean) throws Exception {
- karService.uninstall(name, clean);
- }
public KarService getKarService() {
return karService;
Added: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/MavenRepoManager.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/MavenRepoManager.java?rev=1352937&view=auto
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/MavenRepoManager.java (added)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/MavenRepoManager.java Fri Jun 22 15:50:19 2012
@@ -0,0 +1,76 @@
+package org.apache.karaf.kar.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Allows to add or delete repo URIs from the pax url mvn config
+ */
+public class MavenRepoManager {
+
+ static final String ATTR_REPOS = "org.ops4j.pax.url.mvn.repositories";
+ static final String PAX_URL_MVN_CONFIG_PID = "org.ops4j.pax.url.mvn";
+ private final File configFile;
+
+ public MavenRepoManager(String karafBase) {
+ File etcFile = new File(karafBase, "etc");
+ configFile = new File(etcFile, PAX_URL_MVN_CONFIG_PID + ".cfg");
+ if (!configFile.exists() && configFile.isFile()) {
+ throw new RuntimeException("Cannot find config " + configFile);
+ }
+ }
+
+ public void addRepo(URI repo) throws IOException {
+ NoSubstProperties props = new NoSubstProperties(configFile);
+ List<String> repos = getRepos((String)props.get(ATTR_REPOS));
+ String repoSt = repo.toString();
+ if (!repos.contains(repoSt)) {
+ repos.add(repoSt);
+ }
+ props.put(ATTR_REPOS, getReposAttrValue(repos));
+ props.save();
+ }
+
+ public void removeRepo(URI repo) throws IOException {
+ NoSubstProperties props = new NoSubstProperties(configFile);
+ List<String> repos = getRepos((String)props.get(ATTR_REPOS));
+ List<String> outRepos = new ArrayList<String>();
+ String repoSt = repo.toString();
+ for (String currentRepo : repos) {
+ String temp = new String(currentRepo);
+ if (!repoSt.equals(temp)) {
+ outRepos.add(currentRepo);
+ }
+ }
+ props.put(ATTR_REPOS, getReposAttrValue(outRepos));
+ props.save();
+ }
+
+ List<String> getRepos(String repos) throws IOException {
+ repos = repos.replaceAll("\\s*\\\\\\r?\\n", "");
+ String[] origRepoAr = repos.split("\\s*,\\s*\\\\?");
+ List<String> repoList = new ArrayList<String>();
+ for (String repo : origRepoAr) {
+ repo = repo.trim();
+ if (repo != null && !"".equals(repo)) {
+ repoList.add(repo);
+ }
+ }
+ return repoList;
+ }
+
+ String getReposAttrValue(List<String> repos) {
+ StringBuilder repoAttr = new StringBuilder();
+ repoAttr.append("\\\n");
+ for (int c=0; c<repos.size(); c++) {
+ repoAttr.append(repos.get(c));
+ if (c+1<repos.size()) {
+ repoAttr.append(", \\\n");
+ }
+ }
+ return repoAttr.toString();
+ }
+}
Added: karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/NoSubstProperties.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/NoSubstProperties.java?rev=1352937&view=auto
==============================================================================
--- karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/NoSubstProperties.java (added)
+++ karaf/trunk/kar/core/src/main/java/org/apache/karaf/kar/internal/NoSubstProperties.java Fri Jun 22 15:50:19 2012
@@ -0,0 +1,1041 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.karaf.kar.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * <p>
+ * Enhancement of the standard <code>Properties</code>
+ * managing the maintain of comments, etc.
+ * </p>
+ *
+ * @author gnodet, jbonofre
+ */
+public class NoSubstProperties extends AbstractMap<String, String> {
+
+ /** Constant for the supported comment characters.*/
+ private static final String COMMENT_CHARS = "#!";
+
+ /** The list of possible key/value separators */
+ private static final char[] SEPARATORS = new char[] {'=', ':'};
+
+ /** The white space characters used as key/value separators. */
+ private static final char[] WHITE_SPACE = new char[] {' ', '\t', '\f'};
+
+ /**
+ * The default encoding (ISO-8859-1 as specified by
+ * http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html)
+ */
+ private static final String DEFAULT_ENCODING = "ISO-8859-1";
+
+ /** Constant for the platform specific line separator.*/
+ private static final String LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("line.separator");
+ }
+ });
+
+ /** Constant for the radix of hex numbers.*/
+ private static final int HEX_RADIX = 16;
+
+ /** Constant for the length of a unicode literal.*/
+ private static final int UNICODE_LEN = 4;
+
+ private final Map<String,String> storage = new LinkedHashMap<String,String>();
+ private final Map<String,Layout> layout = new LinkedHashMap<String,Layout>();
+ private List<String> header;
+ private List<String> footer;
+ private File location;
+ private BundleContext context;
+
+ public NoSubstProperties() {
+ }
+
+ public NoSubstProperties(File location) throws IOException {
+ this(location, null);
+ }
+
+ public NoSubstProperties(File location, BundleContext context) throws IOException {
+ this.location = location;
+ this.context = context;
+ if(location.exists())
+ load(location);
+ }
+
+ public void load(File location) throws IOException {
+ InputStream is = new FileInputStream(location);
+ try {
+ load(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public void load(URL location) throws IOException {
+ InputStream is = location.openStream();
+ try {
+ load(is);
+ } finally {
+ is.close();
+ }
+ }
+
+ public void load(InputStream is) throws IOException {
+ load(new InputStreamReader(is, DEFAULT_ENCODING));
+ }
+
+ public void load(Reader reader) throws IOException {
+ loadLayout(reader);
+ }
+
+ public void save() throws IOException {
+ save(this.location);
+ }
+
+ public void save(File location) throws IOException {
+ OutputStream os = new FileOutputStream(location);
+ try {
+ save(os);
+ } finally {
+ os.close();
+ }
+ }
+
+ public void save(OutputStream os) throws IOException {
+ save(new OutputStreamWriter(os, DEFAULT_ENCODING));
+ }
+
+ public void save(Writer writer) throws IOException {
+ saveLayout(writer);
+ }
+
+ /**
+ * Store a properties into a output stream, preserving comments, special character, etc.
+ * This method is mainly to be compatible with the java.util.Properties class.
+ *
+ * @param os an output stream.
+ * @param comment this parameter is ignored as this Properties
+ * @throws IOException
+ */
+ public void store(OutputStream os, String comment) throws IOException {
+ this.save(os);
+ }
+
+ /**
+ * Searches for the property with the specified key in this property list.
+ *
+ * @param key the property key.
+ * @return the value in this property list with the specified key value.
+ */
+ public String getProperty(String key) {
+ return this.get(key);
+ }
+
+ /**
+ * Searches for the property with the specified key in this property list. If the key is not found in this property
+ * list, the default property list, and its defaults, recursively, are then checked. The method returns the default
+ * value argument if the property is not found.
+ *
+ * @param key the property key.
+ * @param defaultValue a default value.
+ * @return
+ */
+ public String getProperty(String key, String defaultValue) {
+ if (this.get(key) != null)
+ return this.get(key);
+ return defaultValue;
+ }
+
+ @Override
+ public Set<Entry<String, String>> entrySet() {
+ return storage.entrySet();
+ }
+
+ /**
+ * Returns an enumeration of all the keys in this property list, including distinct keys in the default property
+ * list if a key of the same name has not already been found from the main properties list.
+ *
+ * @return an enumeration of all the keys in this property list, including the keys in the default property list.
+ */
+ public Enumeration<?> propertyNames() {
+ return Collections.enumeration(storage.keySet());
+ }
+
+ /**
+ * Calls the map method put. Provided for parallelism with the getProperty method.
+ * Enforces use of strings for property keys and values. The value returned is the result of the map call to put.
+ *
+ * @param key the key to be placed into this property list.
+ * @param value the value corresponding to the key.
+ * @return the previous value of the specified key in this property list, or null if it did not have one.
+ */
+ public Object setProperty(String key, String value) {
+ return this.put(key, value);
+ }
+
+ @Override
+ public String put(String key, String value) {
+ String old = storage.put(key, value);
+ if (old == null || !old.equals(value)) {
+ Layout l = layout.get(key);
+ if (l != null) {
+ l.clearValue();
+ }
+ }
+ return old;
+ }
+
+ public String put(String key, List<String> commentLines, List<String> valueLines) {
+ commentLines = new ArrayList<String>(commentLines);
+ valueLines = new ArrayList<String>(valueLines);
+ String escapedKey = escapeKey(key);
+ int lastLine = valueLines.size() - 1;
+ if (valueLines.isEmpty()) {
+ valueLines.add(escapedKey + "=");
+ } else if (!valueLines.get(0).trim().startsWith(escapedKey)) {
+ valueLines.set(0, escapedKey + " = " + escapeJava(valueLines.get(0)) + (0 < lastLine? "\\": ""));
+ }
+ for (int i = 1; i < valueLines.size(); i++) {
+ valueLines.set(i, escapeJava(valueLines.get(i)) + (i < lastLine? "\\": ""));
+ }
+ StringBuilder value = new StringBuilder();
+ for (String line: valueLines) {
+ value.append(line);
+ }
+ this.layout.put(key, new Layout(commentLines, valueLines));
+ return storage.put(key, unescapeJava(value.toString()));
+ }
+
+ public String put(String key, List<String> commentLines, String value) {
+ commentLines = new ArrayList<String>(commentLines);
+ this.layout.put(key, new Layout(commentLines, null));
+ return storage.put(key, value);
+ }
+
+ public String put(String key, String comment, String value) {
+ return put(key, Collections.singletonList(comment), value);
+ }
+
+ public List<String> getRaw(String key) {
+ if (layout.containsKey(key)) {
+ if (layout.get(key).getValueLines() != null) {
+ return new ArrayList<String>(layout.get(key).getValueLines());
+ }
+ }
+ List<String> result = new ArrayList<String>();
+ if (storage.containsKey(key)) {
+ result.add(storage.get(key));
+ }
+ return result;
+ }
+
+ @Override
+ public String remove(Object key) {
+ Layout l = layout.get(key);
+ if (l != null) {
+ l.clearValue();
+ }
+ return storage.remove(key);
+ }
+
+ @Override
+ public void clear() {
+ for (Layout l : layout.values()) {
+ l.clearValue();
+ }
+ storage.clear();
+ }
+
+ /**
+ * Return the comment header.
+ *
+ * @return the comment header
+ */
+ public List<String> getHeader()
+ {
+ return header;
+ }
+
+ /**
+ * Set the comment header.
+ *
+ * @param header the header to use
+ */
+ public void setHeader(List<String> header)
+ {
+ this.header = header;
+ }
+
+ /**
+ * Return the comment footer.
+ *
+ * @return the comment footer
+ */
+ public List<String> getFooter()
+ {
+ return footer;
+ }
+
+ /**
+ * Set the comment footer.
+ *
+ * @param footer the footer to use
+ */
+ public void setFooter(List<String> footer)
+ {
+ this.footer = footer;
+ }
+
+ /**
+ * Reads a properties file and stores its internal structure. The found
+ * properties will be added to the associated configuration object.
+ *
+ * @param in the reader to the properties file
+ * @throws java.io.IOException if an error occurs
+ */
+ protected void loadLayout(Reader in) throws IOException
+ {
+ PropertiesReader reader = new PropertiesReader(in);
+ while (reader.nextProperty())
+ {
+ storage.put(reader.getPropertyName(), reader.getPropertyValue());
+ int idx = checkHeaderComment(reader.getCommentLines());
+ layout.put(reader.getPropertyName(),
+ new Layout(idx < reader.getCommentLines().size() ?
+ new ArrayList<String>(reader.getCommentLines().subList(idx, reader.getCommentLines().size())) :
+ null,
+ new ArrayList<String>(reader.getValueLines())));
+ }
+ footer = new ArrayList<String>(reader.getCommentLines());
+ }
+
+ /**
+ * Writes the properties file to the given writer, preserving as much of its
+ * structure as possible.
+ *
+ * @param out the writer
+ * @throws java.io.IOException if an error occurs
+ */
+ protected void saveLayout(Writer out) throws IOException
+ {
+ PropertiesWriter writer = new PropertiesWriter(out);
+ if (header != null)
+ {
+ for (String s : header)
+ {
+ writer.writeln(s);
+ }
+ }
+
+ for (String key : storage.keySet())
+ {
+ Layout l = layout.get(key);
+ if (l != null && l.getCommentLines() != null)
+ {
+ for (String s : l.getCommentLines())
+ {
+ writer.writeln(s);
+ }
+ }
+ if (l != null && l.getValueLines() != null)
+ {
+ for (String s : l.getValueLines())
+ {
+ writer.writeln(s);
+ }
+ }
+ else
+ {
+ writer.writeProperty(key, storage.get(key));
+ }
+ }
+ if (footer != null)
+ {
+ for (String s : footer)
+ {
+ writer.writeln(s);
+ }
+ }
+ writer.flush();
+ }
+
+ /**
+ * Checks if parts of the passed in comment can be used as header comment.
+ * This method checks whether a header comment can be defined (i.e. whether
+ * this is the first comment in the loaded file). If this is the case, it is
+ * searched for the lates blank line. This line will mark the end of the
+ * header comment. The return value is the index of the first line in the
+ * passed in list, which does not belong to the header comment.
+ *
+ * @param commentLines the comment lines
+ * @return the index of the next line after the header comment
+ */
+ private int checkHeaderComment(List<String> commentLines)
+ {
+ if (getHeader() == null && layout.isEmpty())
+ {
+ // This is the first comment. Search for blank lines.
+ int index = commentLines.size() - 1;
+ while (index >= 0 && commentLines.get(index).length() > 0)
+ {
+ index--;
+ }
+ setHeader(new ArrayList<String>(commentLines.subList(0, index + 1)));
+ return index + 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ /**
+ * Tests whether a line is a comment, i.e. whether it starts with a comment
+ * character.
+ *
+ * @param line the line
+ * @return a flag if this is a comment line
+ */
+ static boolean isCommentLine(String line) {
+ String s = line.trim();
+ // blank lines are also treated as comment lines
+ return s.length() < 1 || COMMENT_CHARS.indexOf(s.charAt(0)) >= 0;
+ }
+
+ /**
+ * <p>Unescapes any Java literals found in the <code>String</code> to a
+ * <code>Writer</code>.</p> This is a slightly modified version of the
+ * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't
+ * drop escaped separators (i.e '\,').
+ *
+ * @param str the <code>String</code> to unescape, may be null
+ * @return the processed string
+ * @throws IllegalArgumentException if the Writer is <code>null</code>
+ */
+ protected static String unescapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuffer out = new StringBuffer(sz);
+ StringBuffer unicode = new StringBuffer(UNICODE_LEN);
+ boolean hadSlash = false;
+ boolean inUnicode = false;
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ if (inUnicode) {
+ // if in unicode, then we're reading unicode
+ // values in somehow
+ unicode.append(ch);
+ if (unicode.length() == UNICODE_LEN) {
+ // unicode now contains the four hex digits
+ // which represents our unicode character
+ try {
+ int value = Integer.parseInt(unicode.toString(), HEX_RADIX);
+ out.append((char) value);
+ unicode.setLength(0);
+ inUnicode = false;
+ hadSlash = false;
+ } catch (NumberFormatException nfe) {
+ throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
+ }
+ }
+ continue;
+ }
+
+ if (hadSlash) {
+ // handle an escaped value
+ hadSlash = false;
+ switch (ch) {
+ case '\\' :
+ out.append('\\');
+ break;
+ case '\'' :
+ out.append('\'');
+ break;
+ case '\"' :
+ out.append('"');
+ break;
+ case 'r' :
+ out.append('\r');
+ break;
+ case 'f' :
+ out.append('\f');
+ break;
+ case 't' :
+ out.append('\t');
+ break;
+ case 'n' :
+ out.append('\n');
+ break;
+ case 'b' :
+ out.append('\b');
+ break;
+ case 'u' :
+ // uh-oh, we're in unicode country....
+ inUnicode = true;
+ break;
+ default :
+ out.append(ch);
+ break;
+ }
+ continue;
+ } else if (ch == '\\') {
+ hadSlash = true;
+ continue;
+ }
+ out.append(ch);
+ }
+
+ if (hadSlash) {
+ // then we're in the weird case of a \ at the end of the
+ // string, let's output it anyway.
+ out.append('\\');
+ }
+
+ return out.toString();
+ }
+
+ /**
+ * <p>Escapes the characters in a <code>String</code> using Java String rules.</p>
+ *
+ * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
+ *
+ * <p>So a tab becomes the characters <code>'\\'</code> and
+ * <code>'t'</code>.</p>
+ *
+ * <p>The only difference between Java strings and JavaScript strings
+ * is that in JavaScript, a single quote must be escaped.</p>
+ *
+ * <p>Example:
+ * <pre>
+ * input string: He didn't say, "Stop!"
+ * output string: He didn't say, \"Stop!\"
+ * </pre>
+ * </p>
+ *
+ * @param str String to escape values in, may be null
+ * @return String with escaped values, <code>null</code> if null string input
+ */
+ protected static String escapeJava(String str) {
+ if (str == null) {
+ return null;
+ }
+ int sz = str.length();
+ StringBuffer out = new StringBuffer(sz * 2);
+ for (int i = 0; i < sz; i++) {
+ char ch = str.charAt(i);
+ // handle unicode
+ if (ch > 0xfff) {
+ out.append("\\u").append(hex(ch));
+ } else if (ch > 0xff) {
+ out.append("\\u0").append(hex(ch));
+ } else if (ch > 0x7f) {
+ out.append("\\u00").append(hex(ch));
+ } else if (ch < 32) {
+ switch (ch) {
+ case '\b' :
+ out.append('\\');
+ out.append('b');
+ break;
+ case '\n' :
+ out.append('\n');
+ break;
+ case '\t' :
+ out.append('\\');
+ out.append('t');
+ break;
+ case '\f' :
+ out.append('\\');
+ out.append('f');
+ break;
+ case '\r' :
+ out.append('\\');
+ out.append('r');
+ break;
+ default :
+ if (ch > 0xf) {
+ out.append("\\u00").append(hex(ch));
+ } else {
+ out.append("\\u000").append(hex(ch));
+ }
+ break;
+ }
+ } else {
+ switch (ch) {
+ case '"' :
+ out.append('\\');
+ out.append('"');
+ break;
+ default :
+ out.append(ch);
+ break;
+ }
+ }
+ }
+ return out.toString();
+ }
+
+ /**
+ * <p>Returns an upper case hexadecimal <code>String</code> for the given
+ * character.</p>
+ *
+ * @param ch The character to convert.
+ * @return An upper case hexadecimal <code>String</code>
+ */
+ protected static String hex(char ch) {
+ return Integer.toHexString(ch).toUpperCase(Locale.ENGLISH);
+ }
+
+ /**
+ * <p>Checks if the value is in the given array.</p>
+ *
+ * <p>The method returns <code>false</code> if a <code>null</code> array is passed in.</p>
+ *
+ * @param array the array to search through
+ * @param valueToFind the value to find
+ * @return <code>true</code> if the array contains the object
+ */
+ public static boolean contains(char[] array, char valueToFind) {
+ if (array == null) {
+ return false;
+ }
+ for (int i = 0; i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Escape the separators in the key.
+ *
+ * @param key the key
+ * @return the escaped key
+ */
+ private static String escapeKey(String key)
+ {
+ StringBuffer newkey = new StringBuffer();
+
+ for (int i = 0; i < key.length(); i++)
+ {
+ char c = key.charAt(i);
+
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c))
+ {
+ // escape the separator
+ newkey.append('\\');
+ newkey.append(c);
+ }
+ else
+ {
+ newkey.append(c);
+ }
+ }
+
+ return newkey.toString();
+ }
+
+ /**
+ * This class is used to read properties lines. These lines do
+ * not terminate with new-line chars but rather when there is no
+ * backslash sign a the end of the line. This is used to
+ * concatenate multiple lines for readability.
+ */
+ public static class PropertiesReader extends LineNumberReader
+ {
+ /** Stores the comment lines for the currently processed property.*/
+ private final List<String> commentLines;
+
+ /** Stores the value lines for the currently processed property.*/
+ private final List<String> valueLines;
+
+ /** Stores the name of the last read property.*/
+ private String propertyName;
+
+ /** Stores the value of the last read property.*/
+ private String propertyValue;
+
+ /**
+ * Creates a new instance of <code>PropertiesReader</code> and sets
+ * the underlaying reader and the list delimiter.
+ *
+ * @param reader the reader
+ */
+ public PropertiesReader(Reader reader)
+ {
+ super(reader);
+ commentLines = new ArrayList<String>();
+ valueLines = new ArrayList<String>();
+ }
+
+ /**
+ * Reads a property line. Returns null if Stream is
+ * at EOF. Concatenates lines ending with "\".
+ * Skips lines beginning with "#" or "!" and empty lines.
+ * The return value is a property definition (<code><name></code>
+ * = <code><value></code>)
+ *
+ * @return A string containing a property value or null
+ *
+ * @throws java.io.IOException in case of an I/O error
+ */
+ public String readProperty() throws IOException
+ {
+ commentLines.clear();
+ valueLines.clear();
+ StringBuffer buffer = new StringBuffer();
+
+ while (true)
+ {
+ String line = readLine();
+ if (line == null)
+ {
+ // EOF
+ return null;
+ }
+
+ if (isCommentLine(line))
+ {
+ commentLines.add(line);
+ continue;
+ }
+
+ valueLines.add(line);
+ line = line.trim();
+
+ if (checkCombineLines(line))
+ {
+ line = line.substring(0, line.length() - 1);
+ buffer.append(line);
+ }
+ else
+ {
+ buffer.append(line);
+ break;
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Parses the next property from the input stream and stores the found
+ * name and value in internal fields. These fields can be obtained using
+ * the provided getter methods. The return value indicates whether EOF
+ * was reached (<b>false</b>) or whether further properties are
+ * available (<b>true</b>).
+ *
+ * @return a flag if further properties are available
+ * @throws java.io.IOException if an error occurs
+ */
+ public boolean nextProperty() throws IOException
+ {
+ String line = readProperty();
+
+ if (line == null)
+ {
+ return false; // EOF
+ }
+
+ // parse the line
+ String[] property = parseProperty(line);
+ propertyName = unescapeJava(property[0]);
+ propertyValue = unescapeJava(property[1]);
+ return true;
+ }
+
+ /**
+ * Returns the comment lines that have been read for the last property.
+ *
+ * @return the comment lines for the last property returned by
+ * <code>readProperty()</code>
+ */
+ public List<String> getCommentLines()
+ {
+ return commentLines;
+ }
+
+ /**
+ * Returns the value lines that have been read for the last property.
+ *
+ * @return the raw value lines for the last property returned by
+ * <code>readProperty()</code>
+ */
+ public List<String> getValueLines()
+ {
+ return valueLines;
+ }
+
+ /**
+ * Returns the name of the last read property. This method can be called
+ * after <code>{@link #nextProperty()}</code> was invoked and its
+ * return value was <b>true</b>.
+ *
+ * @return the name of the last read property
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Returns the value of the last read property. This method can be
+ * called after <code>{@link #nextProperty()}</code> was invoked and
+ * its return value was <b>true</b>.
+ *
+ * @return the value of the last read property
+ */
+ public String getPropertyValue()
+ {
+ return propertyValue;
+ }
+
+ /**
+ * Checks if the passed in line should be combined with the following.
+ * This is true, if the line ends with an odd number of backslashes.
+ *
+ * @param line the line
+ * @return a flag if the lines should be combined
+ */
+ private static boolean checkCombineLines(String line)
+ {
+ int bsCount = 0;
+ for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == '\\'; idx--)
+ {
+ bsCount++;
+ }
+
+ return bsCount % 2 != 0;
+ }
+
+ /**
+ * Parse a property line and return the key and the value in an array.
+ *
+ * @param line the line to parse
+ * @return an array with the property's key and value
+ */
+ private static String[] parseProperty(String line)
+ {
+ // sorry for this spaghetti code, please replace it as soon as
+ // possible with a regexp when the Java 1.3 requirement is dropped
+
+ String[] result = new String[2];
+ StringBuffer key = new StringBuffer();
+ StringBuffer value = new StringBuffer();
+
+ // state of the automaton:
+ // 0: key parsing
+ // 1: antislash found while parsing the key
+ // 2: separator crossing
+ // 3: value parsing
+ int state = 0;
+
+ for (int pos = 0; pos < line.length(); pos++)
+ {
+ char c = line.charAt(pos);
+
+ switch (state)
+ {
+ case 0:
+ if (c == '\\')
+ {
+ state = 1;
+ }
+ else if (contains(WHITE_SPACE, c))
+ {
+ // switch to the separator crossing state
+ state = 2;
+ }
+ else if (contains(SEPARATORS, c))
+ {
+ // switch to the value parsing state
+ state = 3;
+ }
+ else
+ {
+ key.append(c);
+ }
+
+ break;
+
+ case 1:
+ if (contains(SEPARATORS, c) || contains(WHITE_SPACE, c))
+ {
+ // this is an escaped separator or white space
+ key.append(c);
+ }
+ else
+ {
+ // another escaped character, the '\' is preserved
+ key.append('\\');
+ key.append(c);
+ }
+
+ // return to the key parsing state
+ state = 0;
+
+ break;
+
+ case 2:
+ if (contains(WHITE_SPACE, c))
+ {
+ // do nothing, eat all white spaces
+ state = 2;
+ }
+ else if (contains(SEPARATORS, c))
+ {
+ // switch to the value parsing state
+ state = 3;
+ }
+ else
+ {
+ // any other character indicates we encoutered the beginning of the value
+ value.append(c);
+
+ // switch to the value parsing state
+ state = 3;
+ }
+
+ break;
+
+ case 3:
+ value.append(c);
+ break;
+ }
+ }
+
+ result[0] = key.toString().trim();
+ result[1] = value.toString().trim();
+
+ return result;
+ }
+ } // class PropertiesReader
+
+ /**
+ * This class is used to write properties lines.
+ */
+ public static class PropertiesWriter extends FilterWriter
+ {
+ /**
+ * Constructor.
+ *
+ * @param writer a Writer object providing the underlying stream
+ */
+ public PropertiesWriter(Writer writer)
+ {
+ super(writer);
+ }
+
+ /**
+ * Writes the given property and its value.
+ *
+ * @param key the property key
+ * @param value the property value
+ * @throws java.io.IOException if an error occurs
+ */
+ public void writeProperty(String key, String value) throws IOException
+ {
+ write(escapeKey(key));
+ write(" = ");
+ write(escapeJava(value));
+ writeln(null);
+ }
+
+ /**
+ * Helper method for writing a line with the platform specific line
+ * ending.
+ *
+ * @param s the content of the line (may be <b>null</b>)
+ * @throws java.io.IOException if an error occurs
+ */
+ public void writeln(String s) throws IOException
+ {
+ if (s != null)
+ {
+ write(s);
+ }
+ write(LINE_SEPARATOR);
+ }
+
+ } // class PropertiesWriter
+
+ /**
+ * TODO
+ */
+ protected static class Layout {
+
+ private List<String> commentLines;
+ private List<String> valueLines;
+
+ public Layout() {
+ }
+
+ public Layout(List<String> commentLines, List<String> valueLines) {
+ this.commentLines = commentLines;
+ this.valueLines = valueLines;
+ }
+
+ public List<String> getCommentLines() {
+ return commentLines;
+ }
+
+ public void setCommentLines(List<String> commentLines) {
+ this.commentLines = commentLines;
+ }
+
+ public List<String> getValueLines() {
+ return valueLines;
+ }
+
+ public void setValueLines(List<String> valueLines) {
+ this.valueLines = valueLines;
+ }
+
+ public void clearValue() {
+ this.valueLines = null;
+ }
+
+ } // class Layout
+
+}
\ No newline at end of file
Modified: karaf/trunk/kar/core/src/main/resources/OSGI-INF/blueprint/kar-core.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/main/resources/OSGI-INF/blueprint/kar-core.xml?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/kar/core/src/main/resources/OSGI-INF/blueprint/kar-core.xml (original)
+++ karaf/trunk/kar/core/src/main/resources/OSGI-INF/blueprint/kar-core.xml Fri Jun 22 15:50:19 2012
@@ -20,14 +20,18 @@
default-activation="lazy">
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]" />
+
+ <reference id="featuresService" interface="org.apache.karaf.features.FeaturesService"/>
+ <reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin" />
- <bean id="karService" class="org.apache.karaf.kar.internal.KarServiceImpl" init-method="init">
- <property name="base" value="$[karaf.base]"/>
- <property name="storage" value="$[karaf.data]/kar"/>
- <property name="localRepo" value="$[karaf.base]/system"/>
- <property name="featuresService">
- <reference interface="org.apache.karaf.features.FeaturesService"/>
- </property>
+ <bean id="karService" class="org.apache.karaf.kar.internal.KarServiceImpl">
+ <argument value="$[karaf.base]" />
+ <argument ref="featuresService" />
+ <argument ref="mavenRepoManager"/>
+ </bean>
+
+ <bean id="mavenRepoManager" class="org.apache.karaf.kar.internal.MavenRepoManager">
+ <argument value="$[karaf.base]" />
</bean>
<service ref="karService" interface="org.apache.karaf.kar.KarService"/>
Added: karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/MavenRepoManagerTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/MavenRepoManagerTest.java?rev=1352937&view=auto
==============================================================================
--- karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/MavenRepoManagerTest.java (added)
+++ karaf/trunk/kar/core/src/test/java/org/apache/karaf/kar/internal/MavenRepoManagerTest.java Fri Jun 22 15:50:19 2012
@@ -0,0 +1,43 @@
+package org.apache.karaf.kar.internal;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MavenRepoManagerTest {
+
+ @Test
+ public void testGetRepos() throws IOException {
+ String reposAttr = " \\\n" +
+ " http://repo1.maven.org/maven2@id=central, \\\n" +
+ " http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases, \\\n" +
+ " https://oss.sonatype.org/content/repositories/ops4j-snapshots@id=ops4j.sonatype.snapshots.deploy@snapshots@noreleases, \\\n" +
+ " file:${karaf.home}/${karaf.default.repository}@id=systemrepo";
+
+ MavenRepoManager repoManager = new MavenRepoManager(null);
+ List<String> repos = repoManager.getRepos(reposAttr);
+
+ Assert.assertEquals(4, repos.size());
+ Assert.assertEquals("http://repo1.maven.org/maven2@id=central", repos.get(0));
+ Assert.assertEquals("file:${karaf.home}/${karaf.default.repository}@id=systemrepo", repos.get(3));
+ }
+
+ @Test
+ public void testGetReposAttrValue() throws IOException {
+ List<String> repos = new ArrayList<String>();
+ repos.add("http://repo1.maven.org/maven2@id=central");
+ repos.add("http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases");
+ repos.add("file:${karaf.home}/${karaf.default.repository}@id=systemrepo");
+
+ MavenRepoManager repoManager = new MavenRepoManager(null);
+ String reposSt = repoManager.getReposAttrValue(repos);
+
+ Assert.assertEquals("\\\n" +
+ "http://repo1.maven.org/maven2@id=central, \\\n" +
+ "http://repository.apache.org/content/groups/snapshots-group@id=apache@snapshots@noreleases, \\\n" +
+ "file:${karaf.home}/${karaf.default.repository}@id=systemrepo", reposSt);
+ }
+}
Modified: karaf/trunk/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java
URL: http://svn.apache.org/viewvc/karaf/trunk/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java?rev=1352937&r1=1352936&r2=1352937&view=diff
==============================================================================
--- karaf/trunk/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java (original)
+++ karaf/trunk/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/features/InstallKarsMojo.java Fri Jun 22 15:50:19 2012
@@ -49,7 +49,7 @@ import org.apache.karaf.features.interna
import org.apache.karaf.features.internal.model.Feature;
import org.apache.karaf.features.internal.model.Features;
import org.apache.karaf.features.internal.model.JaxbUtil;
-import org.apache.karaf.kar.internal.KarServiceImpl;
+import org.apache.karaf.kar.internal.Kar;
import org.apache.karaf.tooling.utils.MojoSupport;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
@@ -194,29 +194,27 @@ public class InstallKarsMojo extends Moj
startupPropertiesFile.getParentFile().mkdirs();
}
}
- KarServiceImpl karService = new KarServiceImpl();
+
FeaturesService featuresService = new OfflineFeaturesService();
- karService.setFeaturesService(featuresService);
- karService.setBase(workDirectory);
- try {
- karService.init();
- } catch (Exception e) {
- throw new MojoExecutionException("Can't init the KAR service", e);
- }
Collection<Artifact> dependencies = project.getDependencyArtifacts();
StringBuilder buf = new StringBuilder();
byte[] buffer = new byte[4096];
for (Artifact artifact : dependencies) {
dontAddToStartup = "runtime".equals(artifact.getScope());
- karService.setLocalRepo(system.getPath());
if ("kar".equals(artifact.getType()) && acceptScope(artifact)) {
File file = artifact.getFile();
try {
- karService.install(file.toURI());
+ Kar kar = new Kar(file.toURI());
+ kar.extract(new File(system.getPath()), new File(workDirectory));
+ for (URI repoUri : kar.getFeatureRepos()) {
+ featuresService.removeRepository(repoUri);
+ featuresService.addRepository(repoUri);
+ }
} catch (Exception e) {
- buf.append("Could not install kar: ").append(artifact.toString()).append("\n");
- buf.append(e.getMessage()).append("\n\n");
+ throw new RuntimeException("Could not install kar: " + artifact.toString() + "\n", e);
+ //buf.append("Could not install kar: ").append(artifact.toString()).append("\n");
+ //buf.append(e.getMessage()).append("\n\n");
}
}
if ("features".equals(artifact.getClassifier()) && acceptScope(artifact)) {