1
\$\begingroup\$

I have been writing/fixing Java code, but just getting into object design/architecture. I am writing a webservice client in Java to integrate a commercial Address Validation Geocoding Webservice into our application. Ours is a Tax software written in PowerBuilder running inside EAServer. I am writing the web service client in Java, so it can be integrated with the PB client through CORBA.

I have done a similar service earlier to get some GIS information and this was slightly simpler design handling only XML for both Request and Response. I handled getting/sending request and response in the controller itself.

I started using the same design and hit a road block: current web service handles both XML and REST (through HTTP GET URL); actually, there are 2 webservice URLs, the one for Address Validation/Geocoding supports XML or REST, and the other for searching addresses uses REST only. I want to design a generic request abstract class/interface and the controller that can be used for both the services. While trying to come up with the classes, I ran into a classic design issue. Now with Request itself can be a XML string or a URI object (for REST Request), my approach of getting the request and sending it in Controller seems flawed.

Should I make the Request object itself build and send XML/REST itself to the external Service or should I somehow manage to get different types of Requests into the Controller and send it from there (using getRequest and sendRequest)?

Also, I am learning to use Design Patterns in Java. What type of design pattern would be applicable here? I saw command pattern suggested for a similar client. Also, can MVC pattern be applied here?

The method marked as 3. is the meat of the client controller - it gets the Request object, sends the query after getting the XML from the Request object and finally parses the Response object returned to send the data back to the Legacy application in PB.

public class BoeGeoQueryManager {


  private void init(String aUrlStr) {

    try {
      URL endPoint = new URL(aUrlStr);
      GeoQuery_MyLAService service = new GeoQuery_MyLAServiceLocator();
      geoq = service.getGeoQuery_MyLAcfc(endPoint);
    } catch (MalformedURLException me) {
      logger.error("BOEGIS", "", this.toString() + " - " +  "init", "Error initializing. " + me.getMessage());
      me.printStackTrace();
    } catch (ServiceException se) {
      logger.error("BOEGIS", "", this.toString() + " - " +  "init", "Error initializing Service. " + se.getMessage());
      se.printStackTrace();
    }
  }

  // Search by Address
  public String queryBoeGis(String aAddress) throws Exception {
    BoeXMLRequest lRequest = new BoeXMLRequest(aAddress, 0, 0, GISRequest.SEARCH_MODE_ADDRESS);

    return queryBoeGis(lRequest);

  }

  // Search by Lat/Long
  public String queryBoeGis(double aLatitude, double aLongitude) throws Exception {
    BoeXMLRequest lRequest =
        new BoeXMLRequest(GISRequest.REQUEST_BLANK_ADDRESS, aLatitude, aLongitude,
            GISRequest.SEARCH_MODE_LATLONG);

    return queryBoeGis(lRequest);

  }

  // 3. The controller is doing the Webservice call here. I just pass in 
  // the Request object into this. Controller is fully aware it's a XML
  // Request/Response.
  public String queryBoeGis(BoeXMLRequest aRequest) throws Exception {

    String respXML = "";
    String reqXML = "";

    requestCount++;
    try {
      reqXML = aRequest.getXml();

      if (aRequest.isModeLatLong()) {
        respXML = geoq.qByCoords(reqXML);
      } else if (aRequest.isModeAddress()) {
        // search by address (or both)
        respXML = geoq.addressValidationService(reqXML);
      }
      respXML = XMLDocument.cleanup(respXML);
      BoeXMLResponse boeResponse = new BoeXMLResponse(respXML);

      // To be able to get a flattened XML to be sent to the Legacy application
      if (adjustXML)
        respXML = XMLExtractor.getAdjXml(aRequest, boeResponse);

    } catch (Exception e) {
      e.printStackTrace();
      respXML = "";
    }

    // Otherwise, return the original XML
    return respXML;
  }
}

My Request class looks like this (again stripped all comments and other stuff):

There can be more than one layer sent in Request, so I have:

protected Layer[]          layers;

in the super class, GISRequest. Layer contains arrays of fieldName and fieldValue.

public class BoeXMLRequest extends GISRequest {

  private static final String XML_EMPTY         = "";
  private final static String LAYERS_TAG        = PropsUtil.getString("BOEXML.LAYERS_TAG");
  private final static String COLUMN_SUFFIX     = "." + PropsUtil.getString("BOEXML.COLUMN_TAG");
  private final static String LAYER_NAME_SUFFIX = "." + PropsUtil.getString("BOEXML.LAYER_NAME_TAG");

