1 /*
   2  * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.apple.jobjc;
  26 
  27 import java.lang.ref.WeakReference;
  28 import java.lang.reflect.Constructor;
  29 
  30 import javax.tools.annotation.GenerateNativeHeader;
  31 
  32 /* No native methods here, but the constants are needed in the supporting JNI code */
  33 @GenerateNativeHeader
  34 public class NSClass<T extends ID> extends ID {
  35     /* No native methods here, but the constants are needed in the supporting JNI code */
  36     @GenerateNativeHeader
  37     public static class NSClassNotFoundException extends RuntimeException{
  38         public NSClassNotFoundException(String m){ super(m); }
  39         public NSClassNotFoundException(String m, Throwable cause){ super(m, cause); }
  40     }
  41 
  42     static native long getNativeClassByName(String name);
  43     static native long getSuperClassOfClass(long classPtr);
  44     static native String getClassNameOfClass(long classPtr);
  45     static native long getClass(long objPtr);
  46 
  47     public NSClass(final long ptr, final JObjCRuntime runtime) {
  48         super(ptr, runtime);
  49     }
  50 
  51     public NSClass(final String name, final JObjCRuntime runtime) {
  52         this(getNativeClassByName(name), runtime);
  53         if(ptr == 0) throw new NSClassNotFoundException("NSClass pointer is 0. Found no class named " + name);
  54     }
  55 
  56     protected NSClass(final JObjCRuntime runtime){
  57         super(0, runtime);
  58         final String sn = getClass().getSimpleName();
  59         final String name = sn.substring(0, sn.lastIndexOf("Class"));
  60         ptr = getNativeClassByName(name);
  61         if(ptr == 0) throw new NSClassNotFoundException("NSClass pointer is 0. Found no class named " + name);
  62     }
  63 
  64     NSClass<? super T> getSuperClass() {
  65         return new NSClass<T>(getSuperClassOfClass(ptr), runtime);
  66     }
  67 
  68     String getClassName() { return getClassNameOfClass(ptr); }
  69 
  70     @Override protected NativeObjectLifecycleManager getNativeObjectLifecycleManager() {
  71         return NativeObjectLifecycleManager.Nothing.INST;
  72     }
  73 
  74     @Override public boolean equals(Object o){
  75         return (o instanceof NSClass) && (this.ptr == ((NSClass) o).ptr);
  76     }
  77 
  78     //
  79 
  80     static <T extends NSClass> T getObjCClassFor(final JObjCRuntime runtime, final long clsPtr){
  81         if (clsPtr == 0) return null;
  82 
  83         final WeakReference cachedObj = objectCache.get().get(clsPtr);
  84         if(cachedObj != null && cachedObj.get() != null) return (T) cachedObj.get();
  85 
  86         final T newObj = (T) createNewObjCClassFor(runtime, clsPtr);
  87         objectCache.get().put(clsPtr, new WeakReference(newObj));
  88         return newObj;
  89     }
  90 
  91     static <T extends NSClass> T createNewObjCClassFor(final JObjCRuntime runtime, final long clsPtr) {
  92         final Constructor<T> ctor = getNSClassConstructorForClassPtr(runtime, clsPtr);
  93         return (T) createNewObjCObjectForConstructor(ctor, clsPtr, runtime);
  94     }
  95 
  96     @SuppressWarnings("unchecked")
  97     static <T extends NSClass> Constructor<T> getNSClassConstructorForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
  98         final Class<T> clazz = getNSClassForClassPtr(runtime, clazzPtr);
  99         Constructor<T> ctor;
 100         try {
 101             ctor = clazz.getDeclaredConstructor(CTOR_ARGS);
 102         } catch (SecurityException e) {
 103             throw new RuntimeException(e);
 104         } catch (NoSuchMethodException e) {
 105             throw new RuntimeException(e);
 106         }
 107         ctor.setAccessible(true);
 108         return ctor;
 109     }
 110 
 111     @SuppressWarnings("unchecked")
 112     static <T extends ID> Class<T> getNSClassForClassPtr(final JObjCRuntime runtime, final long clazzPtr){
 113         final String className = NSClass.getClassNameOfClass(clazzPtr);
 114         final Class<T> clazz = (Class<T>) runtime.getClassForNativeClassName(className + "Class");
 115         if(clazz == null){
 116             final long superClazzPtr = NSClass.getSuperClassOfClass(clazzPtr);
 117             if(superClazzPtr != 0)
 118                 return getNSClassForClassPtr(runtime, superClazzPtr);
 119         }
 120         return clazz;
 121     }
 122 }