All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.swiftmq.jndi.v400.ContextImpl Maven / Gradle / Ivy

/*
 * Copyright 2019 IIT Software GmbH
 *
 * IIT Software GmbH 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 com.swiftmq.jndi.v400;

import com.swiftmq.client.Versions;
import com.swiftmq.jms.*;
import com.swiftmq.jndi.StopRetryException;
import com.swiftmq.jndi.protocol.v400.*;
import com.swiftmq.swiftlet.jndi.JNDISwiftlet;
import com.swiftmq.tools.dump.Dumpalizer;
import com.swiftmq.tools.timer.TimerEvent;
import com.swiftmq.tools.timer.TimerListener;
import com.swiftmq.tools.timer.TimerRegistry;
import com.swiftmq.tools.util.DataByteArrayOutputStream;
import com.swiftmq.tools.versioning.Versionable;
import com.swiftmq.tools.versioning.Versioned;

import javax.jms.*;
import javax.naming.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ContextImpl implements Context, java.io.Serializable, AutoCloseable, TimerListener {
    Hashtable env = null;
    JNDIInfo jndiInfo = null;
    ConnectionFactory cf = null;
    final AtomicReference connection = new AtomicReference<>();
    final AtomicReference session = new AtomicReference<>();
    final AtomicReference producer = new AtomicReference<>();
    final AtomicBoolean closed = new AtomicBoolean(true);
    boolean debug = false;
    final AtomicLong lastAccessTime = new AtomicLong();
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public ContextImpl(Hashtable env)
            throws NamingException {
        this.env = env;
        String url = (String) env.get(Context.PROVIDER_URL);
        if (url == null)
            throw new NamingException("missing JNDI environment property: Context.PROVIDER_URL (" + Context.PROVIDER_URL + ")");
        jndiInfo = URLParser.parseURL(url);
        debug = jndiInfo.isDebug();
        Map props = new HashMap();
        if (jndiInfo.isIntraVM()) {
            try {
                props.put(SwiftMQConnectionFactory.INTRAVM, "true");
            } catch (Exception e) {
                throw new NamingException("unable to connect, exception = " + e);
            }
        } else {
            String factoryClass = jndiInfo.getFactory();
            try {
                Class.forName(factoryClass);
            } catch (Exception e) {
                throw new NamingException("socket factory not found: " + factoryClass);
            }
            try {
                props.put(SwiftMQConnectionFactory.SOCKETFACTORY, factoryClass);
                props.put(SwiftMQConnectionFactory.HOSTNAME, jndiInfo.getHostname());
                props.put(SwiftMQConnectionFactory.PORT, String.valueOf(jndiInfo.getPort()));
                props.put(SwiftMQConnectionFactory.KEEPALIVEINTERVAL, String.valueOf(jndiInfo.getKeepalive()));
            } catch (Exception e) {
                throw new NamingException("unable to connect, exception = " + e);
            }
        }
        try {
            cf = SwiftMQConnectionFactory.create(props);
            createConnection();
            if (jndiInfo.getIdleclose() > 0)
                TimerRegistry.Singleton().addTimerListener(1000, this);
            closed.set(false);
        } catch (Exception e) {
            if (connection.get() != null) {
                try {
                    connection.get().close();
                } catch (Exception e1) {
                }
            }
            closed.set(true);
            if ((e instanceof JMSSecurityException) || (e instanceof InvalidVersionException))
                throw new StopRetryException(e.getMessage());
            throw new NamingException("unable to connect, exception = " + e);
        }
    }

    private void createConnection() throws JMSException {
        connection.set(cf.createConnection(jndiInfo.getUsername(), jndiInfo.getPassword()));
        session.set(connection.get().createSession(false, 0));
        producer.set(session.get().createProducer(null));
        connection.get().start();
        lastAccessTime.set(System.currentTimeMillis());
        if (debug)
            System.out.println(new Date() + " " + toString() + "/createConnection: " + env.get(Context.PROVIDER_URL));
    }

    private void checkConnection() throws JMSException {
        lock.writeLock().lock();
        try {
            if (!closed.get() && connection.get() == null)
                createConnection();
            lastAccessTime.set(System.currentTimeMillis());
        } finally {
            lock.writeLock().unlock();
        }
    }

    @Override
    public void performTimeAction(TimerEvent evt) {
        long delta = System.currentTimeMillis() - lastAccessTime.get() - jndiInfo.getIdleclose();
        if (debug)
            System.out.println(new Date() + " " + toString() + "/performTimeAction, connection=" + connection + ", delta=" + delta + ", lastAccessTime=" + lastAccessTime);
        if (connection.get() != null && lastAccessTime.get() + jndiInfo.getIdleclose() < System.currentTimeMillis()) {
            if (debug)
                System.out.println(new Date() + " " + toString() + "/createConnection, close connection (idle close)");
            ((SwiftMQConnection) connection.get()).cancel(true);
            connection.set(null);
        }
    }

    public Object addToEnvironment(String name, Object value)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    private Versioned createVersioned(int version, JNDIRequest request) throws Exception {
        DataByteArrayOutputStream dos = new DataByteArrayOutputStream();
        Dumpalizer.dump(dos, request);
        return new Versioned(version, dos.getBuffer(), dos.getCount());
    }

    private BytesMessageImpl createMessage(Versionable versionable, Destination replyTo) throws Exception {
        BytesMessageImpl msg = new BytesMessageImpl();
        versionable.transferToMessage(msg);
        if (replyTo != null)
            msg.setJMSReplyTo(replyTo);
        return msg;
    }

    public void bind(String name, Object obj)
            throws NamingException {
        if (closed.get())
            throw new NamingException("context is closed!");
        if (!(obj instanceof TemporaryTopicImpl || obj instanceof TemporaryQueueImpl))
            throw new OperationNotSupportedException("bind is only supported for TemporaryQueues/TemporaryTopics!");
        try {
            checkConnection();
            TemporaryTopic tt = session.get().createTemporaryTopic();
            MessageConsumer consumer = session.get().createConsumer(tt);

            Versionable versionable = new Versionable();
            versionable.addVersioned(Versions.JNDI_CURRENT, createVersioned(Versions.JNDI_CURRENT, new BindRequest(name, (QueueImpl) obj)),
                    "com.swiftmq.jndi.protocol.v" + Versions.JNDI_CURRENT + ".JNDIRequestFactory");
            BytesMessage request = createMessage(versionable, tt);
            producer.get().send(session.get().createTopic(JNDISwiftlet.JNDI_TOPIC), request, DeliveryMode.NON_PERSISTENT, MessageImpl.MAX_PRIORITY, 0);
            TextMessage reply = (TextMessage) consumer.receive();
            String text = reply.getText();
            consumer.close();
            tt.delete();
            if (text != null)
                throw new Exception(text);
        } catch (Exception e) {
            throw new NamingException("exception occurred during bind: " + e);
        }
    }

    public void bind(Name p0, Object p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void close()
            throws NamingException {
        try {
            if (connection.get() != null) {
                if (debug)
                    System.out.println(new Date() + " " + toString() + "/close");
                connection.get().close();
            }
        } catch (Exception ignored) {
        }
        if (!jndiInfo.isIntraVM() && jndiInfo.getIdleclose() > 0)
            TimerRegistry.Singleton().removeTimerListener(1000, this);
        closed.set(true);
    }

    public String composeName(String p0, String p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Name composeName(Name p0, Name p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Context createSubcontext(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Context createSubcontext(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void destroySubcontext(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void destroySubcontext(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Hashtable getEnvironment()
            throws NamingException {
        return env;
    }

    public String getNameInNamespace()
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NameParser getNameParser(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NameParser getNameParser(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NamingEnumeration list(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NamingEnumeration list(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NamingEnumeration listBindings(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public NamingEnumeration listBindings(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    private Destination getLookupDestination(Session session) throws JMSException {
        if (Versions.JMS_CURRENT < 630)
            return session.createTopic(JNDISwiftlet.JNDI_TOPIC);
        return session.createQueue(JNDISwiftlet.JNDI_QUEUE);
    }

    public Object lookup(String name)
            throws NamingException {
        if (closed.get())
            throw new NamingException("context is closed!");
        if (name == null)
            throw new OperationNotSupportedException("context cloning is not supported!");
        boolean connectionClosed = false;
        Object obj = null;
        try {
            checkConnection();
            TemporaryQueue tq = session.get().createTemporaryQueue();
            MessageConsumer consumer = session.get().createConsumer(tq);

            Versionable versionable = new Versionable();
            versionable.addVersioned(Versions.JNDI_CURRENT,
                    createVersioned(Versions.JNDI_CURRENT, new LookupRequest(name)),
                    "com.swiftmq.jndi.protocol.v" + Versions.JNDI_CURRENT + ".JNDIRequestFactory");
            BytesMessage request = createMessage(versionable, tq);
            producer.get().send(getLookupDestination(session.get()), request, DeliveryMode.NON_PERSISTENT, MessageImpl.MAX_PRIORITY, 0);
            MessageImpl reply = null;
            if (jndiInfo.getTimeout() == 0)
                reply = (MessageImpl) consumer.receive();
            else
                reply = (MessageImpl) consumer.receive(jndiInfo.getTimeout());
            if (reply != null) {
                if (reply instanceof ObjectMessageImpl)
                    obj = ((ObjectMessageImpl) reply).getObject();
                else {
                    BytesMessageImpl msg = (BytesMessageImpl) reply;
                    Versionable vreply = Versionable.toVersionable(msg);
                    vreply.selectVersions(Versions.cutAfterIndex(Versions.getSelectedIndex(Versions.JMS_CURRENT, Versions.JMS), Versions.JMS));
                    obj = vreply.createVersionedObject();
                }
            }
            if (!((SwiftMQMessageConsumer) consumer).isClosed()) {
                consumer.close();
                tq.delete();
            } else
                connectionClosed = true;
        } catch (Exception e) {
            throw new CommunicationException("exception occurred during lookup: " + e);
        }
        if (connectionClosed)
            throw new CommunicationException("Connection lost!");
        if (obj == null)
            throw new NameNotFoundException("Name '" + name + "' not found (timeout occured)!");
        return obj;
    }

    public Object lookup(Name name)
            throws NamingException {
        return lookup(name.get(0));
    }

    public Object lookupLink(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Object lookupLink(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void rebind(String name, Object obj)
            throws NamingException {
        if (closed.get())
            throw new NamingException("context is closed!");
        if (!(obj instanceof TemporaryTopicImpl || obj instanceof TemporaryQueueImpl))
            throw new OperationNotSupportedException("rebind is only supported for TemporaryQueues/TemporaryTopics!");
        try {
            checkConnection();
            TemporaryTopic tt = session.get().createTemporaryTopic();
            MessageConsumer consumer = session.get().createConsumer(tt);

            Versionable versionable = new Versionable();
            versionable.addVersioned(Versions.JNDI_CURRENT,
                    createVersioned(Versions.JNDI_CURRENT, new RebindRequest(name, (QueueImpl) obj)),
                    "com.swiftmq.jndi.protocol.v" + Versions.JNDI_CURRENT + ".JNDIRequestFactory");
            BytesMessage request = createMessage(versionable, tt);
            producer.get().send(session.get().createTopic(JNDISwiftlet.JNDI_TOPIC), request, DeliveryMode.NON_PERSISTENT, MessageImpl.MAX_PRIORITY, 0);
            TextMessage reply = (TextMessage) consumer.receive();
            String text = reply.getText();
            consumer.close();
            tt.delete();
            if (text != null)
                throw new Exception(text);
        } catch (Exception e) {
            throw new NamingException("exception occurred during rebind: " + e);
        }
    }

    public void rebind(Name p0, Object p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public Object removeFromEnvironment(String p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void rename(String p0, String p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void rename(Name p0, Name p1)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }

    public void unbind(String name)
            throws NamingException {
        if (closed.get())
            throw new NamingException("context is closed!");
        try {
            checkConnection();
            Versionable versionable = new Versionable();
            versionable.addVersioned(400, createVersioned(400, new UnbindRequest(name)), "com.swiftmq.jndi.protocol.v400.JNDIRequestFactory");
            BytesMessage request = createMessage(versionable, null);
            producer.get().send(session.get().createTopic(JNDISwiftlet.JNDI_TOPIC), request, DeliveryMode.NON_PERSISTENT, MessageImpl.MAX_PRIORITY, 0);
        } catch (Exception e) {
            throw new NamingException("exception occurred during unbind: " + e);
        }
    }

    public void unbind(Name p0)
            throws NamingException {
        throw new OperationNotSupportedException("not supported");
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy