Java tutorial
/* * Copyright 2016 the original author or authors. * * 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. */ package io.sledge.core.impl.installer; import io.sledge.core.api.installer.InstallationException; import io.sledge.core.api.installer.PackageConfigurer; import org.apache.commons.lang3.text.StrSubstitutor; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.models.annotations.Model; import org.apache.tika.detect.Detector; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MediaType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * @author oliver.burkhalter */ @Model(adaptables = SlingHttpServletRequest.class) public class SledgePackageConfigurer implements PackageConfigurer { private final Logger log = LoggerFactory.getLogger(getClass()); @Inject private Detector tikaDetector; private List<String> validTextfileTypes = Arrays.asList("text/plain", "application/xml", "text/x-java-properties"); @Override public InputStream configure(InputStream packageStream, String packageName, Properties props) { InputStream resultStream = packageStream; try { Path sledgeTmpDir = createSledgeTmpDirectoryIfNotExists(); deleteZipFile(sledgeTmpDir, packageName); Path configurationZipPackagePath = sledgeTmpDir.resolve(packageName); createNewZipfileWithReplacedPlaceholders(packageStream, configurationZipPackagePath, props); resultStream = new FileInputStream(configurationZipPackagePath.toFile()); } catch (IOException e) { log.error("Could not configure package: " + packageName, e); } finally { try { packageStream.reset(); packageStream.close(); } catch (IOException e) { log.error(e.getMessage(), e); } } return resultStream; } @Override public Properties mergeProperties(String envFileContent, Properties propsForMerge) { Properties mergedProps = new Properties(); try { // Support internal property references for application package provided properties Properties origProps = new Properties(); origProps.load(new StringReader(envFileContent)); String configuredEnvironmentFileContent = StrSubstitutor.replace(envFileContent, origProps); mergedProps.load(new StringReader(configuredEnvironmentFileContent)); // Support internal property references for overwrite properties StringWriter propsForMergeWriter = new StringWriter(); propsForMerge.store(propsForMergeWriter, ""); String propsForMergeAsString = propsForMergeWriter.getBuffer().toString(); String configuredPropsForMerge = StrSubstitutor.replace(propsForMergeAsString, propsForMerge); Properties reconfiguredPropsForMerge = new Properties(); reconfiguredPropsForMerge.load(new StringReader(configuredPropsForMerge)); mergedProps.putAll(reconfiguredPropsForMerge); } catch (IOException e) { throw new InstallationException("Could not load environment properties.", e); } return mergedProps; } private void createNewZipfileWithReplacedPlaceholders(InputStream packageStream, Path configurationPackagePath, Properties envProps) throws IOException { // For reading the original configuration package ZipInputStream configPackageZipStream = new ZipInputStream(new BufferedInputStream(packageStream), Charset.forName("UTF-8")); // For outputting the configured (placeholders replaced) version of the package as zip file File outZipFile = configurationPackagePath.toFile(); ZipOutputStream outConfiguredZipStream = new ZipOutputStream(new FileOutputStream(outZipFile)); ZipEntry zipEntry; while ((zipEntry = configPackageZipStream.getNextEntry()) != null) { if (zipEntry.isDirectory()) { configPackageZipStream.closeEntry(); continue; } else { ByteArrayOutputStream output = new ByteArrayOutputStream(); int length; byte[] buffer = new byte[2048]; while ((length = configPackageZipStream.read(buffer, 0, buffer.length)) >= 0) { output.write(buffer, 0, length); } InputStream zipEntryInputStream = new BufferedInputStream( new ByteArrayInputStream(output.toByteArray())); if (zipEntry.getName().endsWith("instance.properties")) { ByteArrayOutputStream envPropsOut = new ByteArrayOutputStream(); envProps.store(envPropsOut, "Environment configurations"); zipEntryInputStream = new BufferedInputStream( new ByteArrayInputStream(envPropsOut.toByteArray())); } else if (isTextFile(zipEntry.getName(), zipEntryInputStream)) { String configuredContent = StrSubstitutor.replace(output, envProps); zipEntryInputStream = new BufferedInputStream( new ByteArrayInputStream(configuredContent.getBytes())); } // Add to output zip file addToZipFile(zipEntry.getName(), zipEntryInputStream, outConfiguredZipStream); zipEntryInputStream.close(); configPackageZipStream.closeEntry(); } } outConfiguredZipStream.close(); configPackageZipStream.close(); } private boolean isTextFile(String filename, InputStream inputStream) throws IOException { Metadata metadata = new Metadata(); metadata.set(Metadata.RESOURCE_NAME_KEY, filename); final MediaType mediaType = tikaDetector.detect(inputStream, metadata); return validTextfileTypes.contains(mediaType.toString()); } private void addToZipFile(String zipEntryName, InputStream inStream, ZipOutputStream zipStream) throws IOException { log.debug("Adding zip entry: " + zipEntryName); ZipEntry entry = new ZipEntry(zipEntryName); zipStream.putNextEntry(entry); byte[] readBuffer = new byte[2048]; int amountRead; int written = 0; while ((amountRead = inStream.read(readBuffer)) > 0) { zipStream.write(readBuffer, 0, amountRead); written += amountRead; } zipStream.closeEntry(); log.debug("Written " + written + " bytes for: " + zipEntryName); } private void deleteZipFile(Path directory, String packageName) throws IOException { Path currentDir = directory.resolve(packageName); Files.deleteIfExists(currentDir); } private Path createSledgeTmpDirectoryIfNotExists() throws IOException { Path sledgeTmpDir = Paths.get("sledge-tmp"); if (Files.notExists(sledgeTmpDir)) { Files.createDirectory(sledgeTmpDir); } return sledgeTmpDir; } }