/**
 * 
 * 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.activemq.store.kahadaptor;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.activemq.kaha.IndexTypes;
import org.apache.activemq.kaha.ListContainer;
import org.apache.activemq.kaha.MapContainer;
import org.apache.activemq.kaha.Store;
import org.apache.activemq.kaha.StoreFactory;
import org.apache.activemq.kaha.StringMarshaller;
import org.apache.activemq.memory.UsageManager;
import org.apache.activemq.openwire.OpenWireFormat;
import org.apache.activemq.store.MessageStore;
import org.apache.activemq.store.PersistenceAdapter;
import org.apache.activemq.store.TopicMessageStore;
import org.apache.activemq.store.TransactionStore;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;

/**
 * @org.apache.xbean.XBean
 * 
 * @version $Revision: 1.4 $
 */
public class KahaPersistenceAdapter implements PersistenceAdapter{

    private static final Log log=LogFactory.getLog(KahaPersistenceAdapter.class);
    static final String PREPARED_TRANSACTIONS_NAME="PreparedTransactions";
    KahaTransactionStore transactionStore;
    ConcurrentHashMap topics=new ConcurrentHashMap();
    ConcurrentHashMap queues=new ConcurrentHashMap();
    ConcurrentHashMap messageStores=new ConcurrentHashMap();
    private boolean useExternalMessageReferences;
    private OpenWireFormat wireFormat=new OpenWireFormat();
    private long maxDataFileLength=32*1024*1024;
    private String indexType=IndexTypes.DISK_INDEX;
    private File dir;
    private Store theStore;

    public KahaPersistenceAdapter(File dir) throws IOException{
        if(!dir.exists()){
            dir.mkdirs();
        }
        this.dir=dir;
    }

    public Set getDestinations(){
        Set rc=new HashSet();
        try{
            Store store=getStore();
            for(Iterator i=store.getMapContainerIds().iterator();i.hasNext();){
                Object obj=i.next();
                if(obj instanceof ActiveMQDestination){
                    rc.add(obj);
                }
            }
        }catch(IOException e){
            log.error("Failed to get destinations ",e);
        }
        return rc;
    }

    public synchronized MessageStore createQueueMessageStore(ActiveMQQueue destination) throws IOException{
        MessageStore rc=(MessageStore)queues.get(destination);
        if(rc==null){
            rc=new KahaMessageStore(getMapContainer(destination,"queue-data"),destination);
            messageStores.put(destination,rc);
            if(transactionStore!=null){
                rc=transactionStore.proxy(rc);
            }
            queues.put(destination,rc);
        }
        return rc;
    }

    public synchronized TopicMessageStore createTopicMessageStore(ActiveMQTopic destination) throws IOException{
        TopicMessageStore rc=(TopicMessageStore)topics.get(destination);
        if(rc==null){
            Store store=getStore();
            ListContainer messageContainer=getListContainer(destination,"topic-data");
            MapContainer subsContainer=getMapContainer(destination.toString()+"-Subscriptions","topic-subs");
            ListContainer ackContainer=store.getListContainer(destination.toString(),"topic-acks");
            ackContainer.setMarshaller(new TopicSubAckMarshaller());
            rc=new KahaTopicMessageStore(store,messageContainer,ackContainer,subsContainer,destination);
            messageStores.put(destination,rc);
            if(transactionStore!=null){
                rc=transactionStore.proxy(rc);
            }
            topics.put(destination,rc);
        }
        return rc;
    }

    protected MessageStore retrieveMessageStore(Object id){
        MessageStore result=(MessageStore)messageStores.get(id);
        return result;
    }

    public TransactionStore createTransactionStore() throws IOException{
        if(transactionStore==null){
            Store store=getStore();
            MapContainer container=store.getMapContainer(PREPARED_TRANSACTIONS_NAME,"transactions");
            container.setKeyMarshaller(new CommandMarshaller(wireFormat));
            container.setValueMarshaller(new TransactionMarshaller(wireFormat));
            container.load();
            transactionStore=new KahaTransactionStore(this,container);
        }
        return transactionStore;
    }

    public void beginTransaction(ConnectionContext context){
    }

    public void commitTransaction(ConnectionContext context) throws IOException{
        if(theStore!=null){
            theStore.force();
        }
    }

    public void rollbackTransaction(ConnectionContext context){
    }

    public void start() throws Exception{
    }

    public void stop() throws Exception{
        if(theStore!=null){
            theStore.close();
        }
    }

    public long getLastMessageBrokerSequenceId() throws IOException{
        return 0;
    }

    public void deleteAllMessages() throws IOException{
        if(theStore!=null){
            theStore.clear();
        }
    }

    public boolean isUseExternalMessageReferences(){
        return useExternalMessageReferences;
    }

    public void setUseExternalMessageReferences(boolean useExternalMessageReferences){
        this.useExternalMessageReferences=useExternalMessageReferences;
    }

    protected MapContainer getMapContainer(Object id,String containerName) throws IOException{
        Store store=getStore();
        MapContainer container=store.getMapContainer(id,containerName);
        container.setKeyMarshaller(new StringMarshaller());
        if(useExternalMessageReferences){
            container.setValueMarshaller(new StringMarshaller());
        }else{
            container.setValueMarshaller(new CommandMarshaller(wireFormat));
        }
        container.load();
        return container;
    }
    
    protected ListContainer getListContainer(Object id,String containerName) throws IOException{
        Store store=getStore();
        ListContainer container=store.getListContainer(id,containerName);
        if(useExternalMessageReferences){
            container.setMarshaller(new StringMarshaller());
        }else{
            container.setMarshaller(new CommandMarshaller(wireFormat));
        }
        container.load();
        return container;
    }

    /**
     * @param usageManager
     *            The UsageManager that is controlling the broker's memory
     *            usage.
     */
    public void setUsageManager(UsageManager usageManager){
    }

    /**
     * @return the maxDataFileLength
     */
    public long getMaxDataFileLength(){
        return maxDataFileLength;
    }

    /**
     * @param maxDataFileLength
     *            the maxDataFileLength to set
     * 
     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryPropertyEditor"
     */
    public void setMaxDataFileLength(long maxDataFileLength){
        this.maxDataFileLength=maxDataFileLength;
    }

    /**
     * @return the indexType
     */
    public String getIndexType(){
        return this.indexType;
    }

    /**
     * @param indexType the indexTypes to set
     */
    public void setIndexType(String indexType){
        this.indexType=indexType;
    }

    protected synchronized Store getStore() throws IOException{
        if(theStore==null){
            String name=dir.getAbsolutePath()+File.separator+"kaha.db";
            theStore=StoreFactory.open(name,"rw");
            theStore.setMaxDataFileLength(maxDataFileLength);
            theStore.setIndexType(indexType);
        }
        return theStore;
    }
}

@@ -6290,13 +6290,14 @@
 ore.
-clear
+delete
 ();%0D

delete instead of clear messages for deleteAllMessagesOnStart()