Here attached is our example, for revision 660156, of an interface to
an external BOINC database, yet read only.

It is injected in the SocialApiGuiceModule.java as follows from the
patch here. Note that we violate the naming conventions so we are easy
to detect and remove :-)

The example is just an extended version of the samplecontainer. It can
be of some interest to novice people (as ourselves) because we use
heavily xpath and the apache MultiThreadedHttpConnectionManager; so it
somehow extends the samplecontainer example.

Of course, it is of no real use without the database side, which
creates the xml. But xpath simplifies the customization process. Our
code in this side is python, but it is not useful except if you are
planning to use shindig in a BOINC database.

Alejandro

Index: java/org/apache/shindig/social/SocialApiGuiceModule.java
===================================================================
--- java/org/apache/shindig/social/SocialApiGuiceModule.java
(revision 660156)
+++ java/org/apache/shindig/social/SocialApiGuiceModule.java    (working copy)
@@ -22,9 +22,9 @@
 import org.apache.shindig.social.opensocial.DataService;
 import org.apache.shindig.social.opensocial.OpenSocialDataHandler;
 import org.apache.shindig.social.opensocial.PeopleService;
-import org.apache.shindig.social.samplecontainer.BasicActivitiesService;
+import org.apache.shindig.social.RemoteHttpContainer.BasicActivitiesService;
 import org.apache.shindig.social.samplecontainer.BasicDataService;
-import org.apache.shindig.social.samplecontainer.BasicPeopleService;
+import org.apache.shindig.social.RemoteHttpContainer.BasicPeopleService;
 import org.apache.shindig.social.samplecontainer.StateFileDataHandler;

 import com.google.inject.AbstractModule;
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF 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.
 */
package org.apache.shindig.social.RemoteHttpContainer;

import org.apache.shindig.common.SecurityToken;

import org.apache.shindig.social.ResponseItem;
import org.apache.shindig.social.ResponseError;
import org.apache.shindig.social.opensocial.ActivitiesService;
import org.apache.shindig.social.opensocial.model.Activity;
import org.json.JSONObject;

import com.google.inject.Inject;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Date;

/**
 * @author Cassandra Doll <[EMAIL PROTECTED]>
 */
public class BasicActivitiesService implements ActivitiesService {


private XmlFileFetcher xmlFileFetcher;
  @Inject
  public BasicActivitiesService(XmlFileFetcher fetcher) {
   this.xmlFileFetcher = fetcher ; 
  }


  public ResponseItem<List<Activity>> getActivities(List<String> ids, 
      SecurityToken token) {
     // Map<String, List<Activity>> allActivities =
     //   XmlStateFileFetcher.get().getActivities();

    XmlFileFetcher fetcher= this.xmlFileFetcher;
    List<Activity> activities = new ArrayList<Activity>();

    for (String id : ids) {
      List<Activity> personActivities = // allActivities.get(id);
                                       fetcher.getActivities(id);  
      if (personActivities != null) {
        activities.addAll(personActivities);
      }
    }

    // TODO: Sort them
    return new ResponseItem<List<Activity>>(activities);
  }



  //esta la tomamos tal cual de la nueva version.
    public ResponseItem<Activity> getActivity(String id, String activityId,
      SecurityToken token) {
    List<String> ids = new ArrayList<String>();
    ids.add(id);

    List<Activity> allActivities = getActivities(ids, token).getResponse();
    for (Activity activity : allActivities) {
      if (activity.getId().equals(activityId)) {
        return new ResponseItem<Activity>(activity);
      }
    }
    return new ResponseItem<Activity>(ResponseError.BAD_REQUEST,
        "Activity not found", null);
  }


  public ResponseItem createActivity(String personId, Activity activity, 
        SecurityToken token) {
    // TODO: Validate the activity and do any template expanding
    //activity.setUserId(personId);
    //activity.setPostedTime(new Date().getTime());

    //XmlStateFileFetcher.get().createActivity(personId, activity);
    return new ResponseItem<JSONObject>(new JSONObject());
  }
}
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF 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.
 */
