Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Friday, February 8, 2008

How to Connect to an Excel Spreadsheet Using JDBC-ODBC Bridge Driver?

JDBC-ODBC can be used to access MS Excel spreadsheets as if they were databases, and thus we could utilize the power of SQL.

There are two ways to connect to a spreadsheet file using jdbc-odbc: Using DSN connection and Using DSN-less connection. The main difference is the construction of JDBC URL.

1. Using DSN connection

To use DSN connection, we firstly need to set up the Excel Spreadsheet as an ODBC source by using Windows Administrative Tools. The details of creating a User DSN can be found from here. Once the DSN is defined, we can interact the target spreadsheet file using jdbc-odbc. The db connection string is (please refer the complete sample for details ):

java.sql.Connection c = java.sql.DriverManager.getConnection( "jdbc:odbc:qa", "", "" );

“qa” is the name of DSN which points at a spreadsheet file which is going to be processed.

2. Using DSN-less connection

It is also possible to connect to a spreadsheet without using DSN, which provides a more flexible way within code to point JDBC at an Excel file of interest without the accesses to a client registry to define the required DSN. Without DSN, the db connection is created as following, please not the difference of constructed JDBC URL:

java.sql.DriverManager.getConnection( "jdbc:odbc:Driver={Microsoft Excel Driver (*.xls)};DBQ=C:/Documents and Settings/myPath/Desktop/qa.xls");

Here DBQ defines the path to the target spreadsheet file (qa.xls). Both backslash and forward slash work well.

With using DSN, we need easy access to a client registry to define the required DSN, while jdbc-odbc driver provide a more flexible method to connect to spreadsheet files without DSN.

3. A complete example of connecting to a spreadsheet using JDBC-ODBC

Here is a complete sample of connecting to a Spreadsheet file using JDBC

import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.DriverManager;

public class ExcelReader
{
public static void main( String [] args )
{
Connection c = null;
Statement stmnt = null;

try
{
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" );

//using DSN connection. Here qa is the name of DSN
//c = DriverManager.getConnection( "jdbc:odbc:qa", "", "" );

//using DSN-less connection
c = DriverManager.getConnection( "jdbc:odbc:Driver={Microsoft Excel Driver (*.xls)};DBQ=C:/Documents and Settings/tangk1.FIC/Desktop/qa.xls");


stmnt = c.createStatement();
String query = "select * from [qas test$] where Month='March' and Year=2001;";
ResultSet rs = stmnt.executeQuery( query );

System.out.println( "Found the following URLs:" );
while( rs.next() )
{
System.out.println( rs.getString( "URL" ) + " " + rs.getInt("Year"));
}
}
catch( Exception e )
{
System.err.println( e );
}
finally
{
try
{
stmnt.close();
c.close();
}
catch( Exception e )
{
System.err.println( e );
}
}
}
}

Reference:

