package com.sams.jws.chapter15;
/**
 * FileRetrieverServlet
 * Serwlet demonstrujący wykorzystanie JAXM. Wywołuje zdalną usługę sieciową
 * obsługi plików, a następnie przetwarza wynik do postaci
 * czytelnej dla przeglądarki.
 */
// Ogólne JDK
import java.io.IOException;
import java.util.Iterator;
// JAXM
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPException;
import javax.xml.soap.AttachmentPart;
import javax.xml.messaging.URLEndpoint;
// JAF
import javax.activation.DataHandler;
// Serwlet
import javax.servlet.*;
import javax.servlet.http.*;

public class FileRetrieverServlet extends HttpServlet {
    private final static boolean DEBUG = true;
    private final static String FILE_SERVICE_URL =
        "http://localhost:8080/jaxm/servlet/com.sams.jws.chapter15.FileService";
    public URLEndpoint urlEndpoint = new URLEndpoint(FILE_SERVICE_URL);
    private final static String DEFAULT_TARGET = "/";
    public SOAPConnection soapConnection = null;
    /**
     * doGet()
     * Odpowiada na otrzymane z przeglądarki żądanie pobrania listy plików z 
     * FileService.
     * Obsługuje we właściwy sposób otrzymane wyniki, przekazując plik bezpośrednio do ]
     * przeglądarki, zwracając listę plików w katalogu lub zwracając stronę błędu z 
     * wyjaśnieniem, gdzie wystąpił błąd. Odpowiedni plik znajduje się w polu FileName 
     * łańcucha żądania.
     */
    public void doGet(
        HttpServletRequest httpServletRequest,
        HttpServletResponse httpServletResponse)
        throws ServletException {

        ServletOutputStream outputStream = null;
        try {
            outputStream = httpServletResponse.getOutputStream();

            String targetFile = httpServletRequest.getParameter("FileName");
            if ((targetFile == null) || (targetFile == ""))
                targetFile = DEFAULT_TARGET;

            if (DEBUG)
                System.out.println(
                    "FileRetrieverServlet otrzymał żądania pobrania pliku: " + targetFile);

            // Przesłanie żądania pobrania pliku do usługi FileService.
            SOAPMessage responseSoapMsg = sendRequestMsg(targetFile);

            // Pobranie kilku pomocniczych odwołań do komunikatu odpowiedzi.
            SOAPEnvelope responseSoapEnv = responseSoapMsg.getSOAPPart().getEnvelope();
            SOAPHeader responseSoapHdr = responseSoapEnv.getHeader();
            SOAPBody responseSoapBody = responseSoapEnv.getBody();

            // Określenie typu odpowiedzi i właściwa jej obsługa.
            String responseType =
                DocumentUtils.findValueOfChild(responseSoapHdr, "ResponseType");
            if ((responseType != null) && (responseType.equals("directoryListing"))) {
                // Zwrot odpowiedzi do przeglądarki w niezmienionej postaci. Można 
                // także.w tym miejscu zbudować dokument HTML zawierający spis pozycji 
                // katalogu z odpowiednim odsyłaczem do każdego pliku.
                httpServletResponse.setContentType("text/xml");
                responseSoapMsg.writeTo(outputStream);
            } else if (responseType.equals("attachedFile")) {
                // Zwrot załącznika.
                Iterator iterator = responseSoapMsg.getAttachments();
                if (iterator.hasNext()) {
                    // Zakłądamy, że pierwsza część załącznika jest poszukiwanym 
                    // plikiem. 
                    // Lepszym rozwiązaniem jest poszukanie odpowiedniego nagłówka MIME.
                    AttachmentPart attachmentPart = (AttachmentPart) iterator.next();
                    DataHandler dataHandler = attachmentPart.getDataHandler();
                    httpServletResponse.setContentType(dataHandler.getContentType());
                    dataHandler.writeTo(outputStream);
                } else {
                    renderErrorPage(outputStream, "Nie udało się zlokalizować załączonego pliku", targetFile);
                } // Else
            } else if (responseType.equals("fault")) {
                SOAPFault soapFault = responseSoapBody.getFault();
                httpServletResponse.setContentType("text/html");
                renderErrorPage(
                    outputStream,
                    "<B>Code:</B> " + soapFault.getFaultCode(),
                    "<B>Description:</B> " + soapFault.getFaultString());
            } else {
                // Nieznana odpowiedź
                httpServletResponse.setContentType("text/html");
                renderErrorPage(
                    outputStream,
                    "Serwer zwrócił uszkodzony komunikat odpowiedzi.",
                    "<B>Pobieranie pliku nie powiodło się:</B> " + targetFile);
            } 
            // Ogólne wyjątki obsługi SOAPMessage.
        } catch (SOAPException e) {
            System.err.println("Wystąpił ogólny wyjątek SOAPException: ");
            e.printStackTrace();
        } catch (IOException e) {
            System.err.println(
                "Wystąpił wyjątek IOException podczas próby zapisu do SOAPMessage: ");
            e.printStackTrace();
        } 
    } // doGet()
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
        try {
            // Inicjalizacja połączenia do wykorzystania przez wszystkie instancje.
            SOAPConnectionFactory soapConnFct = SOAPConnectionFactory.newInstance();
            soapConnection = soapConnFct.createConnection();
        } catch (SOAPException e) {
            System.err.println("Wystąpił ogólny wyjątek SOAPException: ");
            e.printStackTrace();
        }
    } // init()
    /**
     * renderErrorPage
     * Zwrot błędu w sformatowanym dokumencie HTML do strumienia ServletOutputStream
     */
    public void renderErrorPage(
        ServletOutputStream outputStream,
        String line1,
        String line2)
        throws IOException {
        outputStream.println("<HTML>");
        outputStream.println("Podczas obsługi żądania wystąpił błąd.<P>");
        outputStream.println(line1 + "<P>");
        outputStream.println(line2 + "<P>");
        outputStream.println("</HTML>");
    } // renderErrorPage()
    /**
     * sendRequestMsg
     * Wywołanie usługi sieciowej zdalnego dostępu do plików FileService i żądanie
     * pobrania pliku targetFile. Zwrot odpowiedzi SOAPMessage.
     */
    public SOAPMessage sendRequestMsg(String targetFile)
        throws SOAPException, IOException {

        // Inicjalizacja połączenia i profilu SOAP
        MessageFactory messageFactory = MessageFactory.newInstance();

        SOAPMessage requestSoapMsg = messageFactory.createMessage();

        SOAPPart requestSoapPart = requestSoapMsg.getSOAPPart();
        SOAPEnvelope requestSoapEnv = requestSoapPart.getEnvelope();
        SOAPHeader requestSoapHdr = requestSoapEnv.getHeader();
        SOAPBody requestSoapBody = requestSoapEnv.getBody();

        // Dołączenie pola nagłówka
        Name msgPurposeName = requestSoapEnv.createName("CmdName");
        SOAPHeaderElement msgPurposeElement =
            requestSoapHdr.addHeaderElement(msgPurposeName);
        msgPurposeElement.setMustUnderstand(true);
        msgPurposeElement.addTextNode("FileService");

        // Dołączenie pola ciała kwalifikowanego za pomocą przestrzeni nazw
        Name fileName = requestSoapEnv.createName("FileName");
        SOAPBodyElement fileNameElement = requestSoapBody.addBodyElement(fileName);
        fileNameElement.addTextNode(targetFile);

        // Zapis wszystkich zmian w komunikacie przed jego wyświetleniem. 
        // Wysłanie także niejawnie zapisze dokonane zmiany.
        requestSoapMsg.saveChanges();

        if (DEBUG) {
            System.out.println("FileRetrieverServlet wysyła komunikat:");
            requestSoapMsg.writeTo(System.out);
            System.out.println("\n");
        } 

        // Wysłanie żądania i zablokowanie aplikacji do momentu otrzymania odpowiedzi.
        SOAPMessage responseSoapMsg = soapConnection.call(requestSoapMsg, urlEndpoint);

        if (DEBUG) {
            System.out.println("FileRetrieverServlet otrzymał komunikat odpowiedzi:");
            responseSoapMsg.writeTo(System.out);
            System.out.println("\n");
        } 

        return responseSoapMsg;

    } // sendRequestMsg()
} // FileRetrieverServlet