package org.apache.shindig.social.RemoteHttpContainer;

import org.apache.shindig.social.ResponseItem;
import org.apache.shindig.social.opensocial.PeopleService;
import org.apache.shindig.social.opensocial.model.IdSpec;
import org.apache.shindig.social.opensocial.model.Person;
import org.apache.shindig.social.opensocial.model.ApiCollection;
import org.apache.shindig.common.SecurityToken;
import org.json.JSONException;

import com.google.inject.Inject;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
import java.util.Comparator;

public class BasicPeopleService implements PeopleService {
  private static final Comparator<Person> NAME_COMPARATOR
      = new Comparator<Person>() {
    public int compare(Person person, Person person1) {
      String name = person.getName().getUnstructured();
      String name1 = person1.getName().getUnstructured();
      return name.compareTo(name1);
    }
  };


private XmlFileFetcher xmlFileFetcher;

  @Inject
  public BasicPeopleService(XmlFileFetcher fetcher) {
  this.xmlFileFetcher = fetcher;
    ;
  }


private List<Person> getPeople(List<String> ids, SecurityToken token) {
    List<Person> people = new ArrayList<Person>();
    for (String id : ids) {
     XmlFileFetcher fetcher= this.xmlFileFetcher;
      Person person = fetcher.getOnePerson(id);
      if (person != null) {
        if (id.equals(token.getViewerId())) {
          person.setIsViewer(true);
        }
        if (id.equals(token.getOwnerId())) {
          person.setIsOwner(true);
        }
        people.add(person);
      }
    }
    return people;
  }



  public ResponseItem<ApiCollection<Person>> getPeople(List<String> ids,
      SortOrder sortOrder, FilterType filter, int first, int max, 
      Set<String> profileDetails, SecurityToken token) {
    List<Person> people = new ArrayList<Person>();
    for (String id : ids) {
      XmlFileFetcher fetcher= this.xmlFileFetcher;
      Person person = fetcher.getOnePerson(id);  
      if (person != null) {
        if (id.equals(token.getViewerId())) {
          person.setIsViewer(true);
        }
        if (id.equals(token.getOwnerId())) {
          person.setIsOwner(true);
        }
        people.add(person);
      }
    }

    // We can pretend that by default the people are in top friends order
    if (sortOrder.equals(SortOrder.name)) {
      Collections.sort(people, NAME_COMPARATOR);
    }

    // TODO: The samplecontainer doesn't really have the concept of HAS_APP so
    // we can't support any filters yet. We should fix this.

    int totalSize = people.size();
    int last = first + max;
    people = people.subList(first, Math.min(last, totalSize));

    ApiCollection<Person> collection = new ApiCollection<Person>(people, first,
        totalSize);
    return new ResponseItem<ApiCollection<Person>>(collection);
  }


  //esto es nuevo, getPerson
  public ResponseItem<Person> getPerson(String id, SecurityToken token) {
    List<String> ids = new ArrayList<String>();
    ids.add(id);
    return new ResponseItem<Person>(getPeople(ids, token).get(0));
  }


  public List<String> getIds(IdSpec idSpec, SecurityToken token)
      throws JSONException {
     XmlFileFetcher fetcher= this.xmlFileFetcher;
    List<String> ids = new ArrayList<String>();
    switch(idSpec.getType()) {
      case OWNER:
        ids.add(token.getOwnerId());
        break;
      case VIEWER:
        ids.add(token.getViewerId());
        break;
      case OWNER_FRIENDS:
        ids.addAll(fetcher.getFriends(token.getOwnerId())); 
          //replaces ids.addAll(friendIds.get(token.getOwnerId()));
        break;
      case VIEWER_FRIENDS:
        ids.addAll(fetcher.getFriends(token.getOwnerId()));
            //ids.addAll(friendIds.get(token.getViewerId()));
        break;
      case USER_IDS:
        ids.addAll(idSpec.fetchUserIds());
        break;
    }
    return ids;
  }
}
package org.apache.shindig.social.RemoteHttpContainer;



