/**
* Hasan Diwan licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* My only request beyond the license is that you let me know how you use this package, and,
* if you should make any improvements or find/fix bugs, to let me know. Many thanks!
* @author Hasan Diwan
*/
package us.d8u.ebay;
import java.awt.BorderLayout;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import edu.stanford.ejalbert.BrowserLauncher;
import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException;
import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException;
/**
* This is the main/only class for ebay
*
*/
public class App {
static final String EBAY_URL = "http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-NAME=findItemsByKeywords&SERVICE-VERSION=1.0.0&SECURITY-APPNAME=ERM089df1-6a9f-427c-813c-51c02819f1d&RESPONSE-DATA-FORMAT=XML&REST-PAYLOAD&keywords=";
static final String EBAY_QUERY_KEY = "us.d8u.ebay.queryKey";
static final DefaultHttpClient client = new DefaultHttpClient();
protected static final Logger logger = Logger.getLogger("us.d8u.ebay.App");
protected static final int LOCATION_INDEX = 2, DATE_INDEX = 3,
TITLE_INDEX = 0, PRICE_INDEX = 1;
private static boolean updateCheck() {
return true;
}
public static void main(final String[] args) {
try {
if ((System.getProperty("debug") == null) && !updateCheck()) {
JOptionPane
.showMessageDialog(null,
"Update available -- replace code with http://bit.ly/13MNvdl");
}
} catch (HeadlessException e2) {
logger.fatal("Need graphics, dying...");
return;
}
final DefaultTableModel model = new DefaultTableModel() {
/**
*
*/
private static final long serialVersionUID = -3223921605077026L;
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
final Vector<Vector<String>> data = new Vector<Vector<String>>();
final Vector<String> headers = new Vector<String>();
headers.add("Item title");
headers.add("Price");
headers.add("Link");
headers.add("Ends at");
final JFrame mainFrame = new JFrame("eBay");
final Set<Double> _datasetSource = new HashSet<Double>();
_datasetSource.clear();
final JTextArea statisticsArea = new JTextArea();
statisticsArea.setEditable(false);
statisticsArea.setToolTipText(App.getStatisticsHelp());
final JTextField searchField = new JTextField();
searchField.setEditable(true);
JPanel searchPanel = new JPanel();
searchPanel.setLayout(new BorderLayout());
searchPanel.add(searchField, BorderLayout.NORTH);
searchPanel.setSize(mainFrame.getSize());
searchField.setSize(searchPanel.getSize());
final JTable tbl = new JTable();
final JPopupMenu ctxMenu = new JPopupMenu();
final JMenuItem copyItem = new JMenuItem(
"Copy data to clipboard in Excel (CSV) format");
tbl.setSize(mainFrame.getSize());
searchField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
System.setProperty(EBAY_QUERY_KEY,
(String) searchField.getText());
String query = new String();
try {
query = URLEncoder.encode(
(String) searchField.getText(), "utf-8");
} catch (UnsupportedEncodingException e1) {
logger.fatal(e1.getMessage(), e1);
}
HttpGet getMethod = new HttpGet(String.format("%s%s", EBAY_URL,
query));
HttpResponse response = null;
try {
response = client.execute(getMethod);
} catch (ClientProtocolException e1) {
logger.fatal(e1.getMessage(), e1);
} catch (IOException e1) {
logger.fatal(e1.getMessage(), e1);
}
final HttpEntity entity = response.getEntity();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = null;
try {
parser = factory.newSAXParser();
} catch (ParserConfigurationException e1) {
logger.fatal(e1.getMessage(), e1);
} catch (SAXException e1) {
logger.fatal(e1.getMessage(), e1);
}
try {
parser.parse(entity.getContent(), new DefaultHandler() {
private String relevant;
final int LINK_INDEX = 1, PRICE_INDEX = 2;
@Override
public void endDocument() {
statisticsArea
.setText("Data obtained, sorting by price");
model.setDataVector(data, headers);
List<Vector<String>> dataList = new ArrayList<Vector<String>>(
data);
Collections.sort(dataList,
new Comparator<Vector<String>>() {
@Override
public int compare(Vector<String> o1,
Vector<String> o2) {
int result = 0;
DateTimeFormatter endTimeFormatter = DateTimeFormat
.forPattern("yyyy-MM-dd'T'HH:mm:ss");
DecimalFormat formatter = (DecimalFormat) DecimalFormat
.getCurrencyInstance();
DateTime dt1 = endTimeFormatter
.parseDateTime(o1
.get(3)
.substring(
0,
o1.get(3)
.length() - 10));
DateTime dt2 = endTimeFormatter
.parseDateTime(o2
.get(3)
.substring(
0,
o1.get(3)
.length() - 10));
result = dt1.compareTo(dt2);
if (result == 0) {
Double d1 = null;
try {
d1 = (Double) formatter
.parse(o1.get(1))
.doubleValue();
} catch (ParseException e) {
logger.fatal(
e.getMessage(), e);
}
Double d2 = null;
try {
d2 = (Double) formatter
.parse(o2.get(1))
.doubleValue();
} catch (ParseException e) {
logger.fatal(
e.getMessage(), e);
}
result = d2.compareTo(d1);
}
return result;
}
});
data.removeAll(dataList);
data.addAll(dataList);
SummaryStatistics stats = new SummaryStatistics();
DecimalFormat decimalFormatter = (DecimalFormat) DecimalFormat
.getCurrencyInstance();
final StringBuffer csvBuffer = new StringBuffer();
csvBuffer.append("Auction Title, Price\n");
for (final Vector<String> auction : data) {
try {
final double value = decimalFormatter
.parse(auction.get(1))
.doubleValue();
stats.addValue(value);
csvBuffer.append(String.format(
"\"%s\", %.2f\n",
auction.get(TITLE_INDEX)
.replaceAll(",", "\\,"),
value));
_datasetSource.add(value);
} catch (ParseException e) {
logger.fatal(e.getMessage(), e);
}
}
copyItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
String _csv = csvBuffer.toString();
StringSelection csv = new StringSelection(
_csv);
Toolkit tk = Toolkit.getDefaultToolkit();
Clipboard clipboard = tk
.getSystemClipboard();
clipboard.setContents(csv, null);
}
});
ctxMenu.add(copyItem);
tbl.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent arg0) {
if (arg0.getClickCount() == 2) {
JTable target = (JTable) arg0
.getSource();
int row = target.getSelectedRow();
DefaultTableModel ourColumnModel = (DefaultTableModel) target
.getModel();
logger.warn((String) ourColumnModel.getValueAt(row, LOCATION_INDEX));
Toolkit tk = Toolkit
.getDefaultToolkit();
Clipboard pb = tk.getSystemClipboard();
StringSelection toClipboard = new StringSelection(
(String) ourColumnModel
.getValueAt(row,
LOCATION_INDEX));
pb.setContents(toClipboard, null);
}
if (SwingUtilities.isRightMouseButton(arg0)
|| arg0.getModifiers() == InputEvent.CTRL_MASK) {
ctxMenu.show((JTable) arg0.getSource(),
arg0.getX(), arg0.getY());
}
}
private void logClick(String valueAt) {
}
});
statisticsArea.setText(stats.toString());
tbl.setModel(model);
tbl.getColumnModel()
.getColumn(TITLE_INDEX)
.setMaxWidth(
mainFrame.getContentPane()
.getWidth());
tbl.getColumnModel().getColumn(1).setMinWidth(0);
tbl.getColumnModel()
.getColumn(1)
.setMaxWidth(
mainFrame.getContentPane()
.getWidth() / 2);
resize(tbl.getColumnModel().getColumn(2));
resize(tbl.getColumnModel().getColumn(3));
model.fireTableChanged(new TableModelEvent(model,
TableModelEvent.INSERT));
try {
EntityUtils.consume(entity);
} catch (IOException e) {
logger.fatal(e.getMessage(), e);
}
}
private void resize(TableColumn column) {
column.setMinWidth(0);
column.setMaxWidth(0);
}
@Override
public void startDocument() {
data.clear();
statisticsArea.setText("Parsing XML");
}
String element;
@Override
public void startElement(String ns, String localName,
String qName, Attributes attrs) {
element = qName;
}
@Override
public void characters(char[] ch, int begin, int end) {
String relevant = new String(ch, begin, end);
this.relevant = this.relevant + relevant;
}
Vector<String> itemData = new Vector<String>();
@Override
public void endElement(String ns, String localName,
String name) {
String qName = element;
if (qName.equals("itemId")) {
try {
String link = itemData.get(LINK_INDEX);
String price = itemData.get(PRICE_INDEX);
itemData.set(LINK_INDEX, price);
itemData.set(PRICE_INDEX, link);
data.add(itemData);
} catch (ArrayIndexOutOfBoundsException e) {
// take care of first element, where
// collection is empty
} finally {
itemData = new Vector<String>();
}
} else if (qName.equals("convertedCurrentPrice")) {
Double price = new Double(relevant);
DecimalFormat nf = (DecimalFormat) DecimalFormat
.getCurrencyInstance();
itemData.add(nf.format(price));
} else if (qName.equals("title")) {
itemData.add(relevant);
} else if (qName.equals("endTime")) {
DateTimeFormatter formatter = ISODateTimeFormat
.dateTime();
DateTime date = formatter
.parseDateTime(relevant);
itemData.add(date.toString());
} else if (qName.equals("viewItemURL")) {
itemData.add(relevant);
}
this.relevant = "";
}
});
} catch (IllegalStateException e) {
logger.fatal(e.getMessage(), e);
} catch (SAXException e) {
logger.fatal(e.getMessage(), e);
} catch (IOException e) {
logger.fatal(e.getMessage(), e);
}
}
});
JScrollPane scrollPane = new JScrollPane(tbl);
tbl.setSize(scrollPane.getSize());
scrollPane.setSize(mainFrame.getSize());
mainFrame.setLayout(new BorderLayout());
mainFrame.add(searchPanel, BorderLayout.NORTH);
mainFrame.add(scrollPane, BorderLayout.CENTER);
mainFrame.add(statisticsArea, BorderLayout.SOUTH);
mainFrame.pack();
logger.info(mainFrame.getSize().width);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
private static String getIpV4Address() {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet getMethod = new HttpGet("http://api.externalip.net/ip");
HttpResponse response = null;
try {
response = client.execute(getMethod);
} catch (ClientProtocolException e1) {
logger.fatal(e1.getMessage(), e1);
} catch (IOException e1) {
logger.fatal(e1.getMessage(), e1);
}
String ipv4Address = null;
try {
ipv4Address = EntityUtils.toString(response.getEntity());
} catch (org.apache.http.ParseException e) {
logger.fatal(e.getMessage(), e);
} catch (IOException e) {
logger.fatal(e.getMessage(), e);
}
return ipv4Address;
}
private static String getStatisticsHelp() {
String ret = "<html>N - number of entries used to calculate the rest of the stuff<br>"
+ "Min - minimum price<br>"
+ "Max - maximum price<br>"
+ "Mean - sum of prices/number of entries<br>"
+ "Geometric Mean - nth root of the product of n prices<br>"
+ "Variance - how far the prices are spread out<br>"
+ "Sum of Squres - sum of the difference of the prices and their mean<br>"
+ "Standard Deviation - another measure of the variance<br>"
+ "Sum of Logs - sum of the logs to base e</html>";
return ret;
}
}