  public BoeXMLRequest(String aAddress, double aLatitude, double aLongitude, String aSearchMode) {

    super(aAddress, aLatitude, aLongitude, aSearchMode);
    loadLayers();
    status = searchModeToStatus(aSearchMode);
  }


  public BoeXMLRequest(double aLatitude, double aLongitude) {
    this(GISRequest.REQUEST_BLANK_ADDRESS, aLatitude, aLongitude, GISRequest.SEARCH_MODE_LATLONG);
  }

  public String getXml() {
    String searchMode = getSearchMode();

    if (searchMode.equals(GISRequest.SEARCH_MODE_ADDRESS)) {
      return buildXml(address, "0|0", status);
    } else if (searchMode.equals(GISRequest.SEARCH_MODE_LATLONG)) {
      String latLong = String.valueOf(longitude) + "|" + String.valueOf(latitude);
      return buildXml(address, latLong, status);
    } else if (searchMode.equals(GISRequest.SEARCH_MODE_BOTH)) {
      String latLong = String.valueOf(longitude) + "|" + String.valueOf(latitude);
      return buildXml(address, latLong, status);

    }
    return XML_EMPTY;
  }

  protected String buildXml(String address, String latLong, String status) {
    String xmlStr =
        XMLDocument.wrapTag("qWhat", "addr_int") + XMLDocument.wrapTag("status", status)
            + XMLDocument.wrapTag("coordinates", latLong)
            + XMLDocument.wrapTag("address-geocode", address) + getLayerElement();
    // wrap the above element in root "Address-Request" with XML header.
    xmlStr = XMLDocument.wrapXml("Address-Request", xmlStr, true);
    return xmlStr;
  }

  private String getLayerElement() {
    String layerElement = "<layers>";

    // for (Layer layer : this.getLayers()) {

    for (int i = 0; i < this.layers.length; i++) {
      Layer layer = this.layers[i];
      layerElement += "<layer>";
      layerElement += "<name>" + layer.getName() + "</name>";
      layerElement += "<fields>";
      // for (Field field : layer.getFields()) {
      // for (String fieldName : layer.getFieldNames()) {
      for (int j = 0; j < layer.getFieldNames().length; j++) {
        String fieldName = layer.getFieldNames()[j];
        layerElement += "<field>" + fieldName + "</field>";
      }
      layerElement += "</fields>";
      layerElement += "</layer>";
    }
    layerElement += "</layers>";

    return layerElement;

  }

  private void loadLayers() {

    String[] lyrArr = PropsUtil.getString(LAYERS_TAG).split(",");

    layers = new Layer[lyrArr.length];
    for (int i = 0; i < layers.length; i++) {

      String layerName = PropsUtil.getString(lyrArr[i] + LAYER_NAME_SUFFIX);
      String[] flds = PropsUtil.getString(lyrArr[i] + COLUMN_SUFFIX).split(",");
      // no values in request structure
      layers[i] = new Layer(layerName, flds);
    }

  }

  private String searchModeToStatus(String searchMode) {
    String stat = "";
    if (searchMode.equals(GISRequest.SEARCH_MODE_ADDRESS)) {
      stat = PropsUtil.getString("BOERequest.Status.ADDRESS");
    } else if (searchMode.equals(GISRequest.SEARCH_MODE_LATLONG)) {
      stat = PropsUtil.getString("BOERequest.Status.LATLONG");
    } else if (searchMode.equals(GISRequest.SEARCH_MODE_BOTH)) {
      stat = PropsUtil.getString("BOERequest.Status.BOTH");

    }

    return stat;
  }
}

Note: My code has to be in Java 1.4 because of the Legacy EAServer.

Geocoder WebService Client

\$\endgroup\$
  • \$\begingroup\$ This question is probably a better fit on Programmers.SE! It will be closed in on CodeReview because.. there's no code to review. :p \$\endgroup\$ – IEatBagels Nov 16 '15 at 20:44
  • \$\begingroup\$ @TopinFrassi, Thanks for the feedback. I have updated it with previous client code I wrote. This is what I am basing my current program on and ran into design question. \$\endgroup\$ – SamV Nov 16 '15 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.