import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;

import org.apache.shindig.social.opensocial.model.Activity;
import org.apache.shindig.social.opensocial.model.MediaItem;
import org.apache.shindig.social.opensocial.model.Name;
import org.apache.shindig.social.opensocial.model.Person;
import org.apache.shindig.social.opensocial.model.Address;
import org.apache.shindig.social.opensocial.model.Phone;
import org.apache.shindig.social.opensocial.model.Enum;

import com.google.inject.Inject;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.Integer;

import java.util.logging.Level;
import java.util.logging.Logger;



/**
 * @author Alejandro Rivero <[EMAIL PROTECTED]> 
 * code "inspired" in a basic container example by Cassandra Doll
 */

public class XmlFileFetcher {
  private static final String DEFAULT_STATE_URL
      = "http://registro.ibercivis.es/boincopensocial/";;

   private Document document;
   private Person SinglePerson;
   private List<String> PersonFriendId;
   private List<Activity> ListaActividades;
   private URI stateFile;
   private final HttpClient client ; 
     private static final Logger logger
      = Logger.getLogger("org.apache.shindig.social");



  @Inject
  public XmlFileFetcher ()
  {
     this.client = new HttpClient(new MultiThreadedHttpConnectionManager());
  }

  private Document fetchStateDocument(String via) {

    try {
     stateFile = new URI(DEFAULT_STATE_URL+via);
    } catch (URISyntaxException e) {
      throw new RuntimeException(
          "The default state file could not be fetched. ", e);
    }
     
    HttpMethod xml = new GetMethod(stateFile.toString());
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    // factory.setNamespaceAware(true); // never forget this! O no?

    String errorMessage = "The state file " + stateFile
        + " could not be fetched and parsed.";
    try {
      client.executeMethod(xml);
      if (xml.getStatusCode() != 200) {
        logger.log(Level.WARNING, "status="+xml.getStatusCode());
        xml.releaseConnection();
        throw new RuntimeException("Ha fallado una conexion a "+ stateFile.toString());
      }

      document = factory.newDocumentBuilder().parse(xml.getResponseBodyAsStream() );
      xml.releaseConnection();
      return document;
    } catch (SAXException e) {
      xml.releaseConnection();
      throw new RuntimeException(errorMessage, e);
    } catch (IOException e) {
      xml.releaseConnection();
      throw new RuntimeException(errorMessage, e);
    } catch (ParserConfigurationException e) {
       xml.releaseConnection();
      throw new RuntimeException(errorMessage, e);
    }
  }


//punto de entrada para las Actividades de una persona dada
//parece que por desconfianza (no hablamos java) las cosas gordas las dejamos colgando de la instancia y no locales a cada metodo. 
public List<Activity> getActivities(String clavePersona) {
    logger.log(Level.WARNING, "getActivities "+clavePersona );
    ListaActividades = new ArrayList<Activity>();
    // Element root = fetchStateDocument("people/null/"+clavePersona+"/@enviados").getDocumentElement();
    Element root = fetchStateDocument("people/user/"+clavePersona+"/@enviados").getDocumentElement();
    ListaActividades.addAll(AddActivities(root,"people","enviados"));
    //logger.log(Level.WARNING, "getActivities enviados done ");
    root = fetchStateDocument("people/user/"+clavePersona+"/@recibidos").getDocumentElement();
    ListaActividades.addAll(AddActivities(root,"people","recibidos"));
    //logger.log(Level.WARNING, "getActivities recibidos done " );
    root = fetchStateDocument("people/user/"+clavePersona+"/@validados").getDocumentElement();
    ListaActividades.addAll(AddActivities(root,"people","validados"));
    //logger.log(Level.WARNING, "getActivities validados done" );
    return ListaActividades;
}



//punto de entrada para la lista de amigos de una persona
  public  List<String> getFriends(String clavePersona) {
       logger.log(Level.WARNING, "getFriends "+clavePersona );
       Element root = fetchStateDocument("people/"+clavePersona+"/@friends").getDocumentElement(); 
       setupFriendsInXmlTag(root, "people");
    return PersonFriendId;
  }

// punto de entrada para los datos fijos de una persona
  public Person getOnePerson(String clavePersona) {
      logger.log(Level.WARNING, "getOnePerson "+clavePersona );
      Element root = fetchStateDocument("people/"+clavePersona+"/@self").getDocumentElement();
      setupPeopleInXmlTag(root, "people"); 
    return SinglePerson;
  }


//
//
//
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>        TO DO. NOW!
//
//
//
private  List<Activity> AddActivities ( Element root, String tagName, String IdentificadorDeActividad) {

//aqui la forma obvia es primero contar los nodos que hay, con un xpath.evaluate("count(/respuesta/people/person/) o
//como sea el sintaxis, y lueco hacer un bucle leyendo xpath.evaluate("/respuesta/people/person["+i+"]/authenticator/"
//o como sea el sintaxis; la otra posibilidad es extraer de golple todos los nodos y luego para
//cada uno de ellos ir haciendo un xpath("/person/authenticator"), etc. Como la velocidad importa un pimiento
//de momento, creo que es mejor tirar de la primera 

try {
    XPath xpath = XPathFactory.newInstance( XPathFactory.DEFAULT_OBJECT_MODEL_URI ).newXPath();
    int num_activities = ((Number) xpath.evaluate("count(/respuesta/people/person)", document, XPathConstants.NUMBER)).intValue();
    List<NodeList> datos = new ArrayList<NodeList>();
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/claimed_credit", document, XPathConstants.NODESET));
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/granted_credit", document, XPathConstants.NODESET));
    NodeList mod_time = (NodeList) xpath.evaluate("/respuesta/people/person/mod_time", document, XPathConstants.NODESET);
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/userid", document, XPathConstants.NODESET));
    NodeList authenticator = (NodeList) xpath.evaluate("/respuesta/people/person/authenticator", document, XPathConstants.NODESET);
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/hostid", document, XPathConstants.NODESET));
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/last_ip_addr", document, XPathConstants.NODESET));
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/external_ip_addr", document, XPathConstants.NODESET));
    datos.add((NodeList) xpath.evaluate("/respuesta/people/person/appid", document, XPathConstants.NODESET));

    List<String> mistags = new ArrayList<String>();
    mistags.add("claimed_credit");
    mistags.add("granted_credit");
    mistags.add("userid");
    mistags.add("hostid");
    mistags.add("last_ip_addr");
    mistags.add("external_ip_addr");
    mistags.add("app");

    List<Activity> Actividades = new ArrayList<Activity>();
    
   String Aut; 
   String J; 
   Map<String, String> mimapa;
    
   //out.print(num_activities);
   for (int j = 0; j < num_activities; j++) {
      
     //for (Node nodeitem: friendNodes) 
      J = new String();
      J = Integer.toString(j);
      Aut = new String();
      Aut= authenticator.item(j).getTextContent(); 
      Activity actividad = new Activity(J, Aut);
      actividad.setAppId(new String(IdentificadorDeActividad));

      Aut = mod_time.item(j).getTextContent();
      actividad.setPostedTime((long)Integer.parseInt(Aut));

      mimapa = new HashMap<String, String>();
      for (int i = 0; i < mistags.size(); i++) {
           Aut = datos.get(i).item(j).getTextContent();
           mimapa.put(mistags.get(i), Aut);
      }
      
      actividad.setTemplateParams(mimapa);

      // Activity.userid = authenticator.item(j).getTextContent();
      Actividades.add(actividad); 
      }
    
   return Actividades;
   
}    catch (XPathFactoryConfigurationException e) {
  logger.log(Level.WARNING, e.getMessage());
  return null;
}
  catch (XPathExpressionException e) {
  logger.log(Level.WARNING, e.getMessage());
  return null;

}
}

private void setupFriendsInXmlTag(Element root, String tagName) {

try {
    XPath xpath = XPathFactory.newInstance( XPathFactory.DEFAULT_OBJECT_MODEL_URI ).newXPath();
      NodeList friendNodes= (NodeList) xpath.evaluate("/respuesta/people/person/authenticator", document, XPathConstants.NODESET);

    PersonFriendId= new ArrayList<String>();
   //realmente hace falta un for iterado? Deberia poderse hacer de golpe sobre friendNodes.  
   //esto es, for( Node nodeitem: friendNodes) {}
   for (int j = 0; j < friendNodes.getLength(); j++) {
     //for (Node nodeitem: friendNodes) {
      String friendId = friendNodes.item(j).getTextContent();
      if (friendId != null && friendId.trim().length() != 0) {
        PersonFriendId.add(friendId.trim());

      }
    }
   return;
}    catch (XPathFactoryConfigurationException e) { 
         		logger.log(Level.WARNING, e.getMessage());
                       throw new RuntimeException("brrr"+tagName, e); }
     catch (XPathExpressionException e) { 
			logger.log(Level.WARNING, e.getMessage());
                       throw new RuntimeException("brrr"+tagName, e); }
}
  
