blob: d2e805a3dad1d1ad885d703d6d8bc79f6a5c7953 [file] [log] [blame]
/*
* 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.sling.feature.karaf;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Configuration;
import org.apache.sling.feature.Configurations;
import org.apache.sling.feature.Extension;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.support.ArtifactHandler;
import org.apache.sling.feature.support.ArtifactManager;
import org.apache.sling.feature.support.ConfigurationUtil;
/**
* This writer writes out a Karaf feature XML.
*
*/
public class KarafFeatureWriter {
public static void writeKAR(final OutputStream os,
final Feature feature,
final ArtifactManager artifactManager)
throws IOException {
// check for repoinit extension
final Extension repoinitExt = feature.getExtensions().getByName(Extension.NAME_REPOINIT);
File configurationBundleFile = null;
Artifact configuratorBundle = null;
try {
final Configurations configs = new Configurations();
configs.addAll(feature.getConfigurations());
if ( repoinitExt != null ) {
final Configuration cfg = new Configuration("org.apache.sling.jcr.repoinit.RepositoryInitializer",
"feature-" + feature.getId().getArtifactId());
cfg.getProperties().put("scripts", repoinitExt.getText());
configs.add(cfg);
}
if ( !configs.isEmpty() ) {
configurationBundleFile = Files.createTempFile(null, null).toFile();
try ( final FileOutputStream fos = new FileOutputStream(configurationBundleFile)) {
final Map<String, String> map;
if ( repoinitExt == null ) {
map = null;
} else {
map = Collections.singletonMap("Require-Capability",
ConfigurationUtil.REQUIRE_REPOINIT_CAPABILITY);
}
ConfigurationUtil.createConfiguratorBundle(os,
configs,
feature.getId().getGroupId() + "." + feature.getId().getArtifactId(),
feature.getId().getOSGiVersion().toString(),
map);
configuratorBundle = new Artifact(new ArtifactId(feature.getId().getGroupId(),
feature.getId().getArtifactId(),
feature.getId().getVersion(), "configurator", null));
}
}
try ( final ZipOutputStream jos = new ZipOutputStream(os) ) {
// repository/features.xml
// repository/{maven-path-to-bundle}
final ZipEntry xmlEntry = new ZipEntry("repository/features.xml");
jos.putNextEntry(xmlEntry);
final Writer writer = new OutputStreamWriter(jos);
writeFeaturesXML(writer, feature, configuratorBundle);
writer.flush();
jos.closeEntry();
for(final Map.Entry<Integer, List<Artifact>> entry : feature.getBundles().getBundlesByStartOrder().entrySet()) {
for(final Artifact artifact : entry.getValue()) {
final ArtifactHandler handler = artifactManager.getArtifactHandler(artifact.getId().toMvnUrl());
addEntry(jos, artifact, handler.getFile());
}
}
if ( configuratorBundle != null ) {
addEntry(jos, configuratorBundle, configurationBundleFile);
}
}
} finally {
if ( configurationBundleFile != null ) {
configurationBundleFile.delete();
}
}
}
private static void addEntry(final ZipOutputStream jos, final Artifact artifact, final File file)
throws IOException {
final ZipEntry bundleEntry = new ZipEntry("repository/" + artifact.getId().toMvnPath());
jos.putNextEntry(bundleEntry);
final byte[] buffer = new byte[16384];
try ( final FileInputStream fis = new FileInputStream(file)) {
int l = 0;
while ( (l = fis.read(buffer)) > 0 ) {
jos.write(buffer, 0, l);
}
}
jos.closeEntry();
}
/**
* Writes the feature XML to the writer.
* The writer is not closed.
* @param writer Writer
* @param model Model
* @throws IOException
*/
private static void writeFeaturesXML(final Writer writer,
final Feature feature,
final Artifact configuratorBundle)
throws IOException {
final PrintWriter w = new PrintWriter(writer);
w.print("<features name=\"");
w.print(feature.getId().getArtifactId());
w.print("-repo-");
w.print(feature.getId().getVersion());
w.println("\" xmlns=\"http://karaf.apache.org/xmlns/features/v1.4.0\">");
write(w, feature, configuratorBundle);
w.println("</features>");
w.flush();
}
private static void write(final PrintWriter w, final Feature feature, final Artifact configuratorBundle)
throws IOException {
w.print(" <feature name=\"");
w.print(feature.getId().getGroupId());
w.print('.');
w.print(feature.getId().getArtifactId());
if ( feature.getId().getClassifier() != null ) {
w.print('.');
w.print(feature.getId().getClassifier());
}
w.print("\" version=\"");
w.print(feature.getId().getVersion());
w.println("\">");
if ( configuratorBundle != null ) {
w.print(" <bundle start-level=\"1\">");
w.print(configuratorBundle.getId().toMvnUrl());
w.println("</bundle>");
}
// bundles
for(final Map.Entry<Integer, List<Artifact>> entry : feature.getBundles().getBundlesByStartOrder().entrySet()) {
for(final Artifact artifact : entry.getValue()) {
w.print(" <bundle start-level=\"");
w.print(entry.getKey().toString());
w.print("\">");
w.print(artifact.getId().toMvnUrl());
w.println("</bundle>");
}
}
w.println(" </feature>");
}
}