package edu.byu.cs.roots.opg.nfs.newapi;
import java.awt.AWTError;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.xerces.dom.ElementNSImpl;
import org.apache.xerces.impl.dv.util.Base64;
import org.familysearch.platform.FamilySearchPlatform;
import org.familysearch.platform.ct.ParentChildRelationship;
import org.familysearch.ws.client.identity.v2a.schema.Identity;
import org.gedcomx.atom.Feed;
import org.gedcomx.conclusion.Person;
import org.gedcomx.links.Link;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import edu.byu.cs.roots.opg.io.GedcomRecord;
import edu.byu.cs.roots.opg.io.HTTPSecureWrapper;
import edu.byu.cs.roots.opg.nfs.RelationMap;
public class NFSDownloadManager extends SwingWorker<Void,String>{
private final static String devKey = "WCQY-7J1Q-GKVV-7DNM-SQ5M-9Q5H-JX3H-CMJK";
private final static String nfsKey = "3MRF-LC1D-JJ5S-ML42-223W-7PD7-KLR8-6B83";
private final static String usedAccessKey = devKey;
private final static String agentName = "OnePageGenealogy";
private String baseUrl = "https://sandbox.familysearch.org";
private String discoveryUrl = "/.well-known/app-meta.xml";
private String parentRelationshipRel = "http://familysearch.org/links/relationships/parents";
private String childRelationshipRel = "http://familysearch.org/links/relationships/children";
private String spouseRelationshipRel = "http://gedcomx.org/links/relationships/spouse";
private String atomFeedURI = "http://www.w3.org/2005/Atom";
private DefaultHttpClient httpclient;
private ResponseHandler<String> responseHandler;
private ThreadSafeClientConnManager cm;
private RelationMap relMap = null;
private GedcomRecord gedrecord = null;
private String username = "";
private String password = "";
private String sessionId = "";
private Object keyLock;
private NFSLoginFrame loginFrame = null;
private DownloadOptionDialog downloadOptions = null;
private DownloadProgress progress = null;
public NFSDownloadManager(){
relMap = new RelationMap();
gedrecord = new GedcomRecord();
progress = new DownloadProgress(0);
keyLock = new Object();
initializeHttpDevices();
}
@Override
protected void process(List<String> updatedValue){
StringBuilder build = new StringBuilder();
for(String s : updatedValue)
build.append(s+"\n");
String messages = build.toString();
progress.updateProgress(relMap.getAllDone().size(), relMap.getAllDone().size() + relMap.getAllNotDone().size(), messages);
}
@Override
protected Void doInBackground(){
Thread.currentThread().setName("NFSDownloadManagerThread");
try{
getUserLogin();
authenticateNFS();
getUserDownloadOptions();
activateDownloadProgress();
downloadRoot();
}catch(UsernamePasswordException e){
JOptionPane.showMessageDialog(null,
e.getMessage(),
"Error!", JOptionPane.ERROR_MESSAGE);
}catch(DownloadCancelledException e){
System.out.println(e.getMessage());
}catch(UnknownErrorException e){
JOptionPane.showMessageDialog(null,
e.getMessage(),
"Error!", JOptionPane.ERROR_MESSAGE);
}catch(DiscoveryMissingException e){
JOptionPane.showMessageDialog(null,
e.getMessage(),
"Error!", JOptionPane.ERROR_MESSAGE);
}
return null;
}
private void getUserLogin() throws DownloadCancelledException{
//create dialog and retrieve username and password, and load those in
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
loginFrame = new NFSLoginFrame(keyLock);
loginFrame.pack();
loginFrame.setVisible(true);
}
});
lock();
if(loginFrame.getCancelled())
throw new DownloadCancelledException();
username = loginFrame.getUsername();
password = loginFrame.getPassword();
System.out.println("UN: " + username + " PW: " + password);
}
private void authenticateNFS() throws UsernamePasswordException, UnknownErrorException, DiscoveryMissingException{
HttpGet get = new HttpGet(baseUrl+discoveryUrl);
get.addHeader("GET", "/.well-known/app-meta.xml");
get.addHeader("Accept", "application/x-gedcom-conclusion-v1+xml");
try {
String responseBody = (httpclient.execute(get, responseHandler));
System.out.println(responseBody);
Feed extract = (Feed) JAXBContext.newInstance(Feed.class).createUnmarshaller().unmarshal(new StringReader(responseBody));
//Gets the link from the discovery to the Identity\Login resource
System.out.println(extract.toString());
String loginExtension="";
for(Link link : extract.getLinks()){
if(link.getRel().contentEquals("fs-identity-v2")){
loginExtension = link.getHref();
break;
}
}
if(loginExtension.contentEquals(""))
throw new DiscoveryMissingException();
String requestUrl = loginExtension;
get = new HttpGet(requestUrl+"?key="+usedAccessKey);
get.addHeader("User-Agent", agentName);
get.addHeader("Accept", "application/x-gedcom-conclusion-v1+xml");
String encodedLogin = Base64.encode(new String(username+":"+password).getBytes());
get.addHeader("Authorization","Basic "+encodedLogin);
responseBody = (httpclient.execute(get, responseHandler));
Identity identity = (Identity) JAXBContext.newInstance(Identity.class).createUnmarshaller().unmarshal(new StringReader(responseBody));
sessionId = identity.getSession().getId();
} catch (HttpResponseException e) {
//TODO find a better way of giving a more accurate error message
if(e.getStatusCode() == 401)
throw new UsernamePasswordException();
} catch(ClientProtocolException e){
throw new UnknownErrorException();
} catch (IOException e) {
throw new UnknownErrorException();
} catch (JAXBException e) {
throw new UnknownErrorException();
}
}
private void getUserDownloadOptions() throws DownloadCancelledException{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
downloadOptions = new DownloadOptionDialog(keyLock);
Dimension screenSize;
try {
Toolkit tk = Toolkit.getDefaultToolkit();
screenSize = tk.getScreenSize();
} catch (AWTError awe) {
screenSize = new Dimension(640, 480);
}
//Dialog dlgPreOrder = new PreOrderDialog(session, getJFrame());
int frameX = screenSize.width / 2 - downloadOptions.getWidth() / 2;
int frameY = screenSize.height / 2 - downloadOptions.getHeight() / 2;
downloadOptions.setBounds(frameX, frameY,downloadOptions.getWidth(), downloadOptions.getHeight());
downloadOptions.setVisible(true);
}
});
lock();
if(!downloadOptions.getDownload())
throw new DownloadCancelledException();
}
private void activateDownloadProgress(){
SwingUtilities.invokeLater(new Runnable(){
public void run() {
progress = new DownloadProgress(0);
Dimension screenSize;
try {
Toolkit tk = Toolkit.getDefaultToolkit();
screenSize = tk.getScreenSize();
} catch (AWTError awe) {
screenSize = new Dimension(640, 480);
}
//Dialog dlgPreOrder = new PreOrderDialog(session, getJFrame());
int frameX = screenSize.width / 2 - progress.getWidth() / 2;
int frameY = screenSize.height / 2 - progress.getHeight() / 2;
progress.setBounds(frameX, frameY, progress.getWidth(), progress.getHeight());
progress.setVisible(true);
progress.startTimer();
}
});
}
private void downloadRoot() throws UnknownErrorException, DiscoveryMissingException{
HttpGet get = new HttpGet(baseUrl+discoveryUrl);
get.addHeader("GET", "/.well-known/app-meta.xml");
get.addHeader("Accept", "application/x-gedcom-conclusion-v1+xml");
get.addHeader("Authorization", "Bearer " + sessionId);
String responseBody;
try {
responseBody = (httpclient.execute(get, responseHandler));
Feed extract = (Feed) JAXBContext.newInstance(Feed.class).createUnmarshaller().unmarshal(new StringReader(responseBody));
String requestLink = "";
for(Link link : extract.getLinks()){
if(link.getRel().contentEquals("current-user-person")){
requestLink=link.getHref();
break;
}
}
if(requestLink.contentEquals(""))
throw new DiscoveryMissingException();
get = new HttpGet(requestLink);
get.addHeader("Accept", "application/x-fs-v1+xml");
get.addHeader("Authorization", "Bearer " + sessionId);
String rootString = responseBody = (httpclient.execute(get,responseHandler));
System.out.println(responseBody);
FamilySearchPlatform root = (FamilySearchPlatform) JAXBContext.newInstance(FamilySearchPlatform.class).createUnmarshaller().unmarshal(new StringReader(responseBody));
Person rootPerson = root.getPersons().get(0);
String ancestryCode = "";
for(Link link : rootPerson.getLinkExtensions()){
if(link.getRel().contentEquals("ancestry"))
{
ancestryCode = link.getHref();
break;
}
}
get = new HttpGet(ancestryCode);
get.addHeader("Accept", "application/x-fs-v1+xml");
get.addHeader("Authorization", "Bearer " + sessionId);
String ancestryString = responseBody = (httpclient.execute(get,responseHandler));
System.out.println(ancestryString);
FamilySearchPlatform ancestry = (FamilySearchPlatform) JAXBContext.newInstance(FamilySearchPlatform.class).createUnmarshaller().unmarshal(new StringReader(ancestryString));
ancestry.toString();
} catch (HttpResponseException e) {
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JAXBException e) {
e.printStackTrace();
}
}
public void initializeHttpDevices(){
HttpParams params = new BasicHttpParams();
SchemeRegistry registry = new SchemeRegistry();
cm = new ThreadSafeClientConnManager(params, registry);
httpclient = new DefaultHttpClient(cm, params);
httpclient = HTTPSecureWrapper.wrapClient(httpclient);
httpclient.getCredentialsProvider().clear();
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(baseUrl, 80),
new UsernamePasswordCredentials(username, password));
responseHandler = new BasicResponseHandler();
}
public void lock(){
synchronized(keyLock){
try {
System.out.println("LOCKING ON: " +Thread.currentThread().getName());
keyLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}