001 
002 /*
003  *  JScripter Emulation 1.0 - To Script Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package org.jscripter.emu.java;
021 
022 import js.ArrayLike;
023 import js.Js;
024 import js.Value;
025 import js.core.JsGlobal;
026 import jsx.core.ArrayLikes;
027 
028 /**
029  * <p>An <tt>internal</tt> class for the emulation of Java interface objects.</p>
030  * <p>This class is only used internally by JS re-compiler implementations.</p>
031  * 
032  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
033  * 
034  * @javascript This class is only loaded and resolved by re-compiler implementations.
035  */
036 public class JavaInterface extends JavaObject
037 {
038     /**
039      * <p>Internally stores the name of this Java interface or class object.</p>
040      * @since 1.0
041      * @javascript Re-compilers must report error on end-users directly using this field.
042      */
043     public ArrayLike<String> name;
044     /**
045      * <p>Internally stores all the super interfaces for this Java interface or class object.</p>
046      * @since 1.0
047      * @javascript Re-compilers must report error on end-users directly using this field.
048      */
049     public ArrayLike<JavaInterface> interfaces;
050 
051     /**
052      * <p>Internally returns a string representation for the current Java interface object.</p>
053      * @return The string representation for the current Java interface object.
054      * @since 1.0
055      * @javascript Re-compilers must report error on end-users directly using this method.
056      */
057     @Override
058     public String toString() {
059         return new Value.String("interface").add(" ").add(name).var();
060     }
061 
062     /**
063      * <p>Internally gets the name of a Java interface or class object.</p>
064      * @param ji A Java interface or class object.
065      * @return The name of the Java interface or class object.
066      * @since 1.0
067      * @javascript Re-compilers must report error on end-users directly using this method.
068      */
069     public static final String getName(JavaInterface ji) {
070         return ArrayLikes.join(ji.name, ".");
071     }
072 
073     /**
074      * <p>Internally gets the simple name of a Java interface or class object.</p>
075      * @param ji A Java interface or class object.
076      * @return The simple name of the Java interface or class object.
077      * @since 1.0
078      * @javascript Re-compilers must report error on end-users directly using this method.
079      */
080     public static final String getSimpleName(JavaInterface ji) {
081         ArrayLike<String> name = ji.name;
082         int len = ArrayLikes.length(name);
083         return name.get(len - 1);
084     }
085 
086     /**
087      * <p>Internally determines whether a Java object is an instance of a Java 
088      * interface or class object.</p>
089      * @param v A Java object.
090      * @param c A Java interface or class object.
091      * @return <tt>true</tt> if the Java object is an instance of the Java interface
092      * or class object; <tt>false</tt>, otherwise.
093      * @since 1.0
094      * @javascript Re-compilers must report error on end-users directly using this method.
095      */
096     public static final boolean instanceOf(Object v, JavaInterface c) {
097         return Js.be(v) && Js.instanceOf(v, JsGlobal.Object.with()) && (
098                 Js.be(((JavaClass)(java.lang.Object)c).constructor) ?
099                 Js.instanceOf(
100                         v, 
101                         ((JavaClass)(java.lang.Object)c).constructor
102                 ) : 
103                 Js.in(getName(c), v)
104         );
105     }
106 
107     /**
108      * <p>Internally determines whether a Java interface object represents a super
109      * interface of that another Java interface object does.</p>
110      * @param sup A Java interface object.
111      * @param sub A Java interface object.
112      * @return <tt>true</tt> if the 1st Java interface object represents a super interface
113      * of that the 2nd Java interface object does; <tt>false</tt>, otherwise.
114      * @since 1.0
115      * @javascript Re-compilers must report error on end-users directly using this method.
116      */
117     public static final boolean isSuperInterface(JavaInterface sup, JavaInterface sub) {
118         ArrayLike<JavaInterface> si = sub.interfaces;
119         if (Js.not(si)) {
120             return false;
121         } else if (ArrayLikes.indexOf(si, sup) != -1) {
122             return true;
123         }
124         for (int i = 0, len = ArrayLikes.length(si); i < len; i++) {
125             if (isSuperInterface(sup, si.get(i))) {
126                 return true;
127             }
128         }
129         return false;
130     }
131 
132     /**
133      * <p>Internally creates a Java interface object by its name.</p>
134      * @param name Represents the name of a Java interface.
135      * @return The newly created Java interface object.
136      * @since 1.0
137      * @javascript Re-compilers must report error on end-users directly using this method.
138      */
139     protected final static JavaInterface createInterface(ArrayLike<String> name) {
140         JavaInterface oi = new JavaInterface();
141         oi.name = name;
142         return oi;
143     }
144 
145     /**
146      * <p>Internally casts an object to a Java interface or class represented by a
147      * given Java interface object.</p>
148      * @param o An object to cast.
149      * @param c A Java interface object.
150      * @return The object itself.
151      * @throws A {@link ClassCastException} exception if the cast fails.
152      * @since 1.0
153      * @javascript Re-compilers must report error on end-users directly using this method.
154      */
155     protected final static Object checkCast(Object o, JavaInterface c) {
156         return Js.cond(
157                 Js.be(o),
158                 returnOrThrow(
159                         JavaInterface.instanceOf(o, c),
160                         JavaInterface.getName(c),
161                         o
162                 ),
163                 o
164         );
165     }
166 
167     private static Object returnOrThrow(boolean test, String message, Object o) {
168         if (!test) {
169             ClassCastException cce = new ClassCastException(
170                     new Value.String(o.getClass().getName())
171                              .add(":")
172                              .add(message)
173                              .var()
174             );
175             Js.alert(cce.getMessage());
176             throw cce;
177         }
178         return o;
179     }
180 }