#!/usr/bin/env python # # MIT License # # Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ Real-world test (courtesy Leanid Nazdrynau) of the multi-step capabilities of the various Java Builders. TODO: the whole Applet facility is deprecated, need a new test. """ import os import pathlib import TestSCons test = TestSCons.TestSCons() where_javac, java_version = test.java_where_javac() where_javah = test.java_where_javah() where_java_include=test.java_where_includes() swig = test.where_is('swig') if not swig: test.skip_test('Can not find installed "swig", skipping test.\n') # Skip this test on AppVeyor # Skip this test as SCons doesn't (currently) predict the generated # inner/anonymous class generated .class files generated by gcj # and so will always fail if test.javac_is_gcj: test.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n') # TODO rework for 'javac -h', for now skip # The logical test would be: if java_version > 9: # but java_where_javah() roots around and will find from an older version if not test.Environment().WhereIs('javah'): test.skip_test("No Java javah for version > 9, skipping test.\n") # On some systems, the alternatives system does not remove javah even if the # preferred Java doesn't have it, so try another check javacdir = pathlib.Path(where_javac).parent javahdir = pathlib.Path(where_javah).parent if javacdir != javahdir: test.skip_test("Cannot find Java javah matching javac, skipping test.\n") test.subdir( ['src'], ['src', 'HelloApplet'], ['src', 'HelloApplet', 'com'], ['src', 'javah'], ['src', 'jni'], ['src', 'server'], ['src', 'server', 'JavaSource'], ['src', 'server', 'JavaSource', 'com'], ['src', 'server', 'JavaSource', 'com', 'gnu'], ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons'], ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web'], ['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools'], ['src', 'server', 'WebContent'], ['src', 'server', 'WebContent', 'META-INF'], ['src', 'server', 'WebContent', 'WEB-INF'], ['src', 'server', 'WebContent', 'WEB-INF', 'conf'], ['src', 'server', 'WebContent', 'WEB-INF', 'lib'], ['src', 'server', 'WebContent', 'theme'], ) test.write(['SConstruct'], """\ import os, sys if sys.platform == 'win32': # Ensure tests don't pick up link from mingw or cygwin tools = ['msvc', 'mslink', 'jar', 'javac', 'javah', 'swig'] else: tools = ['default', 'javac', 'javah', 'swig'] env = Environment(tools=tools, CPPPATH=["$JAVAINCLUDES"]) Export('env') # env.PrependENVPath('PATH',os.environ.get('PATH',[])) env['INCPREFIX'] = '-I' env.Append(SWIGFLAGS=['-c++', '$_CPPINCFLAGS']) # this is for JNI # env.Append(CCFLAGS=['/IN:/jdk/v1.3.1/include','/IN:/jdk/v1.3.1/include/win32']) # this for windows only C++ build # env.Append(CXXFLAGS='-GX') env.Append(CPPPATH='.') env.VariantDir('buildout', 'src', duplicate=0) if sys.platform[:6] == 'darwin': env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers']) # If you do not have swig on your system please remove # 'buildout/jni/SConscript' line from next call env.SConscript( [ 'buildout/server/JavaSource/SConscript', 'buildout/HelloApplet/SConscript', 'buildout/jni/SConscript', 'buildout/javah/SConscript', ] ) """ % locals()) test.write(['src', 'HelloApplet', 'Hello.html'], """\ Applet Hello
""") test.write(['src', 'HelloApplet', 'SConscript'], """\ import os Import("env") denv = env.Clone() classes = denv.Java(target='classes', source=['com']) # set correct path for jar denv['JARCHDIR'] = os.path.join(denv.Dir('.').get_abspath(), 'classes') denv.Jar('HelloApplet', classes) # To sign applet you have to create keystore before and made a calls like this # keystore='/path/to/jarsignkey' # denv['JARSIGNFLAGS']='-keystore '+keystore+' -storepass pass -keypass passkey' # denv['JARSIGNALIAS']='ALIAS' # denv['JARCOM']=[denv['JARCOM'],'$JARSIGNCOM'] """) test.write(['src', 'HelloApplet', 'com', 'Hello.java'], """\ package com.Hello; import java.awt.*; import java.applet.*; public class Hello extends Applet { static final long serialVersionUID = 0; public void paint(Graphics g) { g.drawString("Hello from SCons signed applet",250,150); } } """) test.write(['src', 'javah', 'MyID.cc'], """\ #include "MyID.h" #ifdef _MSC_VER __declspec(dllexport) #endif int getMyID() { return 0; } """) test.write(['src', 'javah', 'MyID.java'], """\ public class MyID { static private long current = System.currentTimeMillis(); static public String get() { current++; return new Long( current ).toString(); } } """) test.write(['src', 'javah', 'SConscript'], """\ Import('env') denv = env.Clone() denv['JARCHDIR'] = denv.Dir('.').get_abspath() denv.Jar('myid', 'MyID.java') denv.JavaH(denv.Dir('.').get_abspath(), 'MyID.java') denv.SharedLibrary('myid', 'MyID.cc') """) test.write(['src', 'jni', 'A.java'], """\ package web.jni; public class A { class C { void echo2( String text ) { System.out.println( text+"aa" ); } } class B { void echo( String text ) { System.out.println( text ); C c = new C(); c.echo2("from B callin C"); } } public void main( String[] x) { B b = new B(); b.echo("123"); C c = new C(); c.echo2("456"); } } """) test.write(['src', 'jni', 'JniWrapper.cc'], """\ #include #include #include "JniWrapper.h" JniWrapper::JniWrapper( JNIEnv *pEnv ) : mpEnv( pEnv ) { } JniWrapper::JniWrapper( const JniWrapper& rJniWrapper ) : mpEnv( rJniWrapper.mpEnv ) { } JniWrapper::~JniWrapper() { } JniWrapper& JniWrapper::operator=( const JniWrapper& rJniWrapper ) { if ( this != &rJniWrapper ) { mpEnv = rJniWrapper.mpEnv; } return *this; } std::string JniWrapper::unmarshalString( jstring value ) { std::string result; if( value ) { const char *pStr = mpEnv->GetStringUTFChars( value, 0 ); result = pStr; mpEnv->ReleaseStringUTFChars( value, pStr ); } return result; } jobject JniWrapper::marshalDouble( double value ) { jclass classObject = mpEnv->FindClass( "java/lang/Double" ); jmethodID constructorId = mpEnv->GetMethodID( classObject, "", "(D)V" ); jobject result = mpEnv->NewObject( classObject, constructorId, value ); return result; } jobject JniWrapper::getVectorElement( jobject values, int i ) { jclass vectorClass = mpEnv->FindClass( "java/util/Vector" ); jmethodID methodID = mpEnv->GetMethodID( vectorClass, "elementAt", "(I)Ljava/lang/Object;" ); jobject result = mpEnv->CallObjectMethod( values, methodID, i ); return result; } jobject JniWrapper::newVector() { jclass vectorClass = mpEnv->FindClass( "java/util/Vector" ); jmethodID constructorID = mpEnv->GetMethodID( vectorClass, "", "()V" ); jobject result = mpEnv->NewObject( vectorClass, constructorID ); return result; } void JniWrapper::addElement( jobject vector, jobject element ) { jclass vectorClass = mpEnv->FindClass( "java/util/Vector" ); jmethodID addElementMethodID = mpEnv->GetMethodID( vectorClass, "addElement", "(Ljava/lang/Object;)V" ); mpEnv->CallVoidMethod( vector, addElementMethodID, element ); } jobject JniWrapper::marshalDoubleVector( const std::vector& rVector ) { jobject result = newVector(); for ( int i = 0; i < rVector.size(); i++ ) { addElement( result, marshalDouble( rVector[i] ) ); } return result; } std::pair JniWrapper::unmarshalPairString( jobject vector ) { std::pair result; result.first = unmarshalString( (jstring)getVectorElement( vector, 0 ) ); result.second = unmarshalString( (jstring)getVectorElement( vector, 1 ) ); return result; } """) test.write(['src', 'jni', 'JniWrapper.h'], """\ #ifndef JniWrapper_h #define JniWrapper_h #include /** * Provides routines for dealing with JNI translation etc. */ class JniWrapper { public: JniWrapper( JNIEnv *pEnv ); JniWrapper( const JniWrapper& rJniWrapper ); virtual ~JniWrapper(); JniWrapper& operator=( const JniWrapper& rJniWrapper ); std::string unmarshalString( jstring value ); jstring marshalString( const std::string& value ); jbyteArray marshalByteArray( const std::string& value ); double unmarshalDouble( jobject value ); jobject marshalDouble( double value ); jobject marshallStringVector( const std::vector& rMap ); jobject marshalDoubleVector( const std::vector& rVector ); std::pair unmarshalPairString( jobject ); protected: JNIEnv *mpEnv; private: JniWrapper(); jobject newVector(); void addElement( jobject vector, jobject element ); jobject getVectorElement( jobject values, int i ); }; #endif // JniWrapper_h """) test.write(['src', 'jni', 'SConscript'], """\ Import("env") denv = env.Clone() denv.Append(SWIGFLAGS=['-java']) denv.SharedLibrary('scons', ['JniWrapper.cc', 'Sample.i']) denv['JARCHDIR'] = denv.Dir('.').get_abspath() denv.Jar(['Sample.i', 'A.java']) """) test.write(['src', 'jni', 'Sample.h'], """\ #include #include class SampleTest { public: std::vector test1( std::pair param ) { std::vector result; result.push_back(10); return result; } }; """) test.write(['src', 'jni', 'Sample.i'], """\ %module Sample %{ #include "Sample.h" #include "JniWrapper.h" %} %typemap(jni) std::vector, std::vector& "jobject" %typemap(jtype) std::vector, std::vector& "java.util.Vector" %typemap(jstype) std::vector, std::vector& "java.util.Vector" // return a Vector of Doubles %typemap(javaout) std::vector { return $jnicall; } %typemap(out) std::vector { JniWrapper JniWrapper(jenv); $result = JniWrapper.marshalDoubleVector( $1 ); } /********************************************************************* * * Pairs of String (IN/OUT) * *********************************************************************/ %typemap(jni) std::pair, const std::pair& "jobject" %typemap(jtype) std::pair, const std::pair& "java.util.Vector" %typemap(jstype) std::pair, const std::pair& "java.util.Vector" %typemap(javain) std::pair, const std::pair& "$javainput" // pass in by reference a Vector of std::string %typemap(in) const std::pair& { $1 = new std::pair(); JniWrapper JniWrapper(jenv); *($1) = JniWrapper.unmarshalPairString( $input ); } //cleanup %typemap(freearg) const std::pair& { delete $1; } %include "Sample.h" // generate:Sample.java // generate:SampleJni.java // generate:SampleTest.java """) test.write(['src', 'server', 'JavaSource', 'SConscript'], """\ import os Import ("env") classes=env.Java(target='classes',source=['com']) HelloApplet=os.path.join('#/buildout/HelloApplet/HelloApplet.jar') env['WARXFILES']=['SConscript','.cvsignore'] env['WARXDIRS']=['CVS'] #env.War('scons',[classes,Dir('../WebContent'),HelloApplet]) """) test.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'Bool.java'], """\ package com.gnu.scons.web.tools; public class Bool { boolean flag; public Bool() { flag = false; } public Bool( boolean aFlag ) { flag = aFlag; } public boolean booleanValue() { return flag; } } """) test.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'StringUtils.java'], """\ package com.gnu.scons.web.tools; public class StringUtils { public static String toPercent( String value ) { if ( value.equals("") ) { return ""; } else { return value + "%"; } } } """) test.write(['src', 'server', 'WebContent', 'index.html'], """\ index.html

