Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a button which gets a list of files into an array then calls a WwritefiletoDB function for each file:
private void BtnImportActionPerformed(java.awt.event.ActionEvent evt) {
// Create array to store filenames
List<String> filenames = new ArrayList<String>();
JTextFiles.append("*** Current Files Processing ***\n");
File dir = new File(TextFieldDirectory.getText());
File[] files = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".pdf");
}
});
for (File file : files) {
if (file.isFile()) {
JTextFiles.append(file.getAbsolutePath() + "\n");
try {
writefiletoDB(file.getAbsolutePath());
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JTextFiles.append("*** Finished Processing ***\n");
}
Note the try catchblocks.
The writefiletoDB method has this code:
public void writefiletoDB(String currentfile) throws SQLException, IOException {
//System.out.println("This is current file:" + currentfile);
PDDocument pdfDocument = PDDocument.load(new File(currentfile));
PDDocumentCatalog docCatalog = pdfDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
List fields = acroForm.getFields();
PDField EventNo = acroForm.getField("EventNo");
System.out.println("Event String Length: " + EventNo.getValueAsString().length());
// If event number too short - then skip record
if (EventNo.getValueAsString().length() != 10) {
//JOptionPane.showMessageDialog(null, currentfile +" record was skipped - invalid EventNo = " +EventNo.getValueAsString());
JTextFiles.append("The above file skipped - the event number was incorrect length\n");
pdfDocument.close();
return;
};
Iterator fieldsIter = fields.iterator();
// Create Hashmap "pdf" storing PDF field names & values
Map<String, String> pdf = new HashMap<String, String>();
while (fieldsIter.hasNext()) {
PDField field = (PDField) fieldsIter.next();
// Next line removes braces for dropdowns and any leading whitespace
pdf.put(field.getPartialName(), field.getValueAsString().replaceAll("[\\[\\]]", "").trim());
}
//Create list "columns" to store field names from Database
List<String> columns = new ArrayList<String>();
Connection conn = null;
Statement stmnt = null;
try {
//Connect to DB
conn = DriverManager.getConnection("jdbc:ucanaccess://" + TextFieldDatabase.getText());
stmnt = conn.createStatement();
} catch (SQLException se) {
JOptionPane.showMessageDialog(null, "A SQL Error: " +se, "SQL ERROR", JOptionPane.ERROR_MESSAGE);
return;
}
// Check If Event Number already exists in DB - if so then exit
System.out.println("Checking if event exists");
PreparedStatement psEvent = conn.prepareStatement("SELECT EventNo FROM test WHERE EventNo = ?");
psEvent.setString(1, EventNo.getValueAsString());
ResultSet rsEvent = psEvent.executeQuery();
if (!rsEvent.next()) {
System.out.println("Result set is empty");
} else {
JTextFiles.append("The above record already exists - skipping\n");
pdfDocument.close();
return;
}
// Get a list of column names from database
ResultSet rs = stmnt.executeQuery("SELECT * FROM test WHERE False");
ResultSetMetaData rsmd = rs.getMetaData();
//System.out.println("Column names as reported by ResultSetMetaData:");
// Add the column names from database to List columns
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
System.out.println(rsmd.getColumnName(i));
// Store the column names from DB in list columns (via result set rsmd)
columns.add(rsmd.getColumnName(i));
}
// col and val strings to be built colname,colname and ?,?,?,? etc
// for sql prepared statement into DB
StringBuilder col = new StringBuilder();
StringBuilder val = new StringBuilder();
String separator = "";
for (String c : columns) {
if (pdf.containsKey(c)) {
col.append(separator).append(c);
val.append(separator).append("?");
separator = ",";
}
}
// Insert into DB SQL Statement
String sql = String.format("INSERT INTO test (%s) VALUES (%s)", col.toString(), val.toString());
System.out.println(
"This is sql statement: " + sql);
try (PreparedStatement insert = conn.prepareStatement(sql)) {
//Insert position in statement
int pos = 0;
//Second iterations: Bind the values to the statement *** colums is names of cols fromDB
for (String c : columns) {
//Your PDF has a matching formfield ** pdf is hashmap <string,string>
if (c.toLowerCase().contains("date")) {
System.out.println("A Date field has been found: " +c);
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy kk:mm");
DateTime startdt = formatter.parseDateTime(pdf.get("DateStart") +" " +pdf.get("TimeStart"));
long millis = formatter.parseMillis(pdf.get("DateStart") +" " +pdf.get("TimeStart"));
Timestamp timeStamp = new Timestamp(millis);
insert.setTimestamp(++pos, timeStamp);
}
if (pdf.containsKey(c) && !c.toLowerCase().contains("date")) {
insert.setString(++pos, pdf.get(c));
}
}
insert.executeUpdate();
} catch (SQLException e) {
//JFrame frame;
JOptionPane.showMessageDialog(null, "A SQL Error: " +e, "SQL ERROR", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
pdfDocument.close();
}
Note the try catch block, about line 30. If it generates a error the return statement breaks and it returns to the calling method BtnImportActionPerformed and that loops calls the next file generating another error.
I need a way to break out of both writefiletoDB and also stop BtnImportActionPreformed.
Is there a way to handle writefiletoDB exceptions in BtnImportActionPreformed? or break out of both.
What is the best way to do this - I want to make the code more robust.
Thanks
Al
Simplifying your example to the relevant structure, the code is doing this:
void BtnImportActionPerformed() {
for(int i = 0l i < 10; i++) {
writefiletoDB();
}
}
void writefiletoDB() {
try {
doSomething();
} catch (SomeException e) {
return;
}
}
Since the exception is being caught and handled in the inner method, there's no way for the outer method to know that anything went wrong. If you want the outer method to know that an exception has occurred, use the same pattern as the inner method. Catch a thrown exception. Something like this:
void BtnImportActionPerformed() {
for(int i = 0l i < 10; i++) {
try {
writefiletoDB();
} catch (SomeException e) {
// do anything else?
return;
}
}
}
void writefiletoDB() throws SomeException {
try {
doSomething();
} catch (SomeException e) {
// log it? something else?
throw e;
}
}
You might even be able to skip the inner try/catch entirely if the outer method can do all of the exception handling. You'd simply have to declare the possible exceptions on the writefiletoDB method.
There are multiple ways to solve this, I would choose depending upon what is right for your logic.
Do not catch any exception and let the caller of BtnImportActionPerformed catch.
Put try catch around the for loop of BtnImportActionPerformed that way once exception is raised you are out of the loop. Do remove the try/catch inside the for loop.
From the writefiletoDB return success/failure instead of exception. In BtnImportActionPerformed based on the success/failure you can exit the loop.
Related
This question already has answers here:
How to split the large size .txt file data into small portion and insert into database?
(2 answers)
Read data from txt file and insert it into database using java
(2 answers)
Closed 4 years ago.
I have a text file consisting of several lines.
I want to add the whole lines to the table of database.
Before it is inserted to table, it should be substring to get fields value of database table. I think my code (Query) is not good for big data. I know there is other way to do that condition.
public class ReaderFilesData {
LinkedList<String> listFiles = new LinkedList<String>();
private Path path = Paths.get("src/FilesDownloaded/");
DataTRX dataTRX = new DataTRX();
public void readFiles() {
File[] listFile = new File(path.toString()).listFiles();
for (File file : listFile) {
if (file.isFile()) {
listFiles.add(file.getName());
}
}
System.out.println("Total Files : " +listFiles.size());
}
public void readData() {
Path pathsourceFile;
String line;
BufferedReader reader;
for (int i=0; i<listFiles.size(); i++) {
try {
String fileName = listFiles.get(i);
System.out.println("FileName : " +fileName);
pathsourceFile = Paths.get("src/FilesDownloaded/"+fileName+"");
reader = new BufferedReader(new FileReader(pathsourceFile.toString());
while ((line = reader.readLine())!=null) {
int startPoint = line.lastIndexOf(';')+1;
String valueLine = new String(line.substring(startPoint));
System.out.println("Transaction data : " +valueLine);
dataTRX.setId(valueLine.substring(0,2));
dataTRX.setAmount(Integer.parseInt(valueLine.substring(2, 10)));
dataTRX.setDesc(valueLine.substring(10, 18));
System.out.println("getId : " + dataTRX.getId());
System.out.println("getAmount : " + dataTRX.getAmount());
System.out.println("getDesc : " + dataTRX.getDesc());
importData(dataTRX.getId(),
dataTRX.getAmount(),
dataTRX.getDesc(),
}
reader.close();
} catch (Exception e) {
e.getMessage();
}
}
}
public void importData(String id, int amount, String discount ) {
String insertData = "INSERT INTO tbl_trx (id, amount, desc) "
+ "VALUES (?,?,?)";
try {
try (PreparedStatement ps = GeneralRules.conn.prepareStatement(insertData)) {
ps.setString(1, id);
ps.setInt(2, amount);
ps.setString(4, desc);
ps.executeUpdate();
System.out.println("Data successfully update to database!!!\n");
ps.close();
}
} catch (Exception e) {
e.getMessage();
}
}
This is example data of file.txt
320000000200000001
2G0000000500000002
AB0000001500000001
I do substring data base on line above :
substring id,amount,discount (32,00000002,00000001)
substring id,amount,discount (2G,00000005,00000002)
substring id,amount,discount (AB,00000015,00000001)
Your code seems good to me. But If I would have written it, below optimization/replacement, I would have done
1) Use List instead of LinkedList in variable declaration and remove generic String from reference point. Something like
List<String> listFiles = new LinkedList<>();
Link for more explanation on this
2) Similar to using try with resource you did for PreparedStatement, I would do the same for BufferedReader. This would remove the need to close the `BufferedReader' in the end
try (BufferedReader reader = new BufferedReader(new FileReader(pathsourceFile.toString())))
Link for more explanation on this
3) Because you have used try with resource for PreparedStatement, there is no need to have ps.close(), because preparedstatement implements AutoCloseable. So try with resouce will take care of it
4) Instead of e.getMessage(), I would have used e.printStackTrace() because it would give me more information about the error
As far as your use of sub-string is concerned, I would have used it, or would have use regex to split the string.
If number of rows to be inserted are more, which I think is your case, instead of calling executeUpdate() everytime, go with Batch mode. i.e add statements to PreparedStatement batch using addBatch() and execute in one go with executeBatch()
So I'm trying to import a CSV file into my MySQL database through my Java program. The program imports everything that's in the file, like it's suppose to, but the first row, it send to the end of the table, and the program see it's there, but if I search for that nr, it says it doesn't exists. And if I go directly to the database table and edit the nr(if the nr is 137, and I edit and write 137 again) the program recognize that nr, and if I search for it, it will find, and the database table organizes itself and sends that entry where is suppose to be.
I just don't see any logic in this. I someone could help me out, I'd appreciated.
LOAD DATA INFILE 'C:\\Users\\carla.DESKTOP-9364K9K\\Desktop\\Alunos_1.csv'
INTO TABLE utentes character set utf8
FIELDS TERMINATED BY ','
(NrProcesso, Nome, #Nome_Resumido, Ano, Turma, #Subsidio, #Nome_EE, #NIF, #email, #Obs)
SET
Subsidio = IF(#Subsidio='','Nenhum',#Subsidio),
Nome_Resumido = IF(#Nome_Resumido='',NULL,#Nome_Resumido),
Nome_EE = IF(#Nome_EE='',NULL,#Nome_EE),
NIF = IF(#NIF = '', NULL,#NIF),
email = IF(#email='',NULL,#email),
Obs = IF(#Obs='',NULL,#Obs);
Thanks in advance.
You have do do something to check cell/column value and form a sql to inject in MySQL.
public List<Object> getRecordingsListFromCsv(String csvFileLocation, String mp3FileLocation, String mp3FileLocation2, String saveFileLocation, ChannelSftp sftp) {
Map<String, File> recordingsFilesMap = null;
BufferedReader br = null;
List<String> errorFilesList = new ArrayList<>();
List<Object> tempList = new LinkedList<>();
try {
csvRows = 0;
recordingsFilesMap = new LinkedHashMap<>();
br = new BufferedReader(new FileReader(csvFileLocation));
String line = br.readLine();
scriptLog.info("\n" + csvFileLocation + " loaded. Parsing File...");
while ((line = br.readLine()) != null) {
String[] csvArray = parseCsvLineToArray(line);
// System.out.println(Arrays.asList(csvArray) + "\n\n");
if (csvArray[0].trim().isEmpty()) {
continue;
}
/* Do your stuff here */
csvRows++;
}
} catch (FileNotFoundException e) {
scriptLog.error("\n---ERROR---\n FILE NOT FOUND: " + csvFileLocation);
String errorStr = "Type=" + e.toString();
errorStr += "StackTrace=" + Arrays.toString(e.getStackTrace());
scriptLog.error(errorStr);
} catch (IOException e) {
String errorStr = "Type=" + e.toString();
errorStr += "StackTrace=" + Arrays.toString(e.getStackTrace());
scriptLog.error(errorStr);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println(e.toString());
}
}
}
Hope it will help you at some extent!!
Hi all after getting some advice, I am attempting to use the filewriter method in order to export my google analytics queries that i got to a CSV file format here is what i have so far
private static void printGaData(GaData results) {
try {
PrintWriter pw = new PrintWriter(BufferedWriter(new FileWriter("data.csv")));
}
catch(Exception e) {
e.printStackTrace();
}
System.out.println(
"printing results for profile: " + results.getProfileInfo().getProfileName());
if (results.getRows() == null || results.getRows().isEmpty()) {
System.out.println("No results Found.");
} else {
// Print column headers.
for (ColumnHeaders header : results.getColumnHeaders()) {
System.out.printf(header.getName() + ", ");
}
System.out.println();
// Print actual data.
for (List<String> row : results.getRows()) {
for (String column : row) {
pw.printf(row + ", ");
}
pw.println();
}
pw.println();
}
}
}
doesnt output any data and keeps saying that the pw is non extent and stuff like that
Your PrintWriter is inside the try catch block. If you define it outside like
PrintWriter pw = null;
try {
pw = new PrintWriter(BufferedWriter(new FileWriter("data.csv")));
} catch (Exception e) {
// handle exception
}
then it will be available to the rest of your code.
I want to transfer the contents of csv file to mysql.In my csv file there are columns that have text containing commas.
I am using below code to transfer the contents
`
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Date;
import org.apache.commons.lang.StringUtils;
import au.com.bytecode.opencsv.CSVReader;
public class CSVLoader {
static int count;
private static final
String SQL_INSERT = "INSERT INTO ${table}(${keys}) VALUES(${values})";
private static final String TABLE_REGEX = "\\$\\{table\\}";
private static final String KEYS_REGEX = "\\$\\{keys\\}";
private static final String VALUES_REGEX = "\\$\\{values\\}";
private Connection connection;
private char seprator;
/**
* Public constructor to build CSVLoader object with
* Connection details. The connection is closed on success
* or failure.
* #param connection
*/
public CSVLoader(Connection connection) {
this.connection = connection;
//Set default separator
this.seprator = ',';
}
/**
* Parse CSV file using OpenCSV library and load in
* given database table.
* #param csvFile Input CSV file
* #param tableName Database table name to import data
* #param truncateBeforeLoad Truncate the table before inserting
* new records.
* #throws Exception
*/
public void loadCSV(String csvFile, String tableName,
boolean truncateBeforeLoad) throws Exception {
CSVReader csvReader = null;
if(null == this.connection) {
throw new Exception("Not a valid connection.");
}
try {
csvReader = new CSVReader(new FileReader(csvFile), this.seprator);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("Error occured while executing file. "
+ e.getMessage());
}
//String[] headerRow = csvReader.readNext();
String[] headerRow = csvReader.readNext();
count++;
if (null == headerRow) {
throw new FileNotFoundException(
"No columns defined in given CSV file." +
"Please check the CSV file format.");
}
String questionmarks = StringUtils.repeat("?,", headerRow.length);
System.out.println(headerRow.length);
questionmarks = (String) questionmarks.subSequence(0, questionmarks
.length() - 1);
String query = SQL_INSERT.replaceFirst(TABLE_REGEX, tableName);
query = query
.replaceFirst(KEYS_REGEX, StringUtils.join(headerRow, ","));
query = query.replaceFirst(VALUES_REGEX, questionmarks);
System.out.println("Query: " + query);
String[] nextLine;
Connection con = null;
PreparedStatement ps = null;
try {
con = this.connection;
con.setAutoCommit(false);
ps = con.prepareStatement(query);
if(truncateBeforeLoad) {
//delete data from table before loading csv
con.createStatement().execute("DELETE FROM " + tableName);
}
final int batchSize = 1000;
int count = 0;
Date date = null;
while ((nextLine = csvReader.readNext()) != null) {
if (null != nextLine) {
int index = 1;
for (String string : nextLine) {
date = DateUtil.convertToDate(string);
if (null != date) {
ps.setDate(index++, new java.sql.Date(date
.getTime()));
} else {
ps.setString(index++, string);
}
}
System.out.println(count);
ps.addBatch();
System.out.println(count);
}
if (++count % batchSize == 0) {
System.out.println(count);
ps.executeBatch();
}
}
ps.executeBatch(); // insert remaining records
con.commit();
} catch (Exception e) {
con.rollback();
e.printStackTrace();
throw new Exception(
"Error occured while loading data from file to database."
+ e.getMessage());
} finally {
if (null != ps)
ps.close();
if (null != con)
con.close();
csvReader.close();
}
}
public char getSeprator() {
return seprator;
}
public void setSeprator(char seprator) {
this.seprator = seprator;
}
}
`
When executing it I am getting error as "No value specified for parameter 23".
My database table has 22 columns and the csv file also has 22 columns.So I am guessing that in the first row itself there is a text which has a comma in it and it is not able to parse it and hence it is assuming as 23 columns and not 22.
Can anyone help me in clarifying the problem and providing me solution.
I believe the immediate issue is that you do not escape the column names while inserting them into your SQL statement. What you are creating is a statement of this form:
INSERT INTO sometable(key1,key2,key3) VALUES(?,?,?)
Now if you have a comma in a header row (let's say one key is "ke,y3" instead), even if it is read correctly by your CSV library, you will be creating something like this:
INSERT INTO sometable(key1,key2,ke,y3) VALUES(?,?,?)
Now you have a mismatch in the number of values and the number of columns. Note that this can also happen with some other characters: Maybe you have a question mark in one key that is interpreted as a parameter placeholder?
The solution: To save yourself some headache, avoid these characters in the keys if possible. I'm not sure how and if mysql will handle them properly, but if it does, you need to at least escape the column names before inserting them. I'm not sure how you would do that properly and safely (to prevent SQL injection), but since this is apparently a one-off tool, wrapping the column names in backticks like this should be good enough:
INSERT INTO sometable(`key1`,`key2`,`ke,y3`) VALUES(?,?,?)
There are two types of comma in a CSV file. One type of comma separates fields, the other type of comma is part of text and always occurs between quotes. You need to parse commas outside quotes differently from commas inside quotes. Your code does not appear to do this. Perhaps something like:
repeat
c <-read next character
if (c == '"')
parse quoted field // May include commas.
else
parse non-quoted field // Will not include commas.
endif
until file all read.
Using different methods to parse quoted and non-quoted fields makes it easy to treat the two types of comma correctly.
I am currently working on my own version of a glossary written in Java. Truthfully, this is of academic nature and I was hoping someone could point me in the first direction. Anyway, I am reading in text from a text file and putting the words and their corresponding definitions into a Map (Tree Map to be more specific). Everything works good from there. Everything is in the map as it should be.
Now I start to get to the part where I want to go into HTML and output the contents of the map. I know how to do that with iterators and that wasn't much of a problem. However, when I try to display the content mixed in with HTML I don't get all that I want. The page is ultimately supposed to look like this: http://cse.osu.edu/~weide/rsrg/sce/now/321/421/labs/lab10/glossary.html#book
And there is this particularly tricky part where if there's a term contained within a definition it should be clickable. Here is what I have so far. Again, if anyone could help me figure out why the main guts of the HTML aren't displaying I would appreciate it very much! By the way, the text file I'm getting things from is called: terms.txt, and the html file writing to is called glossary.html.
This is what I have so far:
public class Glossary {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Map<String, String> dictionary = new TreeMap<String, String>();
File htmlFile = new File(
"/Users/myname/Documents/workspace/Lab10/src/glossary.html");
File file = new File(
"/Users/myname/Documents/workspace/Lab10/src/terms.txt");
Writer out = new OutputStreamWriter(new FileOutputStream(htmlFile));
String term = null;
String def = null;
String key = null, value = null;
String lead = null;
String multiFinalDef = null;
Set<String> checkValues = new HashSet<String>();
String leftOver = null;
boolean check = false;
Scanner input = null;
try {
input = new Scanner(file);
while (input.hasNext()) {
String keepTrack;
boolean multi = false;
String line = input.nextLine();
term = line;
def = input.nextLine();
keepTrack = def;
while (def.length() > 0 && input.hasNext()) {
def = input.nextLine();
if (def.length() > 0) {
multiFinalDef = " " + keepTrack + def;
multi = true;
}
}
if (multi) {
dictionary.put(term, multiFinalDef);
} else {
dictionary.put(term, keepTrack);
}
checkValues.add(term);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.write("<HTML>\n");
out.write("<HEAD>\n");
out.write("</HEAD>\n");
out.write("<BODY>\n");
out.write("<H1>Glossary</H1>\n");
out.write("<HR /\n");
out.write("<H2>Index</H2>\n");
out.write("<UL>\n");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Set s = dictionary.entrySet();
Iterator iterator = s.iterator();
while (iterator.hasNext()) {
Map.Entry m = (Map.Entry) iterator.next();
// getKey is used to get key of map.
key = (String) m.getKey();
// getValue is used to get the value of the key in map.
value = (String) m.getValue();
// this is just so I know the output from the map is actually correct. And indeed it is.
System.out.println("Key:\t\t\tValue\n " + key + "\t\t\t " + value
+ "\n");
try {
out.write("<LI>" + key + "</LI>\n");
out.write("</UL>\n");
out.write("<HR />\n");
} catch (IOException e) {
e.printStackTrace();
}
}
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
iterator = s.iterator();
while (iterator.hasNext()) {
Map.Entry temp = (Map.Entry) iterator.next();
// getKey is used to get key of map.
String keyTwo = (String) temp.getKey();
// getValue is used to get the value of the key in map.
String valueTwo = (String) temp.getValue();
out.write("<H3><A NAME=\" " + keyTwo + "/><B><I><FONT COLOR=\"red\">"
+ keyTwo + "</FONT></I></B></LI></H3>\n");
for(String getTerm : checkValues){
if (valueTwo.contains(getTerm)) {
check = true;
int foundTermPosition = valueTwo.indexOf(getTerm);
lead = valueTwo.substring(0, foundTermPosition - 1);
//fix left over..
leftOver = valueTwo.substring(foundTermPosition, valueTwo.length());
out.write(lead);
out.write("" + keyTwo + "");
out.write(leftOver + "\n");
//out.write("</blockquote>\n");
}
}
if( check == false)
{
out.write(lead + " " + valueTwo);
}
}
//System.out.println(valueTwo + leftOver);
// used to put words defined in file mentioned in definition
// with hyperlinks to their associated locations, and output the
// definition.
out.write("</P>\n" + "</UL>\n");
out.write("</BODY>\n");
out.write("</HTML>");
out.close();
}
}
By the time your program reaches
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
while (iterator.hasNext()) {
...
the iterator doesn't have any more items left, as it gets exhausted on the first while loop a few lines before, while you're printing the index. To iterate through the map again, you'll need to call the iterator method again. So the block above would become:
out.write("<H2>Terms and Definitions</H2>\n");
out.write("<UL>\n" + "<P>\n");
iterator = s.iterator();
while (iterator.hasNext()) {
...
As I understand, you want to generate html documents. In my humble opinion, the best and generic approach in your case - use any of template engines. For example - Apache Velocity.
It takes a few minutes to look through this tutorial