001/*
002 * Copyright 2017 the original author or authors.
003 *
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements.  See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License.  You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package net.sf.jkniv.camel.sap.jco3;
020
021import java.util.HashMap;
022import java.util.Properties;
023
024import com.sap.conn.jco.ext.DataProviderException;
025import com.sap.conn.jco.ext.DestinationDataEventListener;
026import com.sap.conn.jco.ext.DestinationDataProvider;
027
028/**
029 * Each application using Java Connector 3 deals with destinations. A destination represents a logical address 
030 * of an ABAP system and thus separates the destination configuration from application logic. JCo retrieves
031 * the destination parameters required at runtime from DestinationDataProvider and ServerDataProvider registered
032 * in the runtime environment. If no provider is registered, JCo uses the default implementation that reads the 
033 * configuration from a properties file. It is expected that each environment provides a suitable 
034 * implementation that meets security and other requirements. Furthermore, only one DestinationDataProvider 
035 * and only one ServerDataProvider can be registered per process. The reason behind this design decision 
036 * is the following: the provider implementations are part of the environment infrastructure. 
037 * The implementation should not be application specific, and in particular must be separated from 
038 * application logic. 
039 */
040public class SapJcoDestinationDataProvider implements DestinationDataProvider
041{
042    private DestinationDataEventListener eL;
043    private HashMap<String, Properties>  propsByDestName = new HashMap<String, Properties>();
044    
045    /**
046     * The name of SAP <code>JCoDestination</code> name that identifies a physical destination of a function call.
047     */
048    public Properties getDestinationProperties(String destName)
049    {
050        try
051        {
052            //read the destination from DB
053            Properties p = propsByDestName.get(destName);
054            
055            if (p != null)
056            {
057                //check if all is correct, for example
058                if (p.isEmpty())
059                    throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION,
060                            "destination [" + destName + "] configuration is incorrect", null);
061                
062                return p;
063            }
064            return null;
065        }
066        catch (RuntimeException re)
067        {
068            throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR,
069                    "Internal error to get config from destination [" + destName + "]", re);
070        }
071    }
072    
073    /**
074     * An implementation supporting events has to retain the eventListener instance provided
075     * by the JCo runtime. This listener instance shall be used to notify the JCo runtime
076     * about all changes in destination configurations.
077     * 
078     * @param eventListener The DestinationDataEventListener interface reacts on the events 
079     * that a DestinationDataProvider could fire if the destination configuration was changed
080     */
081    public void setDestinationDataEventListener(DestinationDataEventListener eventListener)
082    {
083        this.eL = eventListener;
084    }
085    
086    public boolean isRegistered()
087    {
088        return (this.eL != null);
089    }
090    
091    public boolean hasDestName(String destName)
092    {
093        return propsByDestName.containsKey(destName);
094    }
095    
096    public boolean supportsEvents()
097    {
098        return true;
099    }
100    
101    /**
102     * Update the connect properties from a specific <code>destName</code>
103     * @param destName the name of <code>JCoDestination</code>
104     * @param properties connection properties
105     */
106    public void changeProperties(String destName, Properties properties)
107    {
108        synchronized (propsByDestName)
109        {
110            if (properties == null)
111            {
112                if (propsByDestName.remove(destName) != null)
113                    eL.deleted(destName);
114            }
115            else
116            {
117                propsByDestName.put(destName, properties);
118                eL.updated(destName); // create or updated
119            }
120        }
121    }
122    
123}