JDBC-ODBC Bridge Driver Enables Spreadsheet-as-database Interaction ( http://www.devx.com/Java/Article/17848)

Sunday, October 14, 2007

Rename/Move Files Using java.io.File API

1. Rename a File in Place

Rename a file in the original place is trivial by using renameTo() method in java.io.File class. The following code snapshot will change a file name from “oldName.pdf” to “newName.pdf”:

String oldName = “oldName.pdf”;
String newName = “newName.pdf”;

File f = new File(oldName);
f.renameTo(newName);

2. Rename/Move a File to an Existing Directory

It is also easy to rename a file, and move the file to an existing directory. The following code will change the file name from “oldName.pdf” to “newName.pdf”, and also move the file from “C:\oldDir” to “C:\newDirsubDir” provide “C:\newDir\subDir” exists:

String oldDir = “C:\\oldDir\\”;
String oldName = “oldName.pdf”;

String newDir = “C:\\oldDir\subDir\\”;
String newName = “newName.pdf”;

File f = new File (oldDir, oldName);

f.renameTo(newDir + newName);


The last line of code will rename and also move the file to newDir , C:\newDir\subDir.

3. Rename/Move a File to an Directory that does not exist

The piece of code above won’t work if C:\newDir\subDir\ does not exist. However, we still can achieve our goal by a little more work. Here is how we do:

String oldDir = “C:\\oldDir\\”;
String oldName = “oldName.pdf”;

String newDir = “C:\\oldDir\\subDir\\”;
File pDir = new File(newDir);
pDir.mkroots();

String newName = “newName.pdf”;

File f = new File (oldDir, oldName);
f.renameTo(newDir + newName);

The last two lines of code in red will create all directories along the path if they do not exist, and then rename and move the file to the new directory.

Tuesday, August 7, 2007

Comparison of C++ and Java (VIII): Vtable vs. Method Invocation Table and Binary Compatibility (1)

Both Java and C++ have mechanisms to support dynamic polymorphism via run-time method binding, C++ uses vtable to achieve this goal while Java is by method invocation table. The difference of these two mechanisms leads to the different behaviours regarding to binary compatibility.

A vtable exmple

in C++, a vtable contains the addresses of the object's dynamically bound methods. Method calls are performed by fetching the method's address from the object's vtable. The vtable is the same for all objects belonging to the same class, and is therefore typically shared between them.

Considering the following example. Class A defines one virtual function methodA which just prints out a silly message:


A.h

class A{

public:
A(){}
virtual void methodB();
};

A.cc

void A::methodA(){
cout<<"print from method A "<<endl;
};

The vtable of A looks like:

vtable layout of class A:

A::_ZTV1A: 3u entries
0 0u
8 (int (*)(...))(&_ZTI1A)
16 A::methodA

The offset of A::methodA is 16.

Here is a test class to reference class A:

test.cc

int main (int argc, char *argv[]){
A* a = new A();
a->methodA();
}


We compile and link program by the following three steps:

>>g++ -c A.cc
>>g++ -c test.cc
>>g++ A.o test.o –o test

and run test program
>>./test

and get output:
>>Print from method A

In the example above, method call a->methodA fetches methodA from a address with offset 16.

Adding a virtual method breaks binary compatibility in C++

To show this, we add a virtual function methodB to class A right BEFORE methodA :

A.h

class A{
public:
A(){}
virtual void methodB(); // a new added function
virtual void methodA();
};

A.cc

void A::methodA(){
cout<<"print from method A "<<endl;
}

void A::methodB(){
cout<<"print from method B "<<endl;
}

Then we recompile class A BUT NOT class test, and link them again:

>>g++ -c A.cc
>>g++ A.o test.o –o test

Then we run test program:
>>./test

and get out put:
>>Print from method B

Why not " Print from method A" as I would expect? Let's take a look at the vtable of the revised class A:

vtable of revised class A

A::_ZTV1A: 4u entries
0 0u
8 (int (*)(...))(&_ZTI1A)
16 A::methodB
24 A::methodA

Note the address of methodA is now with offset 24, while the address of 16 is occupied by methodB. If we execute test program without recompilation, the address with offset 16 is still referenced and thus methodB gets called.

This problem shown above is known as "constant recompilation problem" and is usually considered as a side effect of C++: because C++ compiler references methods or variables by numeric offset at compilation time, sometimes we add a new method or a new instance variable to a class, any and all classes that reference that class will require a recompilation, or they break.







Monday, July 30, 2007

Comparisons of C++ and Java (VII): An Example of Desirable Data Hiding

In many of my readings, data hidings are said undesirable and are not encouraged. However, I at some circumstance, data hidings can make things simpler. For example, in my work, I need to implement an application with classes relationship looks like:


A
/ \
C B
/ | \
B1 B2 B3


Class A is the base class, class B and C are subclasses of A, and class B1, B2 and B3 are subclasses of B. Base class A is defined as:

A.h

class A{
public:
A(){}
static int id;
virtual void doSomething();
virtual int getId(){return ++id;}
};

A.cc

int A::id=0;
void A::doSomething(){
for (int k = 0; k<10; k++)
cout<<"id is : "<<getId()<<endl;
}



Here method doSomething simply print out ids. We want class B and C have their own id sequences, and all class B's share the same id sequences. That is both B and C classes' ids should start from 1. Class B1, B2, and B3 will share the same id sequence. To achieve this, We can design class C and B as following:

B.h

class B:public A{
public:
B(){}
static int id;
virtual int getId()
{
return ++id;
}

B.cc
int B::id=0;


Since data member id is defined again in both class C and B, A/id is hidden and inaccessible from both classes. Each class holds their own data id which starts from 0;

For class B's subclasses, we want them to share the same id sequence, so we DO NOT want to hide the id from class B. class B1, B2 and B3 are defined as following:

B1.h

class B1:public B{
public:
B1(){}
};

B2.h

class B2:public B{
public:
B2(){}
};

B3.h

class B3:public B{
public:
B3(){}
};


And the following test code generate some results that is what we expect:


C* c = new C();
B1* b1 = new B1();
B2* b2 = new B2();
B3* b3 = new B3();

cout<<"In class C, ids are: "<<endl;
c->doSomething();
cout<<"In class B1, ids are:"<<endl;
b1->doSomething();
cout<<"In class B2, ids are: "<<endl;
b2->doSomething();


The result looks like:


In class C, ids are:
id is : 1
id is : 2
id is : 3
id is : 4
id is : 5
id is : 6
id is : 7
id is : 8
id is : 9
id is : 10
In class B1, ids are:
id is : 1
id is : 2
id is : 3
id is : 4
id is : 5
id is : 6
id is : 7
id is : 8
id is : 9
id is : 10
In class B2, ids are:
id is : 11
id is : 12
id is : 13
id is : 14
id is : 15
id is : 16
id is : 17
id is : 18
id is : 19
id is : 20
In class B3, ids are:
id is : 21
id is : 22
id is : 23
id is : 24
id is : 25
id is : 26
id is : 27
id is : 28
id is : 29
id is : 30


There may be many other ways to achieve the same goal, but I found this solution is so simple and easy to understand and implement.


In Java, we can do the exactly same thing except a little change in the syntax. I am not going to bother to write the code.


In both Java and C++, the mechanism of data hiding from inheritance is called implicitly data hiding. In C#, it is said we can do explicitly data hiding by using "new" modifier. I think it is a cool feature in the language because I can tell the compiler I am doing data hiding on purpose.

Saturday, July 7, 2007

Comparisons of C++ and Java (VI): Constant Modifier

Constant modifier is const in C++ and final in Java. However, const and final are not equivalent at any situations (In C++, we can also define a constant by using the #define preprocessor directive, but I am not going to discuss it here)


1. For primitive data type,
const and final have the same meaning, that is the variable can only be assigned once and its value cannot be changed. For instance:


const int i = 10;

in C++ is equivalent to


final int i = 10;

in Java. It illegal to modify the variable after its initialization in both cases.


2. However,
for non-primitive data type (reference data type in Java, structured data types and address types in C++), const and final are different.

Let take a look at some examples. In Java, this piece of code is perfectly legal:


final int[] ary = {1, 2, 3, 4, 5};
ary[4] = 6; //legal

However in C++, this piece of code:


const int ary[] = {1, 2, 3, 4, 5};
ary[4] = 6; // illegal. compilation-time error

will generate compilation-time error:

Error: assignment of read-only location.


3. Why const and final are different regarding to non-primitive datatype?

For mathematics, a constant is a value that never changes, thereby remaining a fixed value. So in C++, a constant is a REAL constant. const is infectious. A const modifier ensures that the object is immutable (It is called Const Correctness in C++). When const keyword is involved when used with pointers or references, we can't modify what the pointer points to or the reference refers to.

While, there is no such const correctness in Java. A final modifier just tells the compiler that the reference to the object cannot be re-assigned, but nothing about its content. A final modifier can never change the immutability of an object. A constant in Java is NOT a real constant. const is a reserved keyword in Java. We may expect the implementation of Const Correctness in Java in the future.


Wednesday, June 27, 2007

Comparisons of C++ and Java (V): Immutability of Strings

Strings are not the same in C++ and Java regarding to immutability. In Java, String objects are immutable, where C++ string type is mutable.

Let’s take a look at some examples:

A C++ Example

string str1=”It is Friday, ”;
string str2=”I am completely released”;
str1.append(str2);

cout<<str1<<endl;

The program will print: It is Friday, I am completely released

A Java Example

String str1 = “It is Friday,”;
String str2 = “I am completely released!”;
str1.concat(str2);

System.out.println(str1);

The program will print: It is Friday,

Immutability of strings in C++ and Java

In C++, a string type is mutable. As shown in example 1, str1.append(str2) appends str2 to the end of str1, and str1 becomes “It is Friday, I am completely released”. In addition to append(), similar functions like substr() and assign() etc. in std::string class DO alter a C++ string.

By contrast, in Java, String objects designed as immutable. As shown in example 2, str1.concat() creates a new String object, the old string str1 remains unchanged. It is also true for some other methods such as substring(), toLowerCase() and toUpperCase(). In other words, any operation performed on one String reference will never have any effect on the content of the String object.

Reduce Object Creation in Java

Because of its mutability and the object-creation overhead of a String object, performance could be a problem. In fact, Java provides several mechanisms to reduce String objects creation:

  • String literal Pool: Java compiler optimizes handling of String literals. Only one String object is shared be all strings that have same character sequence. Such strings are said to be interned, meaning that they share a unique String object. The String class maintains a private pool called String intern pool, where such strings are interned. Java automatically interns String literals.
  • Interning of Strings: we can also explicitly make a String object interned. Intern() method from String class can help achieve interning of a String . When the intern() method is invoked on a String, JVM first checks the String literal pool. If a String with the same content is already in the pool, a reference to the String in the pool is returned. Otherwise, the String is added to the pool and a reference to it is returned. The result is that after interning, all Strings with the same content will point to the same object.
Can we intern all Strings? The answer is may not. As the intern string pool grows large, the cost to find a String in the pool could become more expensive than creating a new object.
  • StringBuffer and StringBuilder serves as mutable strings: as a sort of complementary, Java provides StringBuffer as a sort of mutable string. Content of a StringBuffer object can be modified. It is more efficient to use a StringBuffer instead of operations that result in the creation of many intermediate String object. Introduced in J2SE 5.0, Stringbuilder class provides an API compatible with StringBuilder but is unsynchronized.


Wednesday, May 30, 2007

Comparisons of C++ and Java (IV): Accessibility of Indirect Base Classes

Firstly, let’s take a look at two examples in C++ and Java respectively:

Example 1 (In Java):

A.java
public class A {
A (){}
void printMsg(){
System.out.println("print from class A");
}
}

B.java
public class B extends A {
B (){}
void printMsg(){
System.out.println("print from class B ");
}
}

C.java
public class C extends B {
C (){}
void printMsg(){
// direct base class B is accessible but now indirect base class A
super.printMsg();
System.out.println("print from class C");
}
}

Test code snippet

C c = new C();
c.printMsg();

The inheritance path looks like:

A (indirect base)
|
B (direct base)
|
C

The test Results are:
print from class B
print from class C

In class C, method "printMsg()" in direct base class B is accessible by calling:

super.printMsg()

However, the method "printMsg()" in indirect base class A is not accessible. What about in C++? Let’s take a look at an exactly same example but in C++.

Example 2 (In C++): same as Example 1 but written in C++

class A:

class A{
public:
A(){}
void printMsg( ){
cout&lt;&lt;" print from class A "&lt;&lt;endl;
}
};

class B:

class B : public A{
public:
B(){}
void printMsg(){
cout&lt;&lt;" print from class B "&lt;&lt;endl;
}
};

class C:

class C:public B{
public:
C(){}
void printMsg(){
A::printMsg();//indirect base is accessible too
B::printMsg();
cout&lt;&lt;" print from class C "&lt;&lt;endl;
}
};

Test code snippet:

C* c = new Polygon::C();
c->printMsg();

The test code will print:
print from class A
print from class B
print from class C

As we have noticed, the indirect base class A is accessible in class C which is different than in Java as shown in Example 1.

Why C++ and Java are different at this point?

As my understanding it is because in C++, multiple-inheritance is allowed. A derived class may inherit methods with same finger print from different base classes as shown below:

class A
class A {
public A();
pulbic printMsg();
}

class B1
class B1 {
public B1()
pulbic printMsg();
}

class B2
class B2 {
public B2();
pulbic printMsg();
}

class C
class C : public B1,B2{
public C();
pulbic printMsg();
}


The inheritance path is shown as:
A (indirect base)
/ \
B1 B2 (direct base)
\ /
C

Class C has two direct base classes B1 and B2. This arises the ambiguity because both have a method called “printMsg()”. Image what if the printMsg() in class C would like to inherit both "printMsg()" from class B1 and class B2? Fortunately, C++ provides techniques to eliminates the ambiguities by explict qualification: B1::printMsg() or B2::printMsg() explicitly tells compiler which version of "printMsg()" is been used. However, the solution also leads the de-encapsulation of indirect base classes A in the inheritance tree.

Unlike C++, in Java, strict inheritance is enforced and all classes are single-rooted by the class Object. Multiple implementation inheritance is not allowed, thus the confusion in the examples above does not exist. Everything in the super class is inherited by the subclass. Thus, there is no need to access the indirect base class upward in the inheritance tree.

Monday, May 21, 2007

Comparisons of C++ and Java (III): Method Overriding

Method overriding is not quite the same in C++ as in Java. Here are some examples show the differences:

Method overriding in Java

base.java

public class base {
base (){}
void printMsg(){
System.out.println("print from base class");
}
}

Derived.java

public class derived extends base {
derived (){}
void printMsg(){
System.out.println("print from derived class");
}
}

test code snippet:


public static void main(String args[]){
base b = new derived();
b.printMsg();
}

What do we get:

>> print from derived class

Non-virtual method overriding in C++

base.h

class base{
public:
base(){}
void printMsg();
};

base.cc
void base::printMsg(){
cout&lt;&lt;" print from base"&lt;&lt;endl;
}

derived.h
class derived : public base {
public:
derived(){};
void printMsg();
};

derived.cc

void derived::printMsg(){
cout&lt;&lt;" print from derived class"&lt;&lt;endl;
}

test code snippet:

base* d = new derived();
d->printMsg();

And what do I get:

>>print from base class

which is not what I expect? But how does it happen? The reason is still because of the binding mechanisms in C++ and Java.

As we know there are two binding mechanisms in C++: static binding and dynamic binding. Dynamic binding is implemented through virtual functions; the actual code for the functions is not attached or bound until execution time.

On the other hand, static binding occurs when the functions code is “bound” at compile time. This means that when a non-virtual function is called, the compiler determines at compile time which version of the function to call. When overriding a non-virtual method in a derived class, if we call the method via base class reference or pointer type, the method in the base class is called. In our example above, the printMsg() in the base class is called and print out "print from base class".

As we have discussed before, in Java all method are treated as virtual, so dynamic binding applied all the time. And when we override a method in a derived class, we are able to call the method via a base class reference.

So what is the solution in C++ if I want to call the overridden methods in a derived class via a base class reference?

The answer is to make the method in base class virtual, as shown below:

base.h

class base{
public:
base(){}
virtual void printMsg();
};

Because the function printMsg() is virtual, dynamic binding applies. When we call the derived method via a base class reference, we get what we want:

>> print from derived class

Sunday, May 20, 2007

Comparisons of C++ and Java (II): Static Variables

I used a lot of static variables in Java programming and I don't feel any tricks except you have to know why you make a variable static. I thought it would be the same to use static variable in C++. However, it is not true.

In C++, static data member must be defined outside class definition

In Java, we declare a static variable in class scope and can access it anywhere inside the class. In C++, I thought it must be the same way. Actually it is not. Here is the example. I declare a variable static in head file (test.h) and try to use it in the program file (test.cc) as shown in the sample code:

test.h

class test {
private:
static int i;
public:
test();
}

test.cc
test::test(){
i = 0;
}

At compilation, I get an error says “undefined reference to `test::i”. After I looked up some books and also did some Google search, I finally figured out that a static variable must be defined in the program file. So test.cc should look like:

test.cc

int test::i; //We can also initialize i here, eg. int test::i = 0.
test::test(){
i = 0;
}

Now compiler is happy. But why? The reason is that C++ keeps two files for a class: class declaration (header file) and class definition (program) file. The header file contains the class declaration and does not necessary reserve storage space associated with the identifier, while the program file contains method definitions and reserve storage space for each given identifier.

So when we declare a static data member within a class definition, it is NOT defined. In other words, we are not allocate storage for it. Instead, we must provide a global definition for it elsewhere outside class definition because it does not belong to any specific instance of the class.

What about in Java? Java has a simplified matter by only have class and variable definitions. There are no sole declarations in Java, so class definition and variable definitions are also class declarations and variable declarations. In other words, in Java, all classes, data members and variables within methods are defined, therefore storage spaces are reserved for primitive data types.

In C++, a local variable can be static

In C++, a local variable can be static. For example:

test::test(){

i = 0;

static int count = 0;

}

is perfectly legal in C++. A local static variable has the same life time as a global static variable, but its scope is local to the function in which it is declared. It sounds a good idea to me.

In Java, a static variable can only be declared inside a class scope. Compiler will complain if a local variable is declared as static inside a method scope, Even inner classed cannot have static declarations.








Thursday, May 17, 2007

Comparisons of C++ and Java (I): Static Binding and Dynamic Binding in C++

After years of Java programming, I have to pick up C++ for my work. Sometimes, it is hard to switch from Java thinking. Here is one of the example: Static binding and Dynamic binding in C++.

Let me start with 3 examples.

Example 1 (In Java):

base class:

public class base{
public base(){}
public void printMsg(){
System.out.println("I am printMsg() from base class");
}

derived class

public class derived extends base{
public derived(){}
public void printMsg(){
System.out.println("I am printMsg() from derived class")
}
)

A test class:

public class test {
public static void main(String[] args){
base myClass = new derived();
myClass.printMsg();
}
}

What do get? Here we go:

>>I am printMsg() from derived class

It is so obvious to a Java programmer. OK, let’s look at C++ version of the example above.

Example 2 (in C++): this example looks exactly same as example 1 but in C++.

base class:

class base{
public:
base(){};
void printMsg( cout<<”hi, printMsg() from base”<<endl;);
};
...

derived class:


class derived : public base {
public:
derived();
void printMsg(cout<<”hi, printMsg() from derived class”<<endl);
};
...
test class snippet

....
base* myClass = new Polygon::derived();
myClass->printMsg();
...

What do we get? There we go:

>>hi, printMsg() from base

and not “hi, printMsg() from derived class” as I expected.

How can I access derived class version of printMsg() in C++? There is a way out: by using pure virtual methods. In base.cc we change declaration of void printMsg() as:

Example 3 (in C++): This example is same as example 2 except in the base class. The method printMsg() is made pure virtual:


class base{
public:
base(){};
void printMsg( cout<<”hi, printMsg() from base”<<endl;);
virtual void printMsg() = 0;
};

Then compile and run, I get what I want:

>>hi, printMsg() from derived class

The derived class version of printMsg() get called.

What is going on here?

It is because Java and C++ provide different binding mechanisms to achieve run-time polymorphism.

In C++ there are two kinds of data binding: static binding and dynamic binding. Static binding is by means of nonpuer virtual functions while dynamic binding is by virtual functions.
At run time, the implementation is chosen differently. In static binding, decision is made by the static type of pointer or reference, while in dynamic binding, decision is made by the actual type of object being pointed to.

This can explain the results from example 2 and 3. In example 2, base class contains no virtual printMsg() function, so it is static binding. In example 3, method printMsg() is a virtual function, so dynamic binding applies, therefore the derived class version of printMsg() is picked up.

What happens in Java? In Java, every method is treated as pure virtual method and dynamic binding applies always.

Extra note on pure virtual method in C++:

  1. When using pure virtual methods in C++, never try to call a pure virtual method from a constructor or destructor. Compiler will complain “error: abstract virtual `virtual method' called from constructor” at compilation time.
  2. Making destructor virtual is a best practice since it would make sure the destructor in derived class get called too as desired.

Tuesday, March 20, 2007

Generate Documents With Gridsphere Portlet -- A Bug in build.xml

I wanted to create document for my portlet calledtestportlet created in GridsphereframeworkWhen I run


ant docs


I got errors:


BUILDFAILED
/path/to/gridsphere-2.1.5/projects/testportlet/build.xml:256: No sou rce filesand no packages have been specified.



In the build.xml file the"ant docs" is defined as:

....
<target name="docs" depends="javadocs"description="Create projectdocumentation"/> <!--===================================================================--> <!-- Creates allthe APIdocumentation --> <!--===================================================================--> <targetname="javadocs" depends="setenv" description="CreateJavadocs"> <echo>CreatingJavadocs</echo> <delete quiet="true"dir="${build.javadoc}"/> <mkdirdir="${build.javadoc}"/> <javadocsourcepath="src" classpathref="classpath" destdir="${build.javadoc}" author="true" version="true" splitindex="true" use="true" maxmemory="180m" windowtitle="${project.title}" doctitle="${project.api}"> <!--bottom="Copyright &#169; 2002,2003 GridLab Project. All RightsReserved."> --> </javadoc> </target>
...

I am using Java 1.5 and Apach Ant 1.6. Look like it is the issue of Java 1.5,the sourcepath is ignored even though Irun "javadoc" command from a separatepackage independent of Gridsphere framework. I modified a little bit of thebuild.xml file and now it is workingwell:

1. First remove attribute sourcepath="src"
2. Add "<fileset dir="src" />" to <javadoc> element.

The modified file should look like:

.... <target name="docs" depends="javadocs"description="Create projectdocumentation"/> <!--===================================================================--> <!-- Creates allthe API documentation --> <!--===================================================================--> <targetname="javadocs" depends="setenv" description="CreateJavadocs"> <echo>CreatingJavadocs</echo> <delete quiet="true"dir="${build.javadoc}"/> <mkdirdir="${build.javadoc}"/> <javadocsourcepath="src" classpathref="classpath" destdir="${build.javadoc}" author="true" version="true" splitindex="true" use="true" maxmemory="180m" windowtitle="${project.title}" doctitle="${project.api}"> <filesetdir="src" /> <!--bottom="Copyright &#169; 2002,2003 GridLab Project. All RightsReserved."> --> </javadoc> </target> ...


Save file and run "ant docs" or"ant javadocs", the document files aregenerated in/path/to/gridsphere-2.1.5/projects/testportlet/build/docs/javadocs/.

Commentary:

Some one had mentioned that the combination of ant 1.6 and Java 1.5 wouldigmore attribute "sourcepath" in thebuild file, but I think it is the problem of Java 1.5. Do Gridspherepeople notice that? Anyway, it is still very nice to be able to generatedocuments for portlets from within Gridsphere framework environment if we do alittle bit extra work.