001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.util;
020
021import org.jpos.space.SpaceUtil;
022import org.jpos.space.TSpace;
023
024import java.io.PrintStream;
025import java.util.HashMap;
026import java.util.Map;
027
028/**
029 * Allow runtime binding of jPOS's components (ISOChannels, Logger, MUXes, etc)
030 *
031 * @author <a href="mailto:apr@cs.com.uy">Alejandro P. Revilla</a>
032 * @version $Revision$ $Date$
033 */
034public class NameRegistrar implements Loggeable {
035    private static final NameRegistrar instance = new NameRegistrar();
036    private static final TSpace<String, Object> sp = new TSpace<String,Object>();
037
038    /** Thrown when a requested name is not found in the registrar. */
039    public static class NotFoundException extends Exception {
040        private static final long serialVersionUID = 8744022794646381475L;
041
042        /** Default constructor. */
043        public NotFoundException() {
044            super();
045        }
046
047        /** Constructs a NotFoundException with the given detail message.
048         * @param detail the missing key or detail message
049         */
050        public NotFoundException(String detail) {
051            super(detail);
052        }
053    }
054
055    /** Private constructor — use the singleton. */
056    private NameRegistrar() {
057        super();
058    }
059
060    /** Returns the underlying TSpace used for name registration.
061     * @return the shared TSpace instance
062     */
063    public static TSpace<String, Object> getSpace() {
064        return sp;
065    }
066
067    /**
068     * Returns a copy of the NameRegistrar's entries as a Map.
069     * @return a copy of the NameRegistrar's entries as a Map
070     */
071    public static Map<String,Object> getAsMap() {
072        Map<String,Object> map = new HashMap<String,Object>();
073        for (String k : sp.getKeySet()) {
074            Object v  = sp.rdp(k);
075            if (v != null)
076                map.put(k,v);
077        }
078        return map;
079    }
080
081    /**
082     * Returns the singleton NameRegistrar instance.
083     * @return singleton instance
084     */
085    public static NameRegistrar getInstance() {
086        return instance;
087    }
088
089    /**
090     * register object
091     *
092     * @param key
093     *            - key with which the specified value is to be associated.
094     * @param value
095     *            - value to be associated with the specified key
096     */
097    public static void register(String key, Object value) {
098        sp.put(key, value);
099    }
100
101    /**
102     * Removes the mapping for the given key from the registrar.
103     * @param key
104     *            key whose mapping is to be removed from registrar.
105     */
106    public static void unregister(String key) {
107        SpaceUtil.wipe(sp, key);
108    }
109
110    /**
111     * Get a value from the registry.
112     *
113     * @param <T> desired type of entry value.
114     * @param key the key whose associated value is to be returned.
115     * @return a value
116     * @throws NotFoundException if key not present in registrar
117     */
118    public static <T> T get(String key) throws NotFoundException {
119        @SuppressWarnings("unchecked")
120        T obj = (T) sp.rdp(key);
121        if (obj == null) {
122            throw new NotFoundException(key);
123        }
124        return obj;
125    }
126
127    /**
128     * Get a value from the registry - wait for it specified time.
129     *
130     * @param <T> desired type of value.
131     * @param key the key whose associated value is to be returned.
132     * @param timeout the maximum waiting time (in miliseconds) for
133     * the appearance of value in the registry.
134     * @return a value or {@code null} if it does not exist
135     */
136    public static <T> T get(String key, long timeout) {
137        return (T) sp.rd(key, timeout);
138    }
139
140    /**
141     * Get a value from the registry - without casting {@code NotFoundException}.
142     *
143     * @param <T> desired type of value.
144     * @param key the key whose associated value is to be returned.
145     * @return a value or {@code null} if it does not exist
146     */
147    public static <T> T getIfExists(String key) {
148        @SuppressWarnings("unchecked")
149        T obj = (T) sp.rdp(key);
150        return obj;
151    }
152
153    /** Dumps a summary of registered names to the given stream.
154     * @param p output stream
155     * @param indent indent prefix
156     */
157    public void dump(PrintStream p, String indent) {
158        dump(p, indent, false);
159    }
160
161    /** Dumps registered names to the given stream, optionally including object detail.
162     * @param p output stream
163     * @param indent indent prefix
164     * @param detail if true, also dumps Loggeable objects
165     */
166    public void dump(PrintStream p, String indent, boolean detail) {
167        String inner = indent + "  ";
168        p.println(indent + "name-registrar:");
169        for (String key : sp.getKeySet()) {
170            Object obj = sp.rdp(key);
171            String objectClassName = obj == null ? "<NULL>" : obj.getClass().getName();
172            p.println(inner + key + ": " + objectClassName);
173            if (detail && obj instanceof Loggeable) {
174                try {
175                    ((Loggeable) obj).dump(p, inner + "  ");
176                } catch (Exception e) {         // typically a NPE may be thrown from badly-initialized objects
177                    p.println(e.getMessage());
178                }
179            }
180        }
181    }
182}