  // root is en Element, but it is a Document too, it can be typecasted I hope 
  private void setupPeopleInXmlTag(Element root, String tagName) {
    // TODO: Use the opensource Collections library
     String name="nadie";
     String id="-0";
    try {
    XPath xpath = XPathFactory.newInstance( XPathFactory.DEFAULT_OBJECT_MODEL_URI ).newXPath();
    
      name=xpath.evaluate("/respuesta/people/person/name", document);
      id=xpath.evaluate("/respuesta/people/person/authenticator", document);
      SinglePerson = new Person(id, new Name(name));
      //pasamos de momento el email como unstructured, luego pasaremos ahi la de verdad 
      //y el email en su sitio
      Address direccion=new Address(xpath.evaluate("/respuesta/people/person/email_addr", document));
      direccion.setCountry(xpath.evaluate("/respuesta/people/person/country", document));
      direccion.setLocality(xpath.evaluate("/respuesta/people/person/postal_code", document));
      //problema: longitud y latitud son Float... es lioso de convertir
      //String auxiliar = xpath.evaluate("/respuesta/people/person/latitude", document);
      //Double aux2 =  Double.parseDouble(auxiliar);
      Double auxiliar1 = (Double) xpath.evaluate("/respuesta/people/person/latitude", document,
                                         XPathConstants.NUMBER);
      Float aux1 = new Float (auxiliar1);
      direccion.setLatitude(aux1);
      Double auxiliar2 = (Double) xpath.evaluate("/respuesta/people/person/longitude", document,
                                         XPathConstants.NUMBER);
      //Double aux2 = (Double) auxiliar2;
      Float aux2 = new Float (auxiliar2);
      direccion.setLongitude(aux2);
      SinglePerson.setCurrentLocation(direccion);
      if ("1".equals(xpath.evaluate("/respuesta/people/person/has_profile", document))){
         SinglePerson.setProfileUrl("http://registro.ibercivis.es/view_profile.php?userid=";);  //TODO: poner el userID
      }
      SinglePerson.setThumbnailUrl(xpath.evaluate("/respuesta/people/person/avatar", document));
      List<String> misTags = new ArrayList<String>();
      misTags.add("Creditos: " + xpath.evaluate("/respuesta/people/person/total_credit", document));
      misTags.add("Equipo: " + xpath.evaluate("/respuesta/people/person/equipo", document));
      misTags.add("Creditos_equipo: " + xpath.evaluate("/respuesta/people/person/equipo_total_credit", document));
      SinglePerson.setTags(misTags);

      return;
         
     } catch (XPathFactoryConfigurationException e) {
                       logger.log(Level.WARNING, e.getMessage()); 
                       throw new RuntimeException("brrr "+name+" "+id, e); }
       catch (XPathExpressionException e) {
                       logger.log(Level.WARNING, e.getMessage());
                       throw new RuntimeException("brrr"+name+" "+id, e); }
   }
}

Reply via email to