/*
 * 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.jcr.jackrabbit.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Dictionary;

import javax.jcr.Repository;
import javax.jcr.RepositoryException;

import org.apache.jackrabbit.core.RepositoryImpl;
import org.apache.jackrabbit.core.config.RepositoryConfig;
import org.apache.sling.jcr.api.SlingRepository;
import org.apache.sling.jcr.base.AbstractSlingRepository;
import org.osgi.framework.Bundle;
import org.osgi.service.log.LogService;

/**
 * The <code>SlingServerRepository</code> TODO
 *
 * @scr.component label="%repository.name" description="%repository.description"
 *          factory="org.apache.sling.jcr.jackrabbit.server.SlingServerRepositoryFactory"
 *
 * @scr.property name="service.vendor" value="The Apache Software Foundation"
 * @scr.property name="service.description"
 *      value="Factory for embedded Jackrabbit Repository Instances"
 */
public class SlingServerRepository extends AbstractSlingRepository
        implements Repository, SlingRepository {

    /**
     * The name of the configuration property defining the URL to the
     * repository configuration file (value is
     * "config").
     * <p>
     * If the configuration file is located in the local file system, the
     * "file:" scheme must still be specified.
     * <p>
     * This parameter is mandatory for this activator to start the repository.
     *
     * @scr.property value=""
     */
    public static final String REPOSITORY_CONFIG_URL = "config";

    /**
     * The name of the configuration property defining the file system
     * directory where the repository files are located (value is
     * "home").
     * <p>
     * This parameter is mandatory for this activator to start the repository.
     *
     * @scr.property value=""
     */
    public static final String REPOSITORY_HOME_DIR = "home";

    /**
     * @scr.property value=""
     */
    public static final String REPOSITORY_REGISTRATION_NAME = "name";

    //---------- Repository Management ----------------------------------------
    
    @Override
    protected Repository acquireRepository() {
        Repository repository = super.acquireRepository();
        if (repository != null) {
            return repository;
        }
        
        @SuppressWarnings("unchecked")
        Dictionary<String, Object> environment = this.getComponentContext().getProperties();
        String configURLObj = (String) environment.get(REPOSITORY_CONFIG_URL);
        String home = (String) environment.get(REPOSITORY_HOME_DIR);

        InputStream ins = null;
        try {

            // check whether the URL is a file path
            File configFile = new File(configURLObj);
            if (configFile.canRead()) {
                ins = new FileInputStream(configFile);
            } else {
                URL configURL = new URL(configURLObj);
                ins = configURL.openStream();
            }

            RepositoryConfig crc = RepositoryConfig.create(ins, home);
            return RepositoryImpl.create(crc);
            
        } catch (IOException ioe) {
            
            log(LogService.LOG_ERROR,
                "acquireRepository: IO problem starting repository from "
                    + configURLObj + " in " + home, ioe);
            
        } catch (RepositoryException re) {
            
            log(LogService.LOG_ERROR,
                "acquireRepository: Repository problem starting repository from "
                    + configURLObj + " in " + home, re);
        } finally {
            if (ins != null) {
                try {
                    ins.close();
                } catch (IOException ioe) {
                    // ignore
                }
            }
        }
        
        // got no repository ....
        return null;
    }
    
    @Override
    protected void disposeRepository(Repository repository) {
        super.disposeRepository(repository);

        if (repository instanceof RepositoryImpl) {
            
            try {
                ((RepositoryImpl) repository).shutdown();
            } catch (Throwable t) {
                log(LogService.LOG_ERROR,
                    "deactivate: Unexpected problem shutting down repository",
                    t);
            }
            
        } else {
            log(LogService.LOG_INFO,
                "Repository is not a RepositoryImpl, nothing to do");
        }
    }
    
    //---------- Helper -------------------------------------------------------

    public static void copyFile(Bundle bundle, String entryPath, File destFile) throws FileNotFoundException, IOException {
        if (destFile.canRead()) {
            // nothing to do, file exists
            return;
        }

        // copy from property
        URL entryURL = bundle.getEntry(entryPath);
        if (entryURL == null) {
            throw new FileNotFoundException(entryPath);
        }

        // check for a file property
        InputStream source = entryURL.openStream();

        OutputStream dest = null;
        try {

            // ensure path to parent folder of licFile
            destFile.getParentFile().mkdirs();

            dest = new FileOutputStream(destFile);
            byte[] buf = new byte[2048];
            int rd;
            while ( (rd = source.read(buf)) >= 0) {
                dest.write(buf, 0, rd);
            }


        } finally {
            if (dest != null) {
                try {
                    dest.close();
                } catch (IOException ignore) {
                }
            }

            // licSource is not null
            try {
                source.close();
            } catch (IOException ignore) {
            }
        }
    }
}

@@ -3521,24 +3521,366 @@
 HOME_DIR);%0A%0A
+        // somewhat dirty hack to have the derby.log file in a sensible%0A        // location, but don't overwrite anything already set%0A        if (System.getProperty(%22derby.stream.error.file%22) == null) %7B%0A            String derbyLog = home + %22/derby.log%22;%0A            System.setProperty(%22derby.stream.error.file%22, derbyLog);%0A        %7D%0A        %0A
         Inpu

Set the derby.stream.error.file system property if not set to have the derby.log file created by the Derby database in the current working directory. This is kind of a hack which assumes the Jackrabbit instance is actually using the Derby PersistenceManager, which is actually the case right now.