go?action=home

""") test.write(['src', 'server', 'WebContent', 'META-INF', 'MANIFEST.MF'], """\ Manifest-Version: 1.0 Class-Path: """) test.write(['src', 'server', 'WebContent', 'WEB-INF', 'web.xml'], """\ scons WebExample WebExample com.gnu.scons.web.tool.WebExample WebExample /go index.html index.htm """) test.write(['src', 'server', 'WebContent', 'WEB-INF', 'conf', 'app.properties'], """\ logging = webExample.Example """) test.write(['src', 'server', 'WebContent', 'theme', 'Master.css'], """\ body { font-family: Helvetica,Sans-Serif; font-size: 11pt; } """) test.run(arguments = '.') test.must_exist(['buildout', 'javah', 'myid.jar']) test.must_exist(['buildout', 'javah', 'MyID', 'MyID.class']) test.must_exist(['buildout', 'jni', 'Sample.class']) test.must_exist(['buildout', 'jni', 'Sample.java']) test.must_exist(['buildout', 'jni', 'SampleJNI.class']) test.must_exist(['buildout', 'jni', 'SampleJNI.java']) test.must_exist(['buildout', 'jni', 'SampleTest.java']) # Some combinations of Java + SWIG apparently don't actually generate # a SampleTest.class file, while others do. Only issue a warning if # it doesn't exist. p = test.workpath('buildout', 'jni', 'SampleTest.class') if not os.path.exists(p): print('Warning: %s does not exist' % p) test.up_to_date(arguments = '.') test.pass_test() # Local Variables: # tab-width:4 # indent-tabs-mode:nil # End: # vim: set expandtab tabstop=4 shiftwidth=4: