Package plugins.Freetalk.WoT

Source Code of plugins.Freetalk.WoT.WoTIdentity

/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package plugins.Freetalk.WoT;

import plugins.Freetalk.Freetalk;
import plugins.Freetalk.Identity;
import plugins.Freetalk.Persistent;
import plugins.Freetalk.Persistent.IndexedClass;
import plugins.Freetalk.exceptions.InvalidParameterException;
import freenet.keys.FreenetURI;
import freenet.support.Base64;
import freenet.support.CurrentTimeUTC;
import freenet.support.Logger;
import freenet.support.StringValidityChecker;
import freenet.support.codeshortification.IfNotEquals;
import freenet.support.codeshortification.IfNull;


/**
*
* Activation policy: WoTIdentity does automatic activation on its own.
* This means that WoTIdentity can be activated to a depth of only 1 when querying them from the database.
* All methods automatically activate the object to any needed higher depth.
*
* TODO: Change all code which queries for identities to use the lowest possible activation depth to benefit from automatic activation.
*
* @author xor (xor@freenetproject.org)
*/
@IndexedClass // TODO: Check whether we really need this index.
public class WoTIdentity extends Persistent implements Identity {
 
  /* Attributes, stored in the database. */
 
  @IndexedField
  private final String mID;
   
  /** The requestURI used to fetch this identity from Freenet */
  private final FreenetURI mRequestURI;
 
  /** The nickname of this Identity */
  private final String mNickname;
 
  /**
   * Used for garbage collecting old identities which are not returned by the WoT plugin anymore.
   * We delete them if their last fetch ID is different to the fetch ID of the current fetch.
   */
  private long mLastReceivedFromWoT;


  // TODO: Remove ID parameter and compute the ID from the URI
  public WoTIdentity(String myID, FreenetURI myRequestURI, String myNickname) {
    if(myID == null) throw new IllegalArgumentException("ID == null");
    if(myID.length() == 0) throw new IllegalArgumentException("ID.length() == 0");
    if(myRequestURI == null) throw new IllegalArgumentException("RequestURI == null");
    if(myNickname == null) throw new IllegalArgumentException("Nickname == null");
   
    try {
      validateNickname(myNickname);
    } catch (InvalidParameterException e) {
      throw new IllegalArgumentException(e);
    }
   
    mID = myID;
    mRequestURI = myRequestURI;
    mNickname = myNickname;
    mLastReceivedFromWoT = 0;
   
    IfNotEquals.thenThrow(IdentityID.construct(mID), IdentityID.constructFromURI(mRequestURI), "myID");
  }
 
  @Override
  public void databaseIntegrityTest() throws Exception {
    checkedActivate(1);
   
    IfNull.thenThrow(mID, "mID");
    IfNull.thenThrow(getRequestURI(), "mRequestURI");
    IfNull.thenThrow(mNickname, "mNickname");
   
    IfNotEquals.thenThrow(IdentityID.construct(mID), IdentityID.constructFromURI(getRequestURI()), "mID");
   
    try {
      validateNickname(mNickname);
    } catch (InvalidParameterException e) {
      throw new IllegalStateException(e);
    }
   
    if(mLastReceivedFromWoT < 0)
      throw new IllegalStateException("mLastReceivedFromWoT == " + mLastReceivedFromWoT);
  }
 

  public String getID() {
    checkedActivate(1); // String is a db4o primitive type so 1 is enough
    return mID;
  }
 
  /**
   * Generates a unique id from a {@link FreenetURI}.
   * It is simply a String representing it's routing key.
   * We use this to identify identities and perform requests on the database.
   *
   * @param uri The requestURI of the Identity
   * @return A string to uniquely identify an Identity
   */
  // TODO: Replace with IdentityID.constructFromURI
  public static String getIDFromURI (FreenetURI uri) {
    /* WARNING: This is a copy of the code of plugins.WoT.Identity. Freetalk is not allowed to have its own custom IDs, you cannot change
     * this code here. */
    return Base64.encode(uri.getRoutingKey());
  }

  public FreenetURI getRequestURI() {
    checkedActivate(1);
    checkedActivate(mRequestURI, 2);
    return mRequestURI;
  }

  public String getNickname() {
    checkedActivate(1); // String is a db4o primitive type so 1 is enough
    return mNickname;
  }

  protected String getNickname(int maxLength) {
    checkedActivate(1); // String is a db4o primitive type so 1 is enough
    if(mNickname.length() > maxLength) {
      return mNickname.substring(0, maxLength) + "...";
    }
    return mNickname;
  }

  public String getShortestUniqueName() {
    return mFreetalk.getIdentityManager().getShortestUniqueName(this);
  }

  public String getFreetalkAddress() {
    checkedActivate(1); // String is a db4o primitive type so 1 is enough
    return mNickname + "@" + mID + "." + Freetalk.WOT_CONTEXT.toLowerCase()
  }
 
  /**
   * Returns a Freetalk-address with a maximal content length.
   * The format will be "nickname@abbreviated_routing_key...", i.e. 3 dots will be appended if the length exceeds the maximal length.
   * The "@" and "..." are not included in the length computation - therefore its called maximal <b>content</b> length, not maximal length.
   * If the nickname does not fit in the maximal length it is NOT abbreviated, the full nickname is returned then.
   *
   * The reason for this weird definition is to allow easy computation of nicknames which have a shortest unique length...
   * See {@link WoTIdentityManager.updateShortestUniqueNicknameCache} for how this is used.
   */
  protected String getFreetalkAddress(int maxContentLength) {
    final String address = getFreetalkAddress();
   
    if(getNickname().length() > maxContentLength)
      return getNickname();
   
    if(address.length() > maxContentLength) {
      return address.substring(0, maxContentLength+1) + "..."; // "+1" because the "@" does not count as length.
    }
    return address;
  }

  public synchronized long getLastReceivedFromWoT() {
    checkedActivate(1); // long is a db4o primitive type so 1 is enough
    return mLastReceivedFromWoT;
  }
 
  /**
   * Set the ID of the identity fetch in which this identity was last received from the WoT plugin to the given unique ID.
   */
  public synchronized void setLastReceivedFromWoT(long fetchID) {
    checkedActivate(1);
    mLastReceivedFromWoT = fetchID;
    storeWithoutCommit(); // TODO: Move store() calls outside of class identity
  }

  /**
   * Validates the nickname. If it is valid, nothing happens. If it is invalid, an exception is thrown which exactly describes what is
   * wrong about the nickname.
   *
   * @throws InvalidParameterException If the nickname is invalid, the exception contains a description of the problem as message.
   */
  /* IMPORTANT: This code is duplicated in plugins.WoT.Identity.isNicknameValid().
   * Please also modify it there if you modify it here */
  public static void validateNickname(String newNickname) throws InvalidParameterException {
    if(!StringValidityChecker.containsNoIDNBlacklistCharacters(newNickname)
    || !StringValidityChecker.containsNoInvalidCharacters(newNickname)
    || !StringValidityChecker.containsNoLinebreaks(newNickname)
    || !StringValidityChecker.containsNoControlCharacters(newNickname)
    || !StringValidityChecker.containsNoInvalidFormatting(newNickname)
    || newNickname.contains("@")) // Must not be allowed since we use it to generate "identity@public-key-hash" unique nicknames
      throw new InvalidParameterException("Nickname contains invalid characters"); /* TODO: Tell the user which ones are invalid!!! */
   
    if(newNickname.length() == 0) throw new InvalidParameterException("Blank nickname.");
    if(newNickname.length() > 30) throw new InvalidParameterException("Nickname is too long, the limit is 30 characters.");
  }

  protected void checkedCommit(Object loggingObject) {
    super.checkedCommit(loggingObject);
  }
 
  /**
   * You have to synchronize on this object before modifying the identity and calling storeAndCommit.
   */
  public void storeAndCommit() {
    synchronized(Persistent.transactionLock(mDB)) {
      storeWithoutCommit();
      checkedCommit(this);
    }
  }

  protected void storeWithoutCommit() {
    try {   
      // 1 is the maximal depth of all getter functions. You have to adjust this when introducing new member variables.
      checkedActivate(1);

      // You have to take care to keep the list of stored objects synchronized with those being deleted in deleteWithoutCommit() !
     
      checkedActivate(mRequestURI, 2);
      checkedStore(mRequestURI);
      checkedStore();
    }
    catch(RuntimeException e) {
      checkedRollbackAndThrow(e);
    }
  }
 
  protected void deleteWithoutCommit() {
    try {
      // 1 is the maximal depth of all getter functions. You have to adjust this when introducing new member variables.
      checkedActivate(this, 1);
     
      checkedDelete();
     
      checkedActivate(mRequestURI, 2);
      mRequestURI.removeFrom(mDB);
    }
    catch(RuntimeException e) {
      checkedRollbackAndThrow(e);
    }
  }

  public String toString() {
    if(mDB != null)
      return getFreetalkAddress();
   
    // We do not throw a NPE because toString() is usually used in logging, we want the logging to be robust
   
    Logger.error(this, "toString() called before initializeTransient()!");
   
    return super.toString() + " (intializeTransient() not called!, identity ID may be null, here it is: " + mID + ")";
  }
 
}
TOP

Related Classes of plugins.Freetalk.WoT.WoTIdentity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.