I have a class that pulls in an id, name and (if needed) parent-id, it converts these into objects and then links them.
If you look right at the end you will see what Im trying to fix at the moment, The folder objects know if they have a child and/or parent but if I were to run mkDirs() here it would only work for two levels (root, child-folder) but if there were multipul levels (root/folder1/folder1) it would not work.
Any Idea how I can solve this?
package stable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
public class Loop {
public static void main(String[] args) {
int PID = 0;
int RepoID = 1;
Connection con = null;
String url = "jdbc:mysql://localhost/document_manager";
String user = "root";
String password = "Pa55w0rd";
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
Map<Integer,Folder> data = new HashMap<Integer,Folder>();
while( PID < 50 )
{
try {
Statement st = con.createStatement();
ResultSet result = st.executeQuery("SELECT name, category_id, parent_id FROM categories WHERE parent_id = '"+PID+"' AND repository_id = '"+RepoID+"'");
while (result.next ())
{
String FolderName = result.getString ("name");
String FolderId = result.getString ("category_id");
String ParentId = result.getString ("parent_id");
int intFolderId = Integer.parseInt(FolderId);
int intParentId = Integer.parseInt(ParentId);
System.out.println( FolderId+" "+FolderName+" "+ParentId );
Folder newFolder = new Folder(FolderName, intFolderId, intParentId);
data.put(newFolder.getId(), newFolder);
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
PID++;
}
for(Folder folder : data.values()) {
int parentId = folder.getParentFolderId();
Folder parentFolder = data.get(parentId);
if(parentFolder != null)
parentFolder.addChildFolder(folder);
//Added
System.out.print("\n"+folder.getName());
if(parentFolder != null)
System.out.print(" IS INSIDE "+parentFolder.getName());
else
System.out.print(" HAS NO PARENT!");
}
}
}
Looks like you could/should break out the directory creation logic into its own function and then make it recursive. That should get you the ability to make 'infinite' depth directory hierarchies.
Side note: Its horribly inefficient to make repeated DB calls in a loop. Try a single Select and then loop thru results. If needbe, you can use SQL's 'IN' operator to filter results:
http://www.w3schools.com/sql/sql_in.asp
Related
I came through a link: https://github.com/hyee/OpenCSV which drastically improves the writing time of the JDBC ResultSet to CSV due to setAsyncMode, RESULT_FETCH_SIZE
//Extract ResultSet to CSV file, auto-compress if the fileName extension is ".zip" or ".gz"
//Returns number of records extracted
public int ResultSet2CSV(final ResultSet rs, final String fileName, final String header, final boolean aync) throws Exception {
try (CSVWriter writer = new CSVWriter(fileName)) {
//Define fetch size(default as 30000 rows), higher to be faster performance but takes more memory
ResultSetHelperService.RESULT_FETCH_SIZE=10000;
//Define MAX extract rows, -1 means unlimited.
ResultSetHelperService.MAX_FETCH_ROWS=20000;
writer.setAsyncMode(aync);
int result = writer.writeAll(rs, true);
return result - 1;
}
}
But the problem is I don't know how I can merge above into my requirement. As the link has many other classes involved which I am not sure what they do and if I even need it for my requirement. Still, I tried but it fails to compile whenever I enable 2 commented line code. Below is my code.
Any help on how I can achieve this will be greatly appreciated.
package test;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import com.opencsv.CSVWriter;
import com.opencsv.ResultSetHelperService;
public class OpenCSVTest1
{
static Connection con =null;
static Statement stmt = null;
static ResultSet rs = null;
public static void main(String args[]) throws Exception
{
connection ();
retrieveData(con);
}
private static void connection() throws Exception
{
try
{
Class.forName("<jdbcdriver>");
con = DriverManager.getConnection("jdbc:","<username>","<pass>");
System.out.println("Connection successful");
}
catch (Exception e)
{
System.out.println("Exception while establishing sql connection");
throw e;
}
}
private static void retrieveData(Connection con) throws Exception
{
try
{
stmt=con.createStatement();
stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
String query = "SELECT * FROM dbo.tablename";
rs=stmt.executeQuery(query);
CSVWriter writer = new CSVWriter(new BufferedWriter(new FileWriter("C:\\Data\\File1.csv")));
ResultSetHelperService service = new ResultSetHelperService();
/*** ResultSetHelperService.RESULT_FETCH_SIZE=10000; ***/ // to add
service.setDateTimeFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("**** Started writing Data to CSV **** " + new Date());
writer.setResultService(service);
/*** writer.setAsyncMode(aync); ***/ // to add
int lines = writer.writeAll(rs, true, true, false);
writer.flush();
writer.close();
System.out.println("** OpenCSV -Completed writing the resultSet at " + new Date() + " Number of lines written to the file " + lines);
}
catch (Exception e)
{
System.out.println("Exception while retrieving data" );
e.printStackTrace();
throw e;
}
finally
{
rs.close();
stmt.close();
con.close();
}
}
}
UPDATE
I have updated my code. Right now code is writing complete resultset in CSV at once using writeAll method which is resulting in time consumption.
Now what I want to do is write resultset to CSV in batches as resultset's first column will always have dynamically generated via SELECT query Auto Increment column (Sqno) with values as (1,2,3..) So not sure how I can read result sets first column and split it accoridngly to write in CSV. may be HashMap might help, so I have also added resultset-tohashmap conversion code if required.
import com.opencsv.CSVWriter;
import com.opencsv.ResultSetHelperService;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OpenCSVTest1
{
static int fetchlimit_src = 100;
static Connection con =null;
static Statement stmt = null;
static ResultSet rs = null;
static String filename = "C:\\Data\\filename.csv";
static CSVWriter writer;
public static void main(String args[])
{
try
{
connection();
retrieveData(con);
}
catch(Exception e)
{
System.out.println(e);
}
}
private static void connection() throws Exception
{
try
{
Class.forName("<jdbcdriver>");
con = DriverManager.getConnection("jdbc:","<username>","<pass>");
System.out.println("Connection successful");
}
catch (Exception e)
{
System.out.println("Exception while establishing sql connection");
throw e;
}
}
private static void retrieveData(Connection con) throws Exception
{
try
{
stmt=con.createStatement();
String query = "SELECT ROWNUM AS Sqno, * FROM dbo.tablename "; // Oracle
// String query = "SELECT ROW_NUMBER() OVER(ORDER BY Id ASC) AS Sqno, * FROM dbo.tablename "; // SQLServer
System.out.println(query);
stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(fetchlimit_src);
System.out.println("**** Started querying src **** " + new Date());
rs=stmt.executeQuery(query);
System.out.println("**** Completing querying src **** " + new Date());
// resultset_List(rs); // If required store resultset(rs) to HashMap
writetoCSV(rs,filename);
/** How to write resultset to CSV in batches instead of writing all at once to speed up write performance ?
* Hint: resultset first column is Autoincrement [Sqno] (1,2,3...) which might help to split result in batches.
*
**/
}
catch (Exception e)
{
System.out.println("Exception while retrieving data" );
e.printStackTrace();
throw e;
}
finally
{
rs.close();
stmt.close();
con.close();
}
}
private static List<Map<String, Object>> resultset_List(ResultSet rs) throws SQLException
{
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
while (rs.next())
{
Map<String, Object> row = new HashMap<String, Object>(columns);
for(int i = 1; i <= columns; ++i)
{
row.put(md.getColumnName(i), rs.getObject(i));
}
rows.add(row);
}
// System.out.println(rows.toString());
return rows;
}
private static void writetoCSV(ResultSet rs, String filename) throws Exception
{
try
{
writer = new CSVWriter(new BufferedWriter(new FileWriter(filename)));
ResultSetHelperService service = new ResultSetHelperService();
service.setDateTimeFormat("yyyy-MM-dd HH:mm:ss.SSS");
long batchlimit = 1000;
long Sqno = 1;
ResultSetMetaData rsmd = rs.getMetaData();
String columnname = rsmd.getColumnLabel(1); // To retrieve columns with labels (for example SELECT ROWNUM AS Sqno)
System.out.println("**** Started writing Data to CSV **** " + new Date());
writer.setResultService(service);
int lines = writer.writeAll(rs, true, true, false);
System.out.println("** OpenCSV -Completed writing the resultSet at " + new Date() + " Number of lines written to the file " + lines);
}
catch (Exception e)
{
System.out.println("Exception while writing data" );
e.printStackTrace();
throw e;
}
finally
{
writer.flush();
writer.close();
}
}
}
You should be able to use the OpenCSV sample, pretty much exactly as it is provided in the documentation. So, there should be no need for you to write any of your own batching logic.
I was able to write a 6 million record result set to a CSV file in about 10 seconds. To be clear -that was just the file-write time, not the DB data-fetch time - but I think that should be fast enough for your needs.
Here is your code, with adaptations for using OpenCSV based on its documented approach... But please see the warning at the end of my notes!
import com.opencsv.CSVWriter;
import com.opencsv.ResultSetHelperService;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.text.SimpleDateFormat;
public class OpenCSVDemo {
static int fetchlimit_src = 100;
static Connection con = null;
static Statement stmt = null;
static ResultSet rs = null;
static String filename = "C:\\Data\\filename.csv";
public static void main(String args[]) {
try {
connection();
retrieveData(con);
} catch (Exception e) {
System.out.println(e);
}
}
private static void connection() throws Exception {
try {
final String jdbcDriver = "YOURS GOES HERE";
final String dbUrl = "YOURS GOES HERE";
final String user = "YOURS GOES HERE";
final String pass = "YOURS GOES HERE";
Class.forName(jdbcDriver);
con = DriverManager.getConnection(dbUrl, user, pass);
System.out.println("Connection successful");
} catch (Exception e) {
System.out.println("Exception while establishing sql connection");
throw e;
}
}
private static void retrieveData(Connection con) throws Exception {
try {
stmt = con.createStatement();
String query = "select title_id, primary_title from imdb.title";
System.out.println(query);
stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(fetchlimit_src);
System.out.println("**** Started querying src **** " + new Date());
rs = stmt.executeQuery(query);
System.out.println("**** Completing querying src **** " + new Date());
// resultset_List(rs); // If required store resultset(rs) to HashMap
System.out.println();
String timeStamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date());
System.out.println("Started writing CSV: " + timeStamp);
writeToCsv(rs, filename, null, Boolean.FALSE);
timeStamp = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date());
System.out.println("Finished writing CSV: " + timeStamp);
System.out.println();
} catch (Exception e) {
System.out.println("Exception while retrieving data");
e.printStackTrace();
throw e;
} finally {
rs.close();
stmt.close();
con.close();
}
}
public static int writeToCsv(final ResultSet rs, final String fileName,
final String header, final boolean aync) throws Exception {
try (CSVWriter writer = new CSVWriter(fileName)) {
//Define fetch size(default as 30000 rows), higher to be faster performance but takes more memory
ResultSetHelperService.RESULT_FETCH_SIZE = 1000;
//Define MAX extract rows, -1 means unlimited.
ResultSetHelperService.MAX_FETCH_ROWS = 2000;
writer.setAsyncMode(aync);
int result = writer.writeAll(rs, true);
return result - 1;
}
}
}
Points to note:
1) I used "async" set to false:
writeToCsv(rs, filename, null, Boolean.FALSE);
You may want to experiment with this and the other settings to see if they make any significant difference for you.
2) Regarding your comment "the link has many other classes involved": The OpenCSV library's entire JAR file needs to be included in your project, as does the related disruptor JAR:
opencsv.jar
disruptor-3.3.6.jar
To get the JAR files, go to the GitHub page, click on the green button, select the zip download, unzip the zip file, and look in the "OpenCSV-master\release" folder.
Add these two JARs to your project in the usual way (depends on how you build your project).
3) WARNING: This code runs OK when you use Oracle's Java 8 JDK/JRE. If you try to use OpenJDK (e.g. for Java 13 or similar) it will not run. This is because of some changes behind the scenes to hidden classes. If you are interested, there are more details here.
If you need to use an OpenJDK version of Java, you may therefore have better luck with the library on which this CSV library is based: see here.
I am new to Java and Oracle. I am trying to make an application that lists serial numbers of a product and when you click on a product's serial number from the list, it shows the other column informations from the database in a textbox. I have a form named CRUD.I am using Oracle 10g. Code is here:
package project1;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class CRUD extends javax.swing.JFrame {
Connection connection = null;
public CRUD() {
try {
initComponents();
String driverName = "oracle.jdbc.driver.OracleDriver";
Class.forName(driverName);
String serverName = "192.168.0.36";
String portNumber = "1521";
String sid = "XE";
String url = "jdbc:oracle:thin:#"+serverName+":"+portNumber+":"+sid;
String userName = "HR";
String password = "hr";
try {
connection = DriverManager.getConnection(url,userName,password);
} catch (SQLException ex) {
Logger.getLogger(CRUD.class.getName()).log(Level.SEVERE, null, ex);
}
try {
String temp="";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT SERI_NO FROM KART");
while(rs.next()) // dönebildiği süre boyunca
{
String s = rs.getString("SERI_NO") ; //kolon isimleri oluşturuldu
temp+=s+"_";
}
Object [] tem_obj;
tem_obj=temp.split("_");
listOgrenciler.setListData(tem_obj);
} catch (SQLException ex) {
Logger.getLogger(edit.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (ClassNotFoundException ex) {
Logger.getLogger(CRUD.class.getName()).log(Level.SEVERE, null, ex);
}
listOgrenciler.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent arg0) {
if (!arg0.getValueIsAdjusting()) {
try {
Statement stmtx = connection.createStatement();
Object[] sss=listOgrenciler.getSelectedValues();
String swhere="" ;
for (int i = 0; i < sss.length; i++) {
swhere+=sss[i].toString()+",";
}
swhere=swhere.substring(0,swhere.length()-1);
ResultSet rsx = stmtx.executeQuery("SELECT * FROM KART where SERI_NO in ("+swhere+")") ;
String temp="";
Object [] tem_obj;
tem_obj=temp.split("_");
String ara="";
for (int i = 0; i < tem_obj.length; i++) {
ara+=tem_obj[i].toString()+"\n";
}
texttoarea.setText(ara);
} catch (SQLException ex)
{
Logger.getLogger(edit.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}
Errors i get are here:
20.Şub.2014 11:22:11 project1.CRUD$1 valueChanged
SEVERE: null
java.sql.SQLSyntaxErrorException: ORA-00904: "SNS080961097": invalid identifier
.....
at project1.CRUD$1.valueChanged(CRUD.java:78)
......
As I said before, I am new to both Java and Oracle. If the errors are so obvious don't laugh:)
Your this query
ResultSet rsx = stmtx.executeQuery("SELECT * FROM KART where SERI_NO in ("+swhere+")") ;
should be like this:
ResultSet rsx = stmtx.executeQuery("SELECT * FROM KART where SERI_NO in ('"+swhere+"')") ;
Actually there is no problems with you connection step to Oracle DB, its connected successfully, Your problem is within the query. make sure that you have a SERI_NO column in your KART table.
i suggest you to RUN the both same queries in you code from any SQL client such SQLDeveloper and see what these queries retrieve.
Observe this statement once,
swhere=swhere.substring(0,swhere.length()-1);
replace the above statement with the following
shere=swhere.substring(0,swhere.length()-2);
Because an extra comma(,) is included in your sql statement.
There is no issue with your connection.
Please add some logging to your code and you will know exactly where the error is throwing.
I guess the error is throwing in this line..
SELECT * FROM KART where SERI_NO in ("+swhere+")
You have to specify this as a string with '',where you actual select should look like below.
SELECT * FROM KART where SERI_NO in ('ABC','XCV');
so please check with this one check the value of the "swhere"
I am very new to Java. I have a task with two steps.
I want to read all data from a .csv file.
After reading that data I have to put it into a SQL Server database.
I have done step one. I'm able to read the .csv file data, but I don't know that how to insert it into a database.
Here's my code for fetching the .csv file data:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;
public class DBcvsdataextractor {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String fileName="D:/USPresident Wikipedia URLs Thumbs HS.csv";
try {
BufferedReader br = new BufferedReader( new FileReader(fileName));
StringTokenizer st = null;
int lineNumber = 0, tokenNumber = 0;
while( (fileName = br.readLine()) != null)
{
if(lineNumber++ == 0)
continue;
//break comma separated line using ","
st = new StringTokenizer(fileName, ",");
while(st.hasMoreTokens())
{
//display csv values
tokenNumber++;
System.out.print(st.nextToken() + '\t');
}
//new line
System.out.println(" ");
//reset token number
tokenNumber = 0;
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Now, how do I insert that data into SQL Server?
The SQL Server has a tool for this.
Like this:
BULK INSERT CSVTest
FROM 'c:\csvtest.txt'
WITH
(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
Use this command in your java, using JDBC connection, for example.
Hope this helps.
SQL Server file CSV
If you really want to do this with Java, and really want to write your own CSV parser as you currently did, you can
Instead of printing out each 'CSV-file value', you will have to store them. You could for example use an ArrayList for each column in the CSV file, and populate those while reading the CSV file
Once the file is read, you can loop over those ArrayList instances again to construct one big INSERT statement for all data, or one INSERT statement for each row you encountered in the CSV file. If you would opt for the last option, it is not even necessary to use those ArrayList instances. In that case you could construct an indiviual INSERT statement while reading the CSV file, and submit it to the DB after each time a row has been read.
I know the approach of constructing your query while reading the CSV file would be possible as well if you want to go for one big INSERT statement, but separating the INSERT from the reading of the CSV file has the big advantage you can replace your own CSV parser later on by a standard one without too much trouble.
You can customize below class to insert data into sql server.
File ImportCsv.java
package com.example.demo;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import com.opencsv.CSVReader;
public class ImportCsv
{
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException
{
readCsv();
}
private static void readCsv() throws UnsupportedEncodingException, FileNotFoundException
{
Reader readerstream = new InputStreamReader(new FileInputStream("D:\\file.csv"), "Unicode");
try (CSVReader reader = new CSVReader(readerstream, ',');
Connection connection = DBConnection.getConnection();)
{
String insertQuery = "Insert into [dbo].[tableName] ([Column1],[Column2],[Column3], [Column4],...[Column8]") values (?,?,?,?,?,?,?,?)";
PreparedStatement pstmt = connection.prepareStatement(insertQuery);
String[] rowData = null;
int i = 0;
while((rowData = reader.readNext()) != null){
for (String data : rowData)
{
//System.out.println(new String(data.replace(" ","")));
String strLine = new String(data.replace(" ",""));
String[] splited = strLine.split("\\s+");
pstmt.setNString(1, splited[0]);
pstmt.setNString(2, splited[1]);
pstmt.setNString(3, splited[2]);
pstmt.setNString(4, splited[3]);
pstmt.setNString(5, splited[4]);
pstmt.setNString(6, splited[5]);
pstmt.setNString(7, splited[6]);
try {
pstmt.setNString(8, splited[7]);
}catch(Exception e) {
}
if (++i % 8 == 0) {
pstmt.addBatch();// add batch
}
if (i % 80 == 0) {// insert when the batch size is 10
pstmt.executeBatch();
}
}}
System.out.println("Data Successfully Uploaded");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
DBConnection.java
package com.example.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
static {
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
String url = "jdbc:sqlserver://localhost:1433;" +
"databasename=myDBName;user=user;password=pwd;sendStringParametersAsUnicode=true;";
Connection con =DriverManager.getConnection(url);
return con;
}
}
I've tried several spots to insert the finally block but no matter what I try it ends up making the code worse.
Here is my code, the 4th to last ending curly bracket is the one giving me the error. Any thoughts?
package com.tunestore.action;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.DynaActionForm;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.owasp.validator.html.*;
import org.owasp.esapi.*;
public class DownloadAction extends Action
{
private static final Log log = LogFactory.getLog(DownloadAction.class);
public static String DB_URL;
static
{
if (System.getProperty("tunestore.db.location") != null)
{
DB_URL = "jdbc:derby://localhost:1527/" + System.getProperty("tunestore.db.location");
}
else
{
DB_URL = "jdbc:derby://localhost:1527/" + System.getProperty("user.home") + "/.tunestore";
}
System.setProperty("jdbc.tunestore.url", DB_URL);
}
public static Connection getConnection() throws Exception
{
log.info("Opening database at " + DB_URL);
Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
Connection conn = DriverManager.getConnection(DB_URL);
return conn;
}
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
DynaActionForm daf = (DynaActionForm)form;
String user = (String)request.getSession(true).getAttribute("USERNAME");
if(user != null)
{
Connection conn = null;
try
{
conn = DownloadAction.getConnection();
String sql2 = "SELECT ID FROM CD WHERE CD.BITS = ?";
PreparedStatement stmt2 = conn.prepareStatement(sql2);
stmt2.setString(1, request.getParameter("cd"));
ResultSet rs2 = stmt2.executeQuery();
rs2.next();
String sql = "SELECT COUNT(*) "
+ "FROM TUNEUSER_CD "
+ "WHERE TUNEUSER_CD.TUNEUSER = ? AND TUNEUSER_CD.CD = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, user);
stmt.setInt(2, rs2.getInt(1));
ResultSet rs = stmt.executeQuery();
rs.next();
int owned = rs.getInt(1);
if(owned == 1)
{
try
{
// Try to open the stream first - if there's a goof, it'll be here
InputStream is = this.getServlet().getServletContext().getResourceAsStream("/WEB-INF/bits/" + request.getParameter("cd"));
if (is != null)
{
response.setContentType("audio/mpeg");
response.setHeader("Content-disposition", "attachment; filename=" + daf.getString("cd"));
byte[] buff = new byte[4096];
int bread = 0;
while ((bread = is.read(buff)) >= 0)
{
response.getOutputStream().write(buff, 0, bread);
}
}
else
{
ActionMessages errors = getErrors(request);
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("download.error"));
saveErrors(request, errors);
return mapping.findForward("error");
}
}
catch (Exception e)
{
e.printStackTrace();
ActionMessages errors = getErrors(request);
errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("download.error"));
saveErrors(request, errors);
return mapping.findForward("error");
}
return null;
}
}
}
}
}
That bracket is the location where your outer try block ends. It has no catch block and no finally block, so you get an error. Just add one or the other immediately after the bracket, or remove the try if it's not needed.
You only have one catch block, but two trys. Add a catch block for the first try-catch and you should have your issue solved.
Edit: Why are you nesting try-catch in the first place? I don't believe there is any need to do so.
I'm trying to return an XML file based on my query results. I'm very new to this so I'm not really sure where I'm going wrong. Is this a realistic way to go about doing this or is there something simpler? Right now I'm getting these exceptions:
Error performing query: javax.servlet.ServletException: org.xml.sax.SAXParseException: Content is not allowed in prolog.
If I run my query in isql*plus, it does execute
import java.io.*;
import java.util.*;
import java.sql.*; // JDBC packages
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class step5 extends HttpServlet {
public static final String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";
public static final String URL = "jdbc:odbc:rreOracle";
public static final String username = "cm485a10";
public static final String password = "y4e8f7s5";
SAXParserFactory factory;
public void init() throws ServletException {
factory = SAXParserFactory.newInstance();
}
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
Connection con = null;
try {
Class.forName(DRIVER);
con = DriverManager.getConnection(URL,username,password);
try {
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT sale_id, home_id, agent_id, customer_id FROM sale");
String xml = "";
xml = xml + "<sales_description>";
xml = xml + "<sale>";
boolean courseDataDone = false;
while (rs.next()) {
String sale_id = rs.getString(1);
String home_id = rs.getString(2);
String agent_id = rs.getString(3);
String customer_id = rs.getString(4);
if (!courseDataDone) {
xml = xml + "<sale_id>" + sale_id + "</sale_id>" +
"<home_id>" + home_id + "</home_id>" +
"<agent_id>" + agent_id + "</agent_id>" +
"<customer_id>" + customer_id + "</customer_id>" +
"" +
"";
courseDataDone = true;
}
}
xml = xml + "</sale>" +
"</sales_description>";
try {
SAXParser parser = factory.newSAXParser();
InputSource input = new InputSource(new StringReader(xml));
parser.parse(input, new DefaultHandler());
} catch (ParserConfigurationException e) {
throw new ServletException(e);
} catch (SAXException e) {
throw new ServletException(e);
}
response.setContentType("text/xml;charset=UTF-8");
out.write(xml);
} catch(Exception ex) {
out.println("Error performing query: " + ex);
con.close();
return;
}
} catch(Exception ex) {
out.println("Error performing DB connection: " + ex);
return;
}
}
}
Any help/tips would be appreciated.
You're missing the prolog. Add this to beginning of your XML:
<?xml version="1.0" encoding="UTF-8"?>
By the way, you don't need the SAX parser here. You aren't modifying the XML at all. Get rid of the parser and just write xml directly to the response. You are also not handling JDBC resources correctly in try-with-resources. Here's a basic example of the improvement:
response.setContentType("text/xml;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.append("<sales_description>");
try (
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT sale_id, home_id, agent_id, customer_id FROM sale");
) {
if (resultSet.next()) {
writer.append("<sale>");
writer.append("<sale_id>").append(resultSet.getString("sale_id")).append("</sale_id>");
writer.append("<home_id>").append(resultSet.getString("home_id")).append("</home_id>");
writer.append("<agent_id>").append(resultSet.getString("agent_id")).append("</agent_id>");
writer.append("</sale>");
}
} catch (SQLException e) {
throw new ServletException(e);
}
writer.append("</sales_description>");
To write all records, just replace if (resultSet.next()) by while (resultSet.next()).
To handle the exception more gracefully, i.e. throwing an ServletException which ends in an error page instead of a halfbaked XML, you'd like to build the XML using StringBuilder. Just replace PrintWriter by new StringBuilder() and then at end, do response.getWriter().write(builder.toString()).
One tip would be layering your code a bit more. Servlets shouldn't be importing from java.sql. Put that code in a separate class, test it, and let your servlet call its methods.
You're creating XML in the most brain dead way possible by concatentating strings that way. Why not use a library like JDOM or at least a StringBuilder?
And skaffman's right: your code makes no sense otherwise.
Here are a few ideas you can think about for layering. Start with a model object for Sale - after all, Java's an object-oriented language:
package badservlet.model;
public class Sale
{
private String saleId;
private String homeId;
private String agentId;
private String customerId;
public Sale(String saleId, String homeId, String agentId, String customerId)
{
if ((saleId == null) || (saleId.trim().length() == 0)
throw new IllegalArgumentException("sales id cannot be blank or null");
if ((homeId == null) || (homeId.trim().length() == 0)
throw new IllegalArgumentException("home id cannot be blank or null");
if ((agentId == null) || (agentId.trim().length() == 0)
throw new IllegalArgumentException("agent id cannot be blank or null");
if ((customerId == null) || (customerId.trim().length() == 0)
throw new IllegalArgumentException("customer id cannot be blank or null");
this.saleId = saleId;
this.homeId = homeId;
this.agentId = agentId;
this.customerId = customerId;
}
public String getSaleId()
{
return saleId;
}
public String getHomeId()
{
return homeId;
}
public String getAgentId()
{
return agentId;
}
public String getCustomerId()
{
return customerId;
}
#Override
public String toString()
{
return "Sale{" +
"saleId='" + saleId + '\'' +
", homeId='" + homeId + '\'' +
", agentId='" + agentId + '\'' +
", customerId='" + customerId + '\'' +
'}';
}
}
For persistence, start with a DAO interface:
package badservlet.persistence;
import badservlet.model.Sale;
import java.sql.SQLException;
import java.util.List;
public interface SaleDao
{
List<Sale> find() throws SQLException;
}
And its implementation:
package badservlet.persistence;
import badservlet.model.Sale;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class SaleDaoImpl implements SaleDao
{
private static final String SELECT_ALL_SQL = "SELECT sale_id, home_id, agent_id, customer_id FROM sale";
private Connection connection;
public SaleDaoImpl(Connection connection)
{
this.connection = connection;
}
public SaleDaoImpl(DataSource dataSource) throws SQLException
{
this(dataSource.getConnection());
}
public List<Sale> find() throws SQLException
{
List<Sale> allSales = new ArrayList<Sale>();
Statement st = null;
ResultSet rs = null;
try
{
st = this.connection.createStatement();
rs = st.executeQuery(SELECT_ALL_SQL);
while (rs.next())
{
String saleId = rs.getString("sale_id");
String homeId = rs.getString("home_id");
String agentId = rs.getString("agent_id");
String customerId = rs.getString("customer_id");
Sale sale = new Sale(saleId, homeId, agentId, customerId);
allSales.add(sale);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
finally
{
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (st != null) st.close(); } catch (SQLException e) { e.printStackTrace(); }
}
return allSales;
}
}
And an object-to-XML unmarshaller:
package badservlet.xml;
import badservlet.model.Sale;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.transform.JDOMResult;
import javax.xml.bind.JAXBException;
import javax.xml.transform.Result;
import java.util.List;
public class SaleUnmarshaller
{
public void unmarshal(Object object, Result xml) throws JAXBException
{
List<Sale> allSales = (List<Sale>) object;
Document document = new Document(new Element("sales"));
for (Sale sale : allSales)
{
Element child = new Element("sale");
child.setAttribute("id", sale.getSaleId());
child.addContent(new Element("home", sale.getHomeId()));
child.addContent(new Element("agent", sale.getAgentId()));
child.addContent(new Element("customer", sale.getCustomerId()));
document.addContent(child);
}
JDOMResult result = new JDOMResult();
result.setDocument(document);
xml = result;
}
}
Let your servlet instantiate these objects and call their methods.
It might look more complicated - more classes than just one - but you've accomplished two things: you've broken your problem down into smaller pieces, and you can test them separately.
What are you trying to accomplish here? This code looks very confusing for several reasons:
You're presumably trying to build up an XML string, but you're not appending any XML tags to it at all.
There's a lot of no-ops in there, such as xml = xml + ""; which doesn't achieve anything.
I'm not 100% sure what you want to achieve in the try block near the end. This block will have the side-effect of ensuring your xml string is valid XML, but if this is what you want to do there are probably clearer (and more efficient) ways of validating. If you're hoping it will magically transform your String into XML, then it won't (in fact no matter what, it can't modify the contents of the xml variable so this would be a no-op.
Perhaps it would help if you talked through what you're trying to do here, with particular reference to what you expect the state of affairs to be at each stage. Right now, you're building up a string that looks something like:
FirstSaleIDFirstHomeFirstAgentFirstCustomerSecondSaleIDSecondHomeSecondAgentSecondCustomer...
Then you try to parse this as XML. As you might expect, this is not valid XML hence the parser throws the error (in particular "no content in prolog" means that you have character data before the first tag definition).
I would give you advice on how to improve this but I really have no idea what you expect this to do...
Rather than using String concatanation for building XML, Trying using XML API's like DOM, JDOM etc.
Few Tutorial links:
http://www.w3schools.com/dom/default.asp
http://www.xul.fr/en/dom/
http://swik.net/JDOM+Tutorial
http://www.ibm.com/developerworks/java/library/j-jdom/
If we assume that this values you retrive form database
|sale_id | home_id | agent_id | customer_id |
| 1 | 10 | 100 | 1000 |
| 2 | 20 | 200 | 2000 |
| 3 | 30 | 300 | 3000 |
the xml a the end look like this
1010100100020003000
And after all You are tying to create a XML file from this.
What You should read about:
First about the ResultSet, i really doubt that those id are string not numbers.
next the class StringBuilder, the way you concat strings is wrong because strings is inmutable.
And for sure you should look about the Java API for XML