001/*
002 * This file is part of the Kompics component model runtime.
003 * 
004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
005 * Copyright (C) 2009 Royal Institute of Technology (KTH)
006 *
007 * Kompics is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU General Public License
009 * as published by the Free Software Foundation; either version 2
010 * of the License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with this program; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
020 */
021package se.sics.kompics;
022
023import java.util.HashMap;
024import java.util.HashSet;
025import java.util.Set;
026
027/**
028 * The <code>PortType</code> class.
029 * 
030 * @author Cosmin Arad {@literal <[email protected]>}
031 * @author Jim Dowling {@literal <[email protected]>}
032 */
033public abstract class PortType {
034
035    private static HashMap<Class<? extends PortType>, PortType> map = new HashMap<Class<? extends PortType>, PortType>();
036
037    private Set<Class<? extends KompicsEvent>> positive = new HashSet<Class<? extends KompicsEvent>>();
038    private Set<Class<? extends KompicsEvent>> negative = new HashSet<Class<? extends KompicsEvent>>();
039
040    Class<? extends PortType> portTypeClass;
041
042    /**
043     * Gets the port type.
044     * 
045     * @param <P>
046     *            the type of the port type
047     * @param portTypeClass
048     *            the port type class
049     * 
050     * @return the port type
051     */
052    @SuppressWarnings("unchecked")
053    public static <P extends PortType> P getPortType(Class<P> portTypeClass) {
054        P portType = (P) map.get(portTypeClass);
055        if (portType == null) {
056            try {
057                portType = portTypeClass.newInstance();
058                map.put(portTypeClass, portType);
059            } catch (InstantiationException e) {
060                throw new RuntimeException("Cannot create port type " + portTypeClass.getCanonicalName(), e);
061            } catch (IllegalAccessException e) {
062                throw new RuntimeException("Cannot create port type " + portTypeClass.getCanonicalName(), e);
063            }
064        }
065        return portType;
066    }
067
068    /**
069     * Forces the singleton instance of the port to be loaded.
070     * 
071     * Mostly meant for use with Kompics Scala.
072     * 
073     * @param p
074     *            the port type to load
075     */
076    public static void preloadInstance(PortType p) {
077        map.put(p.getClass(), p);
078    }
079
080    /**
081     * Specifies an indication, response, or confirmation event type.
082     * 
083     * @param eventType
084     *            the event type
085     */
086    protected final void positive(Class<? extends KompicsEvent> eventType) {
087        positive.add(eventType);
088    }
089
090    /**
091     * Specifies an indication, response, or confirmation event type.
092     * 
093     * @param eventType
094     *            the event type
095     */
096    protected final void indication(Class<? extends KompicsEvent> eventType) {
097        positive.add(eventType);
098    }
099
100    /**
101     * Specifies a request, or instruction event type.
102     * 
103     * @param eventType
104     *            the event type
105     */
106    protected final void negative(Class<? extends KompicsEvent> eventType) {
107        negative.add(eventType);
108    }
109
110    /**
111     * Specifies a request, or instruction event type.
112     * 
113     * @param eventType
114     *            the event type
115     */
116    protected final void request(Class<? extends KompicsEvent> eventType) {
117        negative.add(eventType);
118    }
119
120    /**
121     * Checks for positive.
122     * 
123     * @param eventType
124     *            the event type
125     * 
126     * @return true, if successful
127     */
128    public final boolean hasPositive(Class<? extends KompicsEvent> eventType) {
129        if (positive.contains(eventType)) {
130            return true;
131        }
132        for (Class<? extends KompicsEvent> eType : positive) {
133            if (eType.isAssignableFrom(eventType)) {
134                return true;
135            }
136        }
137        return false;
138    }
139
140    /**
141     * Checks for negative.
142     * 
143     * @param eventType
144     *            the event type
145     * 
146     * @return true, if successful
147     */
148    public final boolean hasNegative(Class<? extends KompicsEvent> eventType) {
149        if (negative.contains(eventType)) {
150            return true;
151        }
152        for (Class<? extends KompicsEvent> eType : negative) {
153            if (eType.isAssignableFrom(eventType)) {
154                return true;
155            }
156        }
157        return false;
158    }
159
160    /**
161     * Checks for event.
162     * 
163     * @param positive
164     *            the positive
165     * @param eventType
166     *            the event type
167     * 
168     * @return true, if successful
169     */
170    public final boolean hasEvent(boolean positive, Class<? extends KompicsEvent> eventType) {
171        return (positive == true ? hasPositive(eventType) : hasNegative(eventType));
172    }
173
174    /**
175     * Get all positive (indication) events.
176     * 
177     * @return a set of all positive events
178     */
179    Set<Class<? extends KompicsEvent>> getPositiveEvents() {
180        return positive;
181    }
182
183    /**
184     * Get all negative (request) events.
185     * 
186     * @return a set of all negative events
187     */
188    Set<Class<? extends KompicsEvent>> getNegativeEvents() {
189        return negative;
190    }
191
192    /*
193     * (non-Javadoc)
194     * 
195     * @see java.lang.Object#toString()
196     */
197    @Override
198    public final String toString() {
199        return getClass().getCanonicalName() + " = Positive: " + positive.toString() + ", Negative: "
200                + negative.toString();
201    }
202}