예제 #1
0
/**
 * RTF text extractor
 *
 * @author Wouter Heijke
 * @version $Id$
 */
public class SwingRTFExtractor implements Extractor {
  private static final Logger log = Logging.getLoggerInstance(SwingRTFExtractor.class);

  private String mimetype = "application/rtf";

  @Override
  public void setMimeType(String mimetype) {
    this.mimetype = mimetype;
  }

  @Override
  public String getMimeType() {
    return this.mimetype;
  }

  @Override
  public String extract(InputStream input) throws Exception {
    log.debug("extract stream");
    String result = null;
    DefaultStyledDocument styledDoc = new DefaultStyledDocument();
    try {
      new RTFEditorKit().read(input, styledDoc, 0);
      result = styledDoc.getText(0, styledDoc.getLength());
    } catch (IOException e) {
      throw new Exception("Cannot extract text from a RTF document", e);
    } catch (BadLocationException e) {
      throw new Exception("Cannot extract text from a RTF document", e);
    }
    return result;
  }
}
예제 #2
0
 /**
  * Performs general periodic maintenance. This routine handles alle open pages/main and
  * pages/mirror file service requests. These requests are obtained from the netfiles builder. For
  * each file that should be serviced, the filechange method is called. This routine handles a
  * maximum of 10 page/main, and 50 page/mirror service calls each time it is called. The first
  * time this method is call, nothing happens (?)
  *
  * @return <code>true</code> if maintenance was performed, <code>false</code> otherwise
  */
 public boolean probeCall() {
   if (first) {
     // skip first time this method is called
     first = false;
   } else {
     // handle up to 10 pages/main fileservice requests
     try {
       Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
       // Enumeration e=bul.search("WHERE service='pages' AND subservice='main' AND
       // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC");
       Enumeration e =
           bul.search("service=='pages'+subservice=='main'+status=" + Netfiles.STATUS_REQUEST);
       int i = 0;
       while (e.hasMoreElements() && i < 10) {
         MMObjectNode node = (MMObjectNode) e.nextElement();
         fileChange("" + node.getIntValue("number"), "c");
         i++;
       }
     } catch (Exception e) {
       log.error(Logging.stackTrace(e));
     }
     // handle up to 50 pages/mirror fileservice requests
     try {
       Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
       Enumeration e =
           bul.search("service=='pages'+subservice=='mirror'+status=" + Netfiles.STATUS_REQUEST);
       // Enumeration e=bul.search("WHERE service='pages' AND subservice='mirror' AND
       // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC");
       int i = 0;
       while (e.hasMoreElements() && i < 50) {
         MMObjectNode node = (MMObjectNode) e.nextElement();
         fileChange("" + node.getIntValue("number"), "c");
         i++;
       }
     } catch (Exception e) {
       log.error(Logging.stackTrace(e));
     }
   }
   return true;
 }
예제 #3
0
/**
 * @author Michiel Meeuwissen
 * @since MMBase-1.9.2
 */
public class BitrateLabeler extends Labeler {
  private static final Logger log = Logging.getLoggerInstance(BitrateLabeler.class);
  private static final String CONFIG_TAG = MainFilter.FILTERCONFIG_TAG + ".bitrates";

  private final Map<String, BitrateInfo> bitrates = new LinkedHashMap<String, BitrateInfo>();

  private String key = "bitrate";

  private boolean overwrite = true;

  public void setKey(String k) {
    key = k;
  }

  public void setOverwrite(boolean o) {
    overwrite = o;
  }

  @Override
  public void configure(DocumentReader reader, Element element) {
    bitrates.clear();
    try {
      for (Element bitrate :
          DocumentReader.getChildElements(reader.getElementByPath(element, CONFIG_TAG))) {
        BitrateInfo bri = new BitrateInfo(bitrate);
        log.debug("Adding BitrateInfo " + bri);
        bitrates.put(bri.getName(), bri);
      }
    } catch (Exception ex) {
      log.error("Error in filter.xml:" + ex, ex);
    }
    log.info("Configured bit rate labeler " + bitrates);
    FilterUtils.propertiesConfigure(this, reader, element);
  }

  @Override
  protected void label(URLComposer uc) {
    for (Map.Entry<String, BitrateInfo> entry : bitrates.entrySet()) {
      int bitrate = uc.getSource().getIntValue("bitrate");
      if (entry.getValue().matches(bitrate)) {
        log.debug("" + bitrate + " matched " + entry);
        if (overwrite || !uc.getInfo().containsKey(key)) {
          uc.getInfo().put(key, entry.getKey());
        }
      }
    }
  }
}
예제 #4
0
/**
 * The resources builder can be used by {@link org.mmbase.util.ResourceLoader} to load resources
 * from (configuration files, classes, resourcebundles).
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.8
 */
public class Resources extends Attachments {
  private static final Logger log = Logging.getLoggerInstance(Resources.class);

  /** Implements virtual filename field. {@inheritDoc} */
  @Override
  public Object getValue(MMObjectNode node, String field) {
    if (field.equals(NodeURLStreamHandlerFactory.FILENAME_FIELD)) {
      String s = node.getStringValue(NodeURLStreamHandlerFactory.RESOURCENAME_FIELD);
      int i = s.lastIndexOf("/");
      if (i > 0) {
        return s.substring(i + 1);
      } else {
        return s;
      }
    } else {
      return super.getValue(node, field);
    }
  }
}
예제 #5
0
/**
 * A VWM that manages the files by scheduling them to be send to one or more mirror sites. Requests
 * for scheduling is done in the netfile builder. This VWM handles those netfile requests whose
 * service is 'pages'. Available subservices are 'main' and 'mirror'. Requests for file copy are
 * checked periodically. This results in one or more requests for a 'mirror' service, which then
 * result in a file copy request, which is handled in a separate thread. This VWM also has methods
 * for recalculating pages and handling page changes (which in turn result in a request for file
 * copy.) Entry point for these requests are the FileChange methods from the {@link
 * VwmServiceInterface}.
 *
 * @author Daniel Ockeloen
 * @author Pierre van Rooden (javadocs)
 * @version $Id$
 */
public class PageMaster extends Vwm implements MMBaseObserver, VwmServiceInterface {

  private static final Logger log = Logging.getLoggerInstance(PageMaster.class);

  // field used to skip first probeCall (why???)
  boolean first = true;

  Object syncobj = new Object(); // used in commented code

  /** Queue containing the file-copy tasks that need to be performed by {@link #filecopier} */
  Queue files2copy = new Queue(128);
  /** Thread that handles the actual file transfers. */
  FileCopier filecopier = new FileCopier(files2copy);
  /** Cache for mirror servers */
  Vector mirrornodes;

  // Hashtable properties; (unused)

  /** Constructor for the PageMaster VWM. */
  public PageMaster() {
    log.debug("ready for action");
  }

  /**
   * Performs general periodic maintenance. This routine handles alle open pages/main and
   * pages/mirror file service requests. These requests are obtained from the netfiles builder. For
   * each file that should be serviced, the filechange method is called. This routine handles a
   * maximum of 10 page/main, and 50 page/mirror service calls each time it is called. The first
   * time this method is call, nothing happens (?)
   *
   * @return <code>true</code> if maintenance was performed, <code>false</code> otherwise
   */
  public boolean probeCall() {
    if (first) {
      // skip first time this method is called
      first = false;
    } else {
      // handle up to 10 pages/main fileservice requests
      try {
        Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
        // Enumeration e=bul.search("WHERE service='pages' AND subservice='main' AND
        // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC");
        Enumeration e =
            bul.search("service=='pages'+subservice=='main'+status=" + Netfiles.STATUS_REQUEST);
        int i = 0;
        while (e.hasMoreElements() && i < 10) {
          MMObjectNode node = (MMObjectNode) e.nextElement();
          fileChange("" + node.getIntValue("number"), "c");
          i++;
        }
      } catch (Exception e) {
        log.error(Logging.stackTrace(e));
      }
      // handle up to 50 pages/mirror fileservice requests
      try {
        Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
        Enumeration e =
            bul.search("service=='pages'+subservice=='mirror'+status=" + Netfiles.STATUS_REQUEST);
        // Enumeration e=bul.search("WHERE service='pages' AND subservice='mirror' AND
        // status="+Netfiles.STATUS_REQUEST+" ORDER BY number DESC");
        int i = 0;
        while (e.hasMoreElements() && i < 50) {
          MMObjectNode node = (MMObjectNode) e.nextElement();
          fileChange("" + node.getIntValue("number"), "c");
          i++;
        }
      } catch (Exception e) {
        log.error(Logging.stackTrace(e));
      }
    }
    return true;
  }

  /**
   * Called when a remote node is changed.
   *
   * @param machine Name of the machine that changed the node.
   * @param number Number of the changed node as a <code>String</code>
   * @param builder type of the changed node
   * @param ctype command type, 'c'=changed, 'd'=deleted', 'r'=relations changed, 'n'=new
   * @return <code>true</code>
   */
  public boolean nodeRemoteChanged(String machine, String number, String builder, String ctype) {
    return nodeChanged(machine, number, builder, ctype);
  }

  /**
   * Called when a local node is changed.
   *
   * @param machine Name of the machine that changed the node.
   * @param number Number of the changed node as a <code>String</code>
   * @param builder type of the changed node
   * @param ctype command type, 'c'=changed, 'd'=deleted', 'r'=relations changed, 'n'=new
   * @return <code>true</code>
   */
  public boolean nodeLocalChanged(String machine, String number, String builder, String ctype) {
    return nodeChanged(machine, number, builder, ctype);
  }

  /**
   * Called when a local or remote node is changed. Does not take any action.
   *
   * @param machine Name of the machine that changed the node.
   * @param number Number of the changed node as a <code>String</code>
   * @param builder type of the changed node
   * @param ctype command type, 'c'=changed, 'd'=deleted', 'r'=relations changed, 'n'=new
   * @return <code>true</code>
   */
  public boolean nodeChanged(String machine, String number, String builder, String ctype) {
    // log.debug("sees that : "+number+" has changed type="+ctype);
    return true;
  }

  /**
   * Schedules a service-request on a file. Only "pages/main" services are handled. The
   * service-request is later handled through the {@link #probeCall} method.
   *
   * @param service the service to be performed
   * @param subservice the subservice to be performed
   * @param filename the filename to service
   * @return <code>true</code> if maintenance was performed, <code>false</code> otherwise
   */
  public boolean fileChange(String service, String subservice, String filename) {
    log.debug("frontend change -> " + filename);
    log.service("s=" + service + " sub=" + subservice + "file=" + filename);
    // jump to correct subhandles based on the subservice
    if (subservice.equals("main")) {
      handleMainCheck(service, subservice, filename);
    }
    return true;
  }

  /**
   * Handles a service-request on a file, registered in the netfiles builder. Depending on the
   * subservice requested, this routine calls {@link #handleMirror} or {@link #handleMain}.
   *
   * @param number Number of the node in the netfiles buidler than contain service request
   *     information.
   * @param ctype the type of change on that node ("c" : node was changed)
   * @return <code>true</code>
   */
  public boolean fileChange(String number, String ctype) {
    // log.debug("fileChange="+number+" "+ctype);
    // first get the change node so we can see what is the matter with it.
    Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
    MMObjectNode filenode = bul.getNode(number);
    if (filenode != null) {
      // obtain all the basic info on the file.
      String service = filenode.getStringValue("service");
      String subservice = filenode.getStringValue("subservice");
      int status = filenode.getIntValue("status");

      // jump to correct subhandles based on the subservice
      if (subservice.equals("main")) {
        return handleMain(filenode, status, ctype);
      } else if (subservice.equals("mirror")) {
        return handleMirror(filenode, status, ctype);
      }
    }
    return true;
  }

  /**
   * Handles a pages/mirror service request. Places a page in the file2copy queue, so it will be
   * sent to a mirror site by the FileCopier.
   *
   * @param filenode the filenet node that contains the service request
   * @param status the current status of the node
   * @param ctype the type of change on that node ("c" : node was changed)
   * @return <code>true</code>
   */
  public boolean handleMirror(MMObjectNode filenode, int status, String ctype) {
    switch (status) {
      case Netfiles.STATUS_REQUEST: // Request
        // register the node as being On Its Way
        filenode.setValue("status", Netfiles.STATUS_ON_ITS_WAY);
        filenode.commit();
        String filename = filenode.getStringValue("filename");
        String dstserver = filenode.getStringValue("mmserver");
        // recover the correct source/dest properties for this mirror
        //
        // why does it say "demoserver" ??
        //
        String sshpath = getProperty("demoserver", "sshpath");
        log.debug("sshpath=" + sshpath);
        String srcpath = getProperty("demoserver", "path");
        log.debug("srcpath=" + srcpath);
        String dstuser = getProperty(dstserver, "user");
        log.debug("dstuser="******"host");
        log.debug("dsthost=" + dsthost);
        String dstpath = getProperty(dstserver, "path");
        log.debug("dstpath=" + dstpath);

        /* this code can be dropped as it is handled in FileCopier

                SCPcopy scpcopy=new SCPcopy(sshpath,dstuser,dsthost,dstpath);

                synchronized(syncobj) {
                    scpcopy.copy(srcpath,filename);
                }
        */
        // create a new file2copy object and add it to the queue,
        // so the FileCopier thread will handle it.
        files2copy.append(new aFile2Copy(dstuser, dsthost, dstpath, srcpath, filename, sshpath));

        // register the node as being Done
        filenode.setValue("status", Netfiles.STATUS_DONE);
        filenode.commit();
        break;
      case Netfiles.STATUS_ON_ITS_WAY: // On its way
        break;
      case Netfiles.STATUS_DONE: // Done
        break;
    }
    return true;
  }

  /**
   * Handles a pages/main service request. The events handled are:<br>
   * - requests for handling: schedules requests to mirror this page using {@link #doMainRequest}
   * <br>
   * - changed: page is scheduled to be recalculated<br>
   * - recaculate" page is recaclcutated and scheduled to be handled<br>
   *
   * @param filenode the netfiles node that contains the service request
   * @param status the current status of the node
   * @param ctype the type of change on that node ("c" : node was changed)
   * @return <code>true</code>
   */
  public boolean handleMain(MMObjectNode filenode, int status, String ctype) {
    switch (status) {
      case Netfiles.STATUS_REQUEST: // Request
        // register the node as being On Its Way
        filenode.setValue("status", Netfiles.STATUS_ON_ITS_WAY);
        filenode.commit();
        // do stuff
        doMainRequest(filenode);
        // register the node as being Done
        filenode.setValue("status", Netfiles.STATUS_DONE);
        filenode.commit();
        break;
      case Netfiles.STATUS_ON_ITS_WAY: // On Its Way
        break;
      case Netfiles.STATUS_DONE: // Done
        break;
      case Netfiles.STATUS_CHANGED: // Dirty (?)
        filenode.setValue("status", Netfiles.STATUS_CALC_PAGE);
        filenode.commit();
        break;
      case Netfiles.STATUS_CALC_PAGE: // Recalculate Page
        String filename = filenode.getStringValue("filename");
        calcPage(filename);
        filenode.setValue("status", Netfiles.STATUS_REQUEST);
        filenode.commit();
        break;
    }
    return true;
  }

  /**
   * Handles a main subservice on a page. The page is scheduled to be sent to all appropriate
   * mirrorsites for this service, by setting the request status in the associated mirror nodes. If
   * no mirror nodes are associated with this page, nothing happens.
   *
   * @param filenode the netfiles node with the original (main) request
   */
  public boolean doMainRequest(MMObjectNode filenode) {
    // so this file has changed probably, check if the file is ready on
    // disk and set the mirrors to request.
    String filename = filenode.getStringValue("filename");

    // find and change all the mirror nodes so they get resend
    Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
    Enumeration e =
        bul.search("WHERE filename='" + filename + "' AND service='pages' AND subservice='mirror'");
    while (e.hasMoreElements()) {
      MMObjectNode mirrornode = (MMObjectNode) e.nextElement();
      mirrornode.setValue("status", Netfiles.STATUS_REQUEST);
      mirrornode.commit();
    }
    return true;
  }

  /**
   * Schedules a netfile object to be send to its mirror sites. The routine searches the appropriate
   * netfile node, and sets its status to 'request'. If a node does not exits, a new node is
   * created. In the latter case, the system also creates mirrornodes for each mirrorsite associated
   * with this service.
   *
   * @param service the service to be performed
   * @param subservice the subservice to be performed
   * @param filename the filename to service
   */
  public void handleMainCheck(String service, String subservice, String filename) {
    log.debug("Reached handleMainCheck");
    Netfiles bul = (Netfiles) Vwms.getMMBase().getMMObject("netfiles");
    Enumeration e =
        bul.search(
            "WHERE filename='"
                + filename
                + "' AND service='"
                + service
                + "' AND subservice='"
                + subservice
                + "'");
    if (e.hasMoreElements()) {
      MMObjectNode mainnode = (MMObjectNode) e.nextElement();
      mainnode.setValue("status", Netfiles.STATUS_REQUEST);
      mainnode.commit();
    } else {
      MMObjectNode mainnode = bul.getNewNode("system");
      mainnode.setValue("filename", filename);
      mainnode.setValue("mmserver", Vwms.getMMBase().getMachineName());
      mainnode.setValue("service", service);
      mainnode.setValue("subservice", subservice);
      mainnode.setValue("status", Netfiles.STATUS_REQUEST);
      mainnode.setValue("filesize", -1);
      bul.insert("system", mainnode);

      Enumeration f = getMirrorNodes(service).elements();
      while (f.hasMoreElements()) {
        MMObjectNode n2 = (MMObjectNode) f.nextElement();
        // hack hack also have to create mirror nodes !
        mainnode = bul.getNewNode("system");
        mainnode.setValue("filename", filename);
        mainnode.setValue("mmserver", n2.getStringValue("name"));
        mainnode.setValue("service", service);
        mainnode.setValue("subservice", "mirror");
        mainnode.setValue("status", Netfiles.STATUS_DONE);
        mainnode.setValue("filesize", -1);
        bul.insert("system", mainnode);
      }
    }
  }

  /**
   * Retrieves a named property of a server.
   *
   * @param machine name of the server
   * @param key name of the property to retrieve
   * @return the property value
   */
  public String getProperty(String machine, String key) {
    MMServers mmservers = (MMServers) Vwms.getMMBase().getMMObject("mmservers");
    return mmservers.getMMServerProperty(machine, key);
  }

  /**
   * Recalculate a page. Invokes the SCAN parser (which will re-cache the page through the scancache
   * module) Only works for SCAN.
   *
   * @param url of the page to cache
   */
  public void calcPage(String url) {
    scanparser m = (scanparser) Vwms.getMMBase().getModule("SCANPARSER");
    url = url.substring(0, url.length() - 5);
    url = url.replace(':', '?');
    log.debug("getPage=" + url);
    if (m != null) {
      scanpage sp = new scanpage();
      m.calcPage(url, sp, 0);
    }
  }

  /**
   * Retrieves a list of Mirror Servers. This is done by obtaining a fileserver node and retrieving
   * associated mmserver nodes. This method should be renamed and moved to the netfilesrv builder.
   *
   * @param service preseumably the service to query for. Unused.
   * @return a <code>Vector</code> containing mmserver nodes that act as mirror server for this
   *     service
   */
  public Vector getMirrorNodes(String service) {
    if (mirrornodes != null) return mirrornodes;
    NetFileSrv bul = (NetFileSrv) Vwms.getMMBase().getMMObject("netfilesrv");
    if (bul != null) {
      Enumeration e = bul.search("service=='pages'+subservice=='mirror'");
      if (e.hasMoreElements()) {
        MMObjectNode n1 = (MMObjectNode) e.nextElement();
        mirrornodes = n1.getRelatedNodes("mmservers");
        if (mirrornodes != null) return mirrornodes;
      }
    }
    mirrornodes = new Vector();
    return mirrornodes;
  }
}
예제 #6
0
파일: LRUCache.java 프로젝트: mihxil/mmbase
/**
 * A cache implementation backed by a {@link java.util.LinkedHashMap}, in access-order mode, and
 * restricted maximal size ('Least Recently Used' cache algorithm).
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @see org.mmbase.cache.Cache
 * @since MMBase-1.8.6
 */
public class LRUCache<K, V> implements CacheImplementationInterface<K, V> {

  private static final Logger log = Logging.getLoggerInstance(LRUCache.class);

  private int maxSize;
  private final Map<K, V> backing;

  public LRUCache() {
    this(100);
  }

  public LRUCache(int size) {
    maxSize = size;
    // caches can typically be accessed/modified by multiple threads, so we need to synchronize
    backing =
        Collections.synchronizedMap(
            new LinkedHashMap<K, V>(size, 0.75f, true) {
              private static final long serialVersionUID = 0L;

              @Override
              protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                int overSized = size() - LRUCache.this.maxSize;
                if (overSized <= 0) {
                  return false;
                } else if (overSized == 1) {
                  // Using iterator to manualy remove the eldest rather then return true to make
                  // absolutely sure that one
                  // disappears, because that seems to fail sometimes for QueryResultCache.

                  final Iterator<K> i = keySet().iterator();
                  K actualEldest = i.next();
                  i.remove();
                  overSized = size() - LRUCache.this.maxSize;
                  while (overSized > 0) {
                    // if for some reason a key changed in the cache, even 1 i.remove may not
                    // shrink the cache.
                    log.warn(
                        "cache didn't shrink (a)"
                            + eldest.getKey()
                            + " ["
                            + eldest.getKey().getClass()
                            + "] ["
                            + eldest.getKey().hashCode()
                            + "]");
                    log.warn(
                        "cache didn't shrink (b)"
                            + actualEldest
                            + " ["
                            + actualEldest.getClass()
                            + "] ["
                            + actualEldest.hashCode()
                            + "]");
                    actualEldest = i.next();
                    i.remove();
                    overSized = size() - LRUCache.this.maxSize;
                  }
                  assert overSized <= 0;
                  return false;
                } else {
                  log.warn("How is this possible? Oversized: " + overSized);
                  log.debug("because", new Exception());
                  if (overSized > 10) {
                    log.error(
                        "For some reason this cache grew much too big ("
                            + size()
                            + " >> "
                            + LRUCache.this.maxSize
                            + "). This must be some kind of bug. Resizing now.");
                    clear();
                  }
                  return false;
                }
              }
            });
  }

  @Override
  public int getCount(K key) {
    return -1;
  }

  /**
   * Change the maximum size of the table. This may result in removal of entries in the table.
   *
   * @param size the new desired size
   */
  @Override
  public void setMaxSize(int size) {
    if (size < 0) {
      throw new IllegalArgumentException("Cannot set size to negative value " + size);
    }
    maxSize = size;
    synchronized (backing) {
      while (size() > maxSize) {
        try {
          Iterator<K> i = keySet().iterator();
          i.next();
          i.remove();
        } catch (Exception e) {
          log.warn(e);
          // ConcurentModification?
        }
      }
    }
  }

  @Override
  public final int maxSize() {
    return maxSize;
  }

  /** Returns size, maxSize. */
  @Override
  public String toString() {
    return "Size=" + size() + ", Max=" + maxSize;
  }

  @Override
  public void config(Map<String, String> map) {
    // needs no configuration.
  }

  @Override
  public Object getLock() {
    return backing;
  }

  // wrapping for synchronization
  @Override
  public int size() {
    return backing.size();
  }

  @Override
  public boolean isEmpty() {
    return backing.isEmpty();
  }

  @Override
  @SuppressWarnings("element-type-mismatch")
  public boolean containsKey(Object key) {
    return backing.containsKey(key);
  }

  @Override
  @SuppressWarnings("element-type-mismatch")
  public boolean containsValue(Object value) {
    return backing.containsValue(value);
  }

  @Override
  @SuppressWarnings("element-type-mismatch")
  public V get(Object key) {
    return backing.get(key);
  }

  @Override
  public V put(K key, V value) {
    return backing.put(key, value);
  }

  @Override
  @SuppressWarnings("element-type-mismatch")
  public V remove(Object key) {
    return backing.remove(key);
  }

  @Override
  public void putAll(Map<? extends K, ? extends V> map) {
    backing.putAll(map);
  }

  @Override
  public void clear() {
    backing.clear();
  }

  @Override
  public Set<K> keySet() {
    return backing.keySet();
  }

  @Override
  public Set<Map.Entry<K, V>> entrySet() {
    return backing.entrySet();
  }

  @Override
  public Collection<V> values() {
    return backing.values();
  }
}
예제 #7
0
/**
 * If for some reason you also need to do Queries next to MMBase.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 */
public class JdbcIndexDefinition implements IndexDefinition {

  private static final Logger log = Logging.getLoggerInstance(JdbcIndexDefinition.class);

  private static int directConnections = 0;

  private static final int CACHE_SIZE = 10 * 1024;
  protected static Cache<String, LazyMap> nodeCache =
      new Cache<String, LazyMap>(CACHE_SIZE) {
        {
          putCache();
        }

        @Override
        public final String getName() {
          return "LuceneJdbcNodes";
        }

        @Override
        public final String getDescription() {
          return "Node identifier -> Map";
        }
      };

  private final DataSource dataSource;
  private final String key;
  private final String identifier;
  private final String indexSql;
  private final String findSql;
  private final Analyzer analyzer;

  private final Set<String> keyWords = new HashSet<String>();
  private final Map<String, Indexer.Multiple> nonDefaultMultiples =
      new HashMap<String, Indexer.Multiple>();
  private final Map<String, Float> boosts = new HashMap<String, Float>();

  private final Collection<IndexDefinition> subQueries = new ArrayList<IndexDefinition>();

  private final boolean isSub;

  private String id;

  JdbcIndexDefinition(
      DataSource ds,
      Element element,
      Set allIndexedFields,
      boolean storeText,
      boolean mergeText,
      Analyzer a,
      boolean isSub) {
    this.dataSource = ds;
    indexSql = element.getAttribute("sql");
    key = element.getAttribute("key");
    String elementId = element.getAttribute("identifier");
    identifier = "".equals(elementId) ? key : elementId;
    findSql = element.getAttribute("find");
    NodeList childNodes = element.getChildNodes();
    for (int k = 0; k < childNodes.getLength(); k++) {
      if (childNodes.item(k) instanceof Element) {
        Element childElement = (Element) childNodes.item(k);
        if ("field".equals(childElement.getLocalName())) {
          if (childElement.getAttribute("keyword").equals("true")) {
            keyWords.add(childElement.getAttribute("name"));
          }
          String m = childElement.getAttribute("multiple");
          if ("".equals(m)) m = "add";
          if (!m.equals("add")) {
            nonDefaultMultiples.put(
                childElement.getAttribute("name"), Indexer.Multiple.valueOf(m.toUpperCase()));
          }
          String b = childElement.getAttribute("boost");
          if (!b.equals("")) {
            boosts.put(childElement.getAttribute("name"), Float.valueOf(b));
          }
        } else if ("related".equals(childElement.getLocalName())) {
          subQueries.add(
              new JdbcIndexDefinition(
                  ds, childElement, allIndexedFields, storeText, mergeText, a, true));
        }
      }
    }
    this.analyzer = a;
    this.isSub = isSub;
    assert !isSub || "".equals(findSql);
  }

  @Override
  public void setId(String i) {
    id = i;
  }

  @Override
  public String getId() {
    return id;
  }

  /**
   * Jdbc connection pooling of MMBase would kill the statement if too duratious. This produces a
   * 'direct connection' in that case, to circumvent that problem (Indexing queries _may_ take a
   * while).
   */
  protected Connection getDirectConnection() throws SQLException {
    directConnections++;
    try {
      if (dataSource instanceof GenericDataSource) {
        return ((GenericDataSource) dataSource).getDirectConnection();
      } else {
        return dataSource.getConnection();
      }
    } catch (SQLException sqe) {
      log.error("With direct connection #" + directConnections + ": " + sqe.getMessage());
      throw sqe;
    } catch (Throwable t) {
      throw new RuntimeException("direct connection #" + directConnections, t);
    }
  }

  @Override
  public Analyzer getAnalyzer() {
    return analyzer;
  }

  protected String getFindSql(String identifier) {
    assert !isSub;
    if (findSql == null || "".equals(findSql)) throw new RuntimeException("No find query defined");
    if (identifier == null) throw new RuntimeException("No find query defined");
    String s = findSql.replaceAll("\\[IDENTIFIER\\]", identifier);
    s = s.replaceAll("\\[KEY\\]", identifier); // deprecated
    return s;
  }

  @Override
  public boolean inIndex(String identifier) {
    CloseableIterator<JdbcEntry> i = getSqlCursor(getFindSql(identifier));
    boolean result = i.hasNext();
    try {
      i.close();
    } catch (IOException ex) {
      log.warn(ex);
    }
    return result;
  }

  protected String getSql(String identifier) {
    if (indexSql == null || "".equals(indexSql)) throw new RuntimeException("No sql defined");
    if (identifier == null) throw new RuntimeException("No query defined");
    String s = indexSql.replaceAll("\\[PARENTKEY\\]", identifier);
    s = s.replaceAll("\\[KEY\\]", identifier); // deprecated
    return s;
  }

  CloseableIterator<JdbcEntry> getSqlCursor(final String sql) {
    try {
      long start = System.currentTimeMillis();
      final Connection con = getDirectConnection();
      log.debug("About to execute " + sql + " (" + directConnections + ")");
      final Statement statement = con.createStatement();
      final ResultSet results = statement.executeQuery(sql);
      if (log.isDebugEnabled()) {
        log.debug("Executed " + sql + " in " + (System.currentTimeMillis() - start) + " ms");
      }
      final ResultSetMetaData meta = results.getMetaData();

      return new CloseableIterator<JdbcEntry>() {
        boolean hasNext = results.isBeforeFirst();
        int i = 0;

        @Override
        public boolean hasNext() {
          return hasNext;
        }

        @Override
        public JdbcEntry next() {
          if (!hasNext) {
            throw new NoSuchElementException();
          }
          try {
            results.next();
            hasNext = !results.isLast();
          } catch (java.sql.SQLException sqe) {
            log.error(sqe);
            hasNext = false;
          }
          JdbcEntry entry = new JdbcEntry(meta, results, sql);
          i++;
          if (log.isServiceEnabled()) {
            if (i % 100 == 0) {
              log.service("jdbc cursor " + i + " (now at id=" + entry.getIdentifier() + ")");
            } else if (log.isDebugEnabled()) {
              log.trace("jdbc cursor " + i + " (now at id=" + entry.getIdentifier() + ")");
            }
          }
          return entry;
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException();
        }

        @Override
        public void close() {
          log.debug("Closing " + con);
          try {
            if (results != null) results.close();
            if (statement != null) statement.close();
            if (con != null) con.close();
          } catch (Exception e) {
            log.error(e);
          }
        }
      };
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }

  /**
   * A map representing a row in a database. But only filled when actually used. So, only on first
   * use, a query is done. And not before that.
   *
   * @since MMBase-1.9
   */
  protected class LazyMap extends AbstractMap<String, String> {
    private Map<String, String> map = null;
    private final Map<String, String> keys;
    private final String identifier;

    LazyMap(String identifier, Map<String, String> keys) {
      this.identifier = identifier;
      this.keys = keys;
    }

    protected void check() {
      if (map == null) {
        Connection connection = null;
        Statement statement = null;
        ResultSet results = null;
        try {
          connection = dataSource.getConnection();
          statement = connection.createStatement();
          long start = System.currentTimeMillis();
          String s = getFindSql(identifier);
          if (log.isTraceEnabled()) {
            log.trace("About to execute " + s + " because ", new Exception());
          }
          results = statement.executeQuery(s);
          ResultSetMetaData meta = results.getMetaData();
          map = new HashMap<String, String>();
          if (results.next()) {
            for (int i = 1; i <= meta.getColumnCount(); i++) {
              String value = org.mmbase.util.Casting.toString(results.getString(i));
              map.put(meta.getColumnName(i).toLowerCase(), value);
            }
          }
          long duration = (System.currentTimeMillis() - start);
          if (duration > 500) {
            log.warn("Executed " + s + " in " + duration + " ms");
          } else if (duration > 100) {
            log.debug("Executed " + s + " in " + duration + " ms");
          } else {
            log.trace("Executed " + s + " in " + duration + " ms");
          }
        } catch (Exception e) {
          throw new RuntimeException(e.getMessage(), e);
        } finally {
          if (results != null)
            try {
              results.close();
            } catch (Exception e) {
            }
          if (statement != null)
            try {
              statement.close();
            } catch (Exception e) {
            }
          if (connection != null)
            try {
              connection.close();
            } catch (Exception e) {
            }
        }
      }
    }

    @Override
    public Set<Map.Entry<String, String>> entrySet() {
      check();
      return map.entrySet();
    }

    @Override
    public int size() {
      check();
      return map.size();
    }

    @Override
    public String get(Object key) {
      if (JdbcIndexDefinition.this.identifier.equals(key)) return identifier;
      if (keys.containsKey(key)) return keys.get(key);
      check();
      return map.get(key);
    }

    @Override
    public boolean containsKey(Object key) {
      if (JdbcIndexDefinition.this.identifier.equals(key)) return true;
      if (keys.containsKey(key)) return true;
      check();
      return map.containsKey(key);
    }

    @Override
    public String toString() {
      if (map != null) {
        return map.toString();
      } else {
        return "[LAZY node " + identifier + "]";
      }
    }
  }

  @Override
  public org.mmbase.bridge.Node getNode(final Cloud userCloud, final Document doc) {
    String docId = doc.get("number");
    if (docId == null) {
      throw new IllegalArgumentException("No number found in " + doc);
    }
    LazyMap m = nodeCache.get(docId); //
    if (m == null) {
      Map<String, String> keys = new HashMap<String, String>();
      for (String keyWord : keyWords) {
        keys.put(keyWord, doc.get(keyWord));
      }
      m = new LazyMap(docId, keys);
      nodeCache.put(docId, m);
    }
    org.mmbase.bridge.Node node =
        new MapNode<String>(
            m,
            new MapNodeManager(userCloud, m) {
              @Override
              public boolean hasField(String name) {
                if (JdbcIndexDefinition.this.key.equals(name)) return true;
                return super.hasField(name);
              }

              @Override
              public org.mmbase.bridge.Field getField(String name) {
                if (map == null && JdbcIndexDefinition.this.key.equals(name)) {
                  org.mmbase.core.CoreField fd =
                      org.mmbase.core.util.Fields.createField(
                          name,
                          org.mmbase.core.util.Fields.classToType(Object.class),
                          org.mmbase.bridge.Field.TYPE_UNKNOWN,
                          org.mmbase.bridge.Field.STATE_VIRTUAL,
                          null);
                  return new org.mmbase.bridge.implementation.BasicField(fd, this);
                } else {
                  return super.getField(name);
                }
              }
            });
    if (log.isDebugEnabled()) {
      log.debug("Returning node for " + node);
    }
    return node;
  }

  @Override
  public CloseableIterator<JdbcEntry> getCursor() {
    assert !isSub;
    return getSqlCursor(indexSql);
  }

  @Override
  public CloseableIterator<JdbcEntry> getSubCursor(String identifier) {
    if (isSub) {
      log.debug("Using getSubCursor for " + identifier);
      return getSqlCursor(getSql(identifier));
    } else {
      return getSqlCursor(getFindSql(identifier));
    }
  }

  @Override
  public String toString() {
    return indexSql;
  }

  public class JdbcEntry implements IndexEntry {
    final ResultSetMetaData meta;
    final ResultSet results;
    final String sql;

    JdbcEntry(ResultSetMetaData m, ResultSet r, String s) {
      log.trace("new JDBC Entry");
      meta = m;
      results = r;
      sql = s;
    }

    @Override
    public void index(Document document) {
      if (log.isTraceEnabled()) {
        log.trace(
            "Indexing "
                + sql
                + " id="
                + JdbcIndexDefinition.this.identifier
                + ", key = "
                + JdbcIndexDefinition.this.key);
      }
      String id = getIdentifier();
      if (id != null) {
        document.add(
            new Field(
                "builder",
                "VIRTUAL BUILDER",
                Field.Store.YES,
                Field.Index.NOT_ANALYZED)); // keyword
        document.add(
            new Field(
                "number", getIdentifier(), Field.Store.YES, Field.Index.NOT_ANALYZED)); // keyword
      }
      try {
        for (int i = 1; i <= meta.getColumnCount(); i++) {
          String value = org.mmbase.util.Casting.toString(results.getString(i));
          if (log.isTraceEnabled()) {
            log.trace(
                "Indexing " + value + " for " + meta.getColumnName(i) + " on " + getIdentifier());
          }
          String fieldName = meta.getColumnName(i);
          if (keyWords.contains(fieldName)) {
            Indexer.addField(
                document,
                new Field(fieldName, value, Field.Store.YES, Field.Index.NOT_ANALYZED),
                nonDefaultMultiples.get(fieldName)); // keyword
          } else {
            Field field = new Field(fieldName, value, Field.Store.YES, Field.Index.ANALYZED);
            Float boost = boosts.get(fieldName);
            if (boost != null) {
              field.setBoost(boost);
            }
            Indexer.addField(document, field, nonDefaultMultiples.get(fieldName));
            Field fullText = new Field("fulltext", value, Field.Store.YES, Field.Index.ANALYZED);
            if (boost != null) {
              fullText.setBoost(boost);
            }
            document.add(fullText);
          }
        }
      } catch (SQLException sqe) {
        log.error(sqe.getMessage(), sqe);
      }
    }

    @Override
    public Collection<IndexDefinition> getSubDefinitions() {
      return JdbcIndexDefinition.this.subQueries;
    }

    @Override
    public String getIdentifier() {
      if (JdbcIndexDefinition.this.identifier != null
          && !JdbcIndexDefinition.this.identifier.equals("")) {
        try {
          return results.getString(JdbcIndexDefinition.this.identifier);
        } catch (SQLException sqe) {
          log.error(meta + " " + sqe.getMessage(), sqe);
          return "";
        }
      } else {
        return null;
      }
    }

    @Override
    public String getKey() {
      if (JdbcIndexDefinition.this.key != null && !JdbcIndexDefinition.this.key.equals("")) {
        try {
          return results.getString(JdbcIndexDefinition.this.key);
        } catch (SQLException sqe) {
          log.error(sqe.getMessage(), sqe);
          return "";
        }
      } else {
        return null;
      }
    }

    public Set<String> getIdentifiers() {
      Set<String> ids = new HashSet<String>();
      ids.add(getIdentifier());
      return ids;
    }
  }
}
예제 #8
0
/**
 * Generic tool to execute some SQL
 *
 * @since MMBase-1.9.5
 * @author Michiel Meeuwissen
 * @version $Id$
 */
public class SqlExecutor implements Runnable {

  private static final Logger LOG = Logging.getLoggerInstance(SqlExecutor.class);

  private String query;
  private String update;
  private String onlyIfQuery;
  private Pattern ignore = Pattern.compile("");

  protected DataSource dataSource;
  protected String prefix;

  public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
  }

  public void setPrefix(String pref) {
    this.prefix = pref;
  }

  public DataSource getDataSource() {
    return dataSource;
  }

  public String getPrefix() {
    if (prefix == null) {
      return "$PREFIX";
    } else {
      return prefix;
    }
  }

  public void setIgnoreException(String e) {
    ignore = Pattern.compile(e);
  }

  public void setQuery(String q) {
    if (update != null) throw new IllegalStateException();
    query = q;
  }

  public void setUpdate(String u) {
    if (query != null) throw new IllegalStateException();
    update = u;
  }

  /**
   * A query returning either true of false. E.g. <param name="onlyIf"><![CDATA[select 1 = (select
   * count(*) from mm_versions where m_type='application' and name='Limburg' and m_version <
   * 7);]]></param>
   */
  public void setOnlyIf(String q) {
    onlyIfQuery = q;
  }

  protected void executeQuery(Statement stmt, String q) throws SQLException {
    q = q.replace("$PREFIX", getPrefix());
    LOG.info(" Executing " + q);
    ResultSet rs = stmt.executeQuery(q);
    StringBuilder header = new StringBuilder();
    for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
      if (i > 1) {
        header.append("|");
      }
      header.append(rs.getMetaData().getColumnName(i));
    }
    LOG.info(header);
    int seq = 0;
    while (true) {
      boolean valid = rs.next();
      if (!valid) break;
      seq++;
      StringBuilder line = new StringBuilder();
      for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
        if (i > 1) {
          line.append("|");
        }
        line.append(rs.getString(i));
      }
      LOG.info(seq + ":" + line);
    }
  }

  protected void executeUpdate(Statement stmt, String u) throws SQLException {
    u = u.replace("$PREFIX", getPrefix());
    LOG.info(" Executing update " + u);
    int result = stmt.executeUpdate(u);
    LOG.service("Result :" + result);
  }

  protected boolean executeOnlyIf(Connection con, String q) throws SQLException {
    if (q == null) return true;
    Statement stmt = null;
    try {
      stmt = con.createStatement();
      q = q.replace("$PREFIX", getPrefix());
      LOG.debug(" Executing query " + q);
      ResultSet rs = stmt.executeQuery(q);
      rs.next();
      boolean res = rs.getBoolean(1);
      LOG.debug("Result: " + res);
      return res;
    } catch (SQLException sqe) {
      LOG.error(sqe.getMessage() + " from " + q);
      throw sqe;
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
        }
      } catch (Exception g) {
      }
    }
  }

  public void run() {
    Connection con = null;
    Statement stmt = null;
    try {
      DataSource ds = getDataSource();
      con = ds.getConnection();
      if (executeOnlyIf(con, onlyIfQuery)) {
        stmt = con.createStatement();
        if (query != null) {
          executeQuery(stmt, query);
        } else if (update != null) {
          executeUpdate(stmt, update);
        } else {
          throw new IllegalStateException("Both query and update properties are unset");
        }
      } else {
        LOG.debug("Skipped because of " + onlyIfQuery);
      }
    } catch (RuntimeException e) {
      throw e;
    } catch (Throwable t) {
      if (ignore.matcher(t.getMessage()).matches()) {
        LOG.info("Ignoring " + t.getMessage());
      } else {
        throw new RuntimeException(t.getMessage(), t);
      }
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
        }
      } catch (Exception g) {
      }
      try {
        if (con != null) {
          con.close();
        }
      } catch (Exception g) {
      }
    }
  }

  @Override
  public String toString() {
    if (update != null) {
      return update;
    } else if (query != null) {
      return query;
    } else {
      return "No query yet";
    }
  }
}
예제 #9
0
/**
 * This return page resolver will return the referrer url wiht a parameter 'nodenr' added when there
 * is a new node in the result container. if there is an error it will return the value of the
 * errorPage field. TODO: make sure the error page exists and shows the errors well. only global
 * errors should trigger the error page. field errors should be shown in the editor.
 *
 * @author ebunders
 */
public class ReferrerResolver implements ModelAndViewResolver {
  private static Logger log = Logging.getLoggerInstance(ReferrerResolver.class);
  private String errorPage;

  public ModelAndView getModelAndView(HttpServletRequest request, ResultContainer result) {

    Map<String, Object> model = new HashMap<String, Object>();
    model.put("idmap", result.getIdMap());
    ModelAndView errorMandv = new ModelAndView(errorPage);

    List<GlobalError> globalErrors = result.getGlobalErrors();
    if (result.hasGlobalErrors()) {
      errorMandv.addObject(GlobalError.MODEL_MAPPING_KEY, globalErrors);
      log.debug("request has global errors, so the return page is: " + errorPage);
      return errorMandv;
    }

    if (result.hasFieldErrors()) {
      model.put(FieldError.MODEL_MAPPING_KEY, result.getFieldErrors());
      // Field errors are not displayed in the error page but in the referrer page (the form)
    }

    // has a new object been created?
    // String newObject = result.getNewObjects();
    // set the new object in the request (why?)
    // if (newObject != null) {
    // request.setAttribute("newObject", newObject);
    // if (log.isDebugEnabled()) {
    // log.debug("object number " + newObject);
    // }
    // }
    final String callerPage = request.getHeader("referer");
    if (callerPage == null) {
      // this is an error for this view resolver
      globalErrors.add(new GlobalError("error.no.referrer.header", result.getLocale()));
      log.error("REFERRER NOT SET! This request's redirection wil fail.");
      errorMandv.addObject(GlobalError.MODEL_MAPPING_KEY, globalErrors);
      return errorMandv;
    }
    // add the node number of the new object to the referer url.

    //        if (result.getNewObject().size() > 0) {
    //            if (log.isDebugEnabled()) {
    //                log.debug("new object created.");
    //            }
    //            String newNodeNr = result.getNewObject().get(0);
    //            //newPage = newPage.substring(0, newPage.indexOf("?") + 1) + "nodenr=" +
    // newNodeNr;
    //            String newPage = new URLParamMap(callerPage).addParam("nodenr", newNodeNr,
    // true).toString();
    //        }

    URLParamMap u = new URLParamMap(callerPage);
    if (result.getExtraParams().size() > 0) {
      for (String param : result.getExtraParams().keySet()) {
        u.addParam(param, result.getExtraParams().get(param), true);
      }
    }

    RedirectView redirectView = new RedirectView(u.toString());
    return new ModelAndView(redirectView, model);
  }

  public void setErrorPage(String errorPage) {
    this.errorPage = errorPage;
  }
}
예제 #10
0
파일: Contexts.java 프로젝트: mihxil/mmbase
/**
 * Representation of a 'context', which can be read as a valid value of the 'owner' field of any
 * object in MMBase. Rights are distributed using this thing. This is part of cloud context
 * security, so the 'context' values need to be present in the cloud.
 *
 * @author Eduard Witteveen
 * @author Pierre van Rooden
 * @author Michiel Meeuwissen
 * @version $Id$
 * @see org.mmbase.security.implementation.cloudcontext.Verify
 * @see org.mmbase.security.Authorization
 */
public class Contexts extends MMObjectBuilder {
  private static final Logger log = Logging.getLoggerInstance(Contexts.class);

  /** @javadoc */
  public static final String DEFAULT_CONTEXT =
      "default"; // default used to be 'admin', but does that make sense?

  static final int DEFAULT_MAX_CONTEXTS_IN_QUERY = 50;
  public static final Parameter<String> PARAMETER_OPERATION =
      new Parameter<String>("operation", String.class);
  public static final Parameter<String> PARAMETER_GROUPORUSER =
      new Parameter<String>("grouporuser", String.class);

  /**
   * Things which must be cleared when some security objects change, can all be collected in this
   * map
   */

  // protected static Map<String,SortedSet<String>>  invalidableObjects = new
  // HashMap<String,SortedSet<String>>();

  private boolean readAll = false;

  private boolean allContextsPossible =
      true; // if you want to use security for workflow, then you want this to be false
  private boolean disableContextChecks = false;

  private int maxContextsInQuery = DEFAULT_MAX_CONTEXTS_IN_QUERY;

  private ContextProvider provider;

  protected ContextProvider createProvider() {
    return new BasicContextProvider(Contexts.this) {
      @Override
      protected boolean isAllContextsPossible() {
        return Contexts.this.allContextsPossible;
      }

      @Override
      protected boolean canReadAll() {
        return Contexts.this.readAll;
      }

      @Override
      protected int getMaxContextsInQuery() {
        return Contexts.this.maxContextsInQuery;
      }

      @Override
      protected boolean disableContextChecks() {
        return Contexts.this.disableContextChecks;
      }
    };
  }

  /** @javadoc */
  public boolean init() {
    String s = getInitParameters().get("readall");
    readAll = "true".equals(s);

    s = getInitParameters().get("allcontextspossible");
    allContextsPossible = !"false".equals(s);

    s = getInitParameters().get("maxcontextsinquery");
    if (!"".equals(s) && s != null) {
      maxContextsInQuery = Integer.parseInt(s);
    }

    s = getInitParameters().get("disableContextChecks");
    if (!"".equals(s) && s != null) {
      disableContextChecks = "true".equals(s);
    }
    provider = createProvider();

    return super.init();
  }

  /** Staticly receives the MMObjectBuilder instance (cast to Contexts). A utility function. */
  public static Contexts getBuilder() {
    return (Contexts) MMBase.getMMBase().getBuilder("mmbasecontexts");
  }

  public ContextProvider getProvider() {
    return provider;
  }

  protected boolean isOwnNode(User user, MMObjectNode node) {
    return Authenticate.getInstance().getUserProvider().isOwnNode(user, node);
  }

  protected boolean mayDo(
      MMObjectNode user, MMObjectNode contextNode, Operation operation, boolean checkOwnRights) {
    return provider.mayDoOnContext(user, contextNode, operation, checkOwnRights);
  }

  /**
   * Implements check function with same arguments of Authorisation security implementation
   *
   * @see Verify#check(UserContext, Query, Operation)
   */
  public Authorization.QueryCheck check(User userContext, Query query, Operation operation) {
    return provider.check(userContext, query, operation);
  }

  public final MMObjectNode getDefaultContextNode() {
    return getProvider().getContextNode(DEFAULT_CONTEXT);
  }

  // ********************************************************************************
  // EDIT FUNCTIONS
  // ********************************************************************************

  /** Makes sure unique values and not-null's are filed */
  public void setDefaults(MMObjectNode node) {
    setUniqueValue(node, "name", "context");
  }

  /** @javadoc */
  protected MMObjectNode getUserNode(UserContext user) {
    return ((User) user).getNode();
  }

  protected MMObjectNode getGroupOrUserNode(Parameters a) {
    MMObjectNode groupOrUser = getNode(a.getString(PARAMETER_GROUPORUSER));
    if (groupOrUser == null)
      throw new IllegalArgumentException(
          "There is no node with id '" + a.get(PARAMETER_GROUPORUSER) + "'");

    MMObjectBuilder parent = groupOrUser.getBuilder();
    MMObjectBuilder userBuilder = Authenticate.getInstance().getUserProvider().getUserBuilder();
    if (!(parent instanceof Groups || userBuilder.getClass().isInstance(parent))) {
      throw new IllegalArgumentException(
          "Node '" + a.get(PARAMETER_GROUPORUSER) + "' does not represent a group or a user");
    }
    return groupOrUser;
  }

  public String toString(MMObjectNode n) {
    return n.getStringValue("name");
  }
}
예제 #11
0
/**
 * A bean can be accessed through the function framework.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.8
 */
public final class ExampleBean {

  private static final Logger log = Logging.getLoggerInstance(ExampleBean.class);
  private String parameter1;
  private Integer parameter2 = 0;
  private String parameter3 = "default";
  private Node node;
  private Cloud cloud;

  public void setParameter1(String hoi) {
    parameter1 = hoi;
  }

  public void setParameter2(Integer j) {
    parameter2 = j;
  }

  public Integer getParameter2() {
    return parameter2;
  }

  public void setAnotherParameter(String a) {
    parameter3 = a;
  }

  public String getAnotherParameter() {
    return parameter3;
  }

  /** Makes this bean usable as a Node function. */
  public void setNode(Node node) {
    this.node = node;
  }

  /**
   * Makes the functions usable in bridge (so with security). See also {@link Parameter#CLOUD}. This
   * is an example of a parameter which is automatically filled by function tags.
   */
  public void setCloud(Cloud c) {
    cloud = c;
  }

  /** A function defined by this class */
  public String stringFunction() {
    return "[[" + parameter1 + "/" + parameter3 + "]]";
  }

  public Integer integerFunction() {
    return parameter2 * 3;
  }

  /** A function returning a Map */
  public Map<String, String> mapFunction() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("bloe", parameter1);
    return map;
  }

  /** A function returning a Node as a core object (deprecated). */
  /*
  public MMObjectNode nodeFunction1() {
      VirtualBuilder builder = new VirtualBuilder(MMBase.getMMBase());
      MMObjectNode virtual = builder.getNewNode("admin");
      virtual.storeValue("bloe", parameter1);
      return virtual;
  }
  */

  public Node nodeFunction1() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("bloe", parameter1);
    return new org.mmbase.bridge.util.MapNode(map);
  }

  /** A function returning a Node as a bridge object, but based on a Map of values. */
  public Node nodeFunction2() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("bloe", parameter1);
    return new org.mmbase.bridge.util.MapNode(map);
  }

  public Collection<Object> nodeListFunction() {
    List<Object> result = new ArrayList<Object>();
    result.add(nodeFunction1());
    result.add(nodeFunction2());
    return result;
  }

  public NodeList nodeListFunction1() {
    Collection<Object> col = nodeListFunction();
    col.add(mapFunction());
    // return new org.mmbase.bridge.util.CollectionNodeList(col);
    // it's safer to specify the cloud too, especially to be able to convert the result of
    // nodeFunction1()
    return new org.mmbase.bridge.util.CollectionNodeList(col, cloud);
  }

  /**
   * A real node-function (using the node argument). Returns the next newer node of same type. Also
   * a nice example on the difference between core and bridge.
   */
  public Object successor() {
    if (node == null) throw new IllegalArgumentException("successor is a node-function");
    if (cloud != null) {
      log.debug("Using bridge (security restrictions will be honoured)");
      NodeManager nm = node.getNodeManager();
      NodeQuery q = nm.createQuery();
      StepField field = q.getStepField(nm.getField("number"));
      q.setConstraint(
          q.createConstraint(
              field, FieldCompareConstraint.GREATER, Integer.valueOf(node.getNumber())));
      q.addSortOrder(field, SortOrder.ORDER_ASCENDING);
      q.setMaxNumber(1);
      NodeIterator i = nm.getList(q).nodeIterator();
      return i.hasNext() ? i.nextNode() : null;
    } else {
      log.debug("Using core.");
      throw new UnsupportedOperationException("Core implementation was dropped. See source code.");
      /* This is how it would go with core objects
      MMObjectBuilder builder = MMBase.getMMBase().getBuilder(node.getNodeManager().getName());
      NodeSearchQuery query = new NodeSearchQuery(builder);
      StepField field = query.getField(builder.getField("number"));
      BasicFieldValueConstraint cons = new BasicFieldValueConstraint(field, node.getNumber());
      cons.setOperator(FieldCompareConstraint.GREATER);
      query.setConstraint(cons);
      query.addSortOrder(field);
      query.setMaxNumber(1);
      try {
          java.util.Iterator<MMObjectNode> i = builder.getNodes(query).iterator();
          return i.hasNext() ?  i.next() : null;
      } catch (Exception e) {
          return null;
      }
      */
    }
  }
}
예제 #12
0
/**
 * This maintains a list of reusable {@link CommandExecutor.Method}s. You can obtain on unused one
 * with {@link #getFreeExecutor}. Supposing that you are going to want to use it in a seperate
 * thread, it also maintains ThreadPoolExecuters.
 *
 * @author Michiel Meeuwissen
 * @since MMBase-1.9.6
 */
public class Executors {

  private static final Logger LOG = Logging.getLoggerInstance(Processor.class);

  static {
    EntityResolver.registerSystemID(
        Processor.NAMESPACE_CREATECACHES + ".xsd", Processor.XSD_CREATECACHES, Processor.class);
  }

  private Executors() {
    // no instances;
  }

  private static int transSeq = 0;

  private static final Map<Stage, ThreadPoolExecutor> threadPools =
      new EnumMap<Stage, ThreadPoolExecutor>(Stage.class);
  private static final ConcurrentHashMap<CommandExecutor.Method, Stage> executorsMap =
      new ConcurrentHashMap<CommandExecutor.Method, Stage>();

  public static Map<CommandExecutor.Method, Stage> getExecutors() {
    return executorsMap;
  }

  protected static final ResourceWatcher watcher =
      new ResourceWatcher() {
        @Override
        public void onChange(String resource) {
          try {
            LOG.debug("Reading " + resource);

            HashMap<CommandExecutor.Method, Stage> newexecutorsMap =
                new HashMap<CommandExecutor.Method, Stage>();
            Document document = getResourceLoader().getDocument(resource);
            Map<Stage, Integer> totals = new EnumMap<Stage, Integer>(Stage.class);

            if (document != null) {
              org.w3c.dom.NodeList ellist = document.getDocumentElement().getChildNodes();

              Stage prevStage = Stage.RECOGNIZER;
              for (int i = 0; i <= ellist.getLength(); i++) {
                if (ellist.item(i) instanceof Element) {
                  Element el = (Element) ellist.item(i);
                  if (el.getTagName().equals("localhost")) {
                    int max = Integer.parseInt(el.getAttribute("max_simultaneous_transcoders"));
                    Stage s = Stage.valueOf(el.getAttribute("stage").toUpperCase());
                    Integer t = totals.get(s);
                    if (t == null) t = 0;
                    t += max;
                    totals.put(s, t);
                    for (int j = 1; j <= max; j++) {
                      newexecutorsMap.put(new CommandExecutor.Method(), s);
                    }
                  } else if (el.getTagName().equals("server")) {
                    int max = Integer.parseInt(el.getAttribute("max_simultaneous_transcoders"));
                    Stage s = Stage.valueOf(el.getAttribute("stage").toUpperCase());
                    Integer t = totals.get(s);
                    if (t == null) t = 0;
                    t += max;
                    totals.put(s, t);
                    String host = el.getAttribute("host");
                    int port = Integer.parseInt(el.getAttribute("port"));
                    for (int j = 1; j <= max; j++) {
                      newexecutorsMap.put(new CommandExecutor.Method(host, port), s);
                    }
                  }
                }
              }
              for (Map.Entry<Stage, Integer> e : totals.entrySet()) {
                threadPools.get(e.getKey()).setCorePoolSize(e.getValue());
                threadPools.get(e.getKey()).setMaximumPoolSize(e.getValue());
              }
            } else {
              LOG.warn("No " + resource);
            }
            synchronized (executorsMap) {
              executorsMap.clear();
              executorsMap.putAll(newexecutorsMap);
            }
            LOG.service(
                "Reading of configuration file "
                    + resource
                    + " successfull. Executors "
                    + executorsMap
                    + ". Max simultaneous transcoders: "
                    + totals);
          } catch (Exception e) {
            LOG.error(
                e.getClass()
                    + " "
                    + e.getMessage()
                    + " In "
                    + resource
                    + " Executors now "
                    + executorsMap
                    + " (not changed)",
                e);
          }
        }
      };

  static {
    threadPools.put(
        Stage.TRANSCODER,
        new ThreadPoolExecutor(
            3,
            3,
            5 * 60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(),
            new ThreadFactory() {
              public Thread newThread(Runnable r) {
                return ThreadPools.newThread(
                    r, "TranscoderThread-" + Stage.TRANSCODER + "-" + (transSeq++));
              }
            }));
    threadPools.put(
        Stage.RECOGNIZER,
        new ThreadPoolExecutor(
            3,
            3,
            5 * 60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(),
            new ThreadFactory() {
              public Thread newThread(Runnable r) {
                return ThreadPools.newThread(
                    r, "TranscoderThread-" + Stage.RECOGNIZER + "-" + (transSeq++));
              }
            }));

    // register them too
    ThreadPools.getThreadPools()
        .put(Executors.class.getName() + "." + Stage.TRANSCODER, threadPools.get(Stage.TRANSCODER));
    ThreadPools.getThreadPools()
        .put(Executors.class.getName() + "." + Stage.RECOGNIZER, threadPools.get(Stage.RECOGNIZER));

    // fill the rest of the map too, so we don't have to think about it any more later on.
    for (Stage s : Stage.values()) {
      if (!threadPools.containsKey(s)) {
        threadPools.put(s, ThreadPools.jobsExecutor);
      }
    }
    // default configuration, 5 + 1 executors.
    for (int i = 0; i < 5; i++) {
      executorsMap.put(new CommandExecutor.Method(), Stage.TRANSCODER);
    }
    executorsMap.put(new CommandExecutor.Method(), Stage.RECOGNIZER);
    readConfiguration();
  }

  protected static void readConfiguration() {
    watcher.exit();
    watcher.add("streams/createcaches.xml");
    watcher.setDelay(10000);
    watcher.onChange();
    watcher.start();
  }

  public static CommandExecutor.Method getFreeExecutor() {
    // for backwards compatability, be sure to return one
    return getFreeExecutor(Stage.TRANSCODER);
  }

  public static CommandExecutor.Method getFreeExecutor(Stage st) {
    while (true) {
      synchronized (executorsMap) {
        try {
          for (Map.Entry<CommandExecutor.Method, Stage> entry : executorsMap.entrySet()) {
            if (!entry.getKey().isInUse() && entry.getValue() == st) {
              CommandExecutor.Method m = entry.getKey();
              m.setInUse(true);
              return m;
            }
          }

          LOG.info("All executors for stage " + st + " in use (will wait..)");
          executorsMap.wait();

        } catch (InterruptedException ie) {
          return null;
        }
      }
    }
  }

  public static void notifyExecutors() {
    synchronized (executorsMap) {
      executorsMap.notifyAll();
    }
  }

  public static Future submit(Stage s, Callable c) {
    return threadPools.get(s).submit(c);
  }
}
예제 #13
0
/**
 * A {@link Renderer} implementation based on an MMBase's {@link org.mmbase.util.ResourceLoader}.
 * Blocks rendered with this, cannot have parameters.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.9
 */
public class ResourceRenderer extends AbstractRenderer {
  private static final Logger log = Logging.getLoggerInstance(ResourceRenderer.class);

  protected String resource;
  protected String resourceType = "web";
  protected String xsl = null;
  protected boolean decorate = false;

  public ResourceRenderer(Type t, Block parent) {
    super(t, parent);
  }

  public void setResource(String r) {
    resource = r;
  }

  public void setType(String t) {
    resourceType = t;
  }

  public void setXslt(String x) throws MalformedURLException {
    xsl = x;
  }

  public void setDecorate(boolean d) {
    decorate = d;
  }

  private String getResource() {
    if (resourceType.equals("web")) {
      return resource.charAt(0) == '/'
          ? resource
          : JspRenderer.JSP_ROOT + getBlock().getComponent().getName() + '/' + resource;
    } else {
      return resource;
    }
  }

  @Override
  public void render(Parameters blockParameters, Writer w, RenderHints hints)
      throws FrameworkException {

    if (decorate) {
      try {
        decorateIntro(hints, w, null);
      } catch (IOException ioe) {
        throw new FrameworkException(ioe);
      }
    }
    String name = getResource();
    ResourceLoader loader = ResourceLoader.Type.valueOf(resourceType.toUpperCase()).get();
    try {
      InputStream is = loader.getResourceAsStream(name);
      if (is == null)
        throw new FrameworkException(
            "No such resource " + loader.getResource(name) + " in " + loader);
      if (xsl == null) {
        Reader r = loader.getReader(is, name);
        char[] buf = new char[1000];
        int c;
        while ((c = r.read(buf, 0, 1000)) > 0) {
          w.write(buf, 0, c);
        }
      } else {
        /// convert using the xsl and spit out that.
        URL x = ResourceLoader.getConfigurationRoot().getResource(xsl);
        Utils.xslTransform(blockParameters, loader.getResource(name), is, w, x);
      }
    } catch (IOException ioe) {
      throw new FrameworkException(ioe);
    } catch (javax.xml.transform.TransformerException te) {
      throw new FrameworkException(te.getMessage(), te);
    } catch (RuntimeException e) {
      log.debug(e.getMessage(), e);
      throw e;
    } finally {
      if (decorate) {
        try {
          decorateOutro(hints, w);
        } catch (IOException ioe) {
          throw new FrameworkException(ioe);
        }
      }
    }
  }

  @Override
  public String toString() {
    return resource;
  }

  @Override
  public URI getUri() {
    try {
      ResourceLoader loader = ResourceLoader.Type.valueOf(resourceType.toUpperCase()).get();
      return loader.getResource(getResource()).toURI();
    } catch (URISyntaxException use) {
      log.warn(use);
      return null;
    }
  }
}
예제 #14
0
/**
 * The Basic Framework is based on a list of {@link UrlConverter}s. It is configured in
 * 'config/framework.xml'. The order in which the UrlConverters are configured is the order in which
 * they are processed.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.9
 */
public class BasicFramework extends Framework {
  private static final Logger log = Logging.getLoggerInstance(BasicFramework.class);

  public static final String XSD = "basicframework.xsd";
  public static final String NAMESPACE = "http://www.mmbase.org/xmlns/basicframework";

  static {
    org.mmbase.util.xml.EntityResolver.registerSystemID(NAMESPACE + ".xsd", XSD, Framework.class);
  }

  public static final Parameter<String> ACTION = new Parameter<String>("_action", String.class);

  private final ChainedUrlConverter urlConverter = new ChainedUrlConverter();
  private Parameter<?>[] parDef;
  protected final UrlConverter fallbackConverter = new BasicUrlConverter(this);

  protected final LocalizedString description = new LocalizedString("description");

  protected final Map<Setting<?>, Object> settingValues = new HashMap<Setting<?>, Object>();

  public BasicFramework(Element el) {
    configure(el);
  }

  public BasicFramework() {}

  @Override
  public String getUrl(
      String path, Map<String, ?> parameters, Parameters frameworkParameters, boolean escapeAmps)
      throws FrameworkException {
    Url link = urlConverter.getUrl(path, parameters, frameworkParameters, escapeAmps);
    log.debug("got " + link + " from " + urlConverter);
    if (link == Url.NOT) {
      return fallbackConverter.getUrl(path, parameters, frameworkParameters, escapeAmps).getUrl();
    } else {
      return link.getUrl();
    }
  }

  @Override
  public String getProcessUrl(
      String path, Map<String, ?> parameters, Parameters frameworkParameters, boolean escapeAmps)
      throws FrameworkException {
    HttpServletRequest request =
        BasicUrlConverter.getUserRequest(frameworkParameters.get(Parameter.REQUEST));
    State state = State.getState(request);
    frameworkParameters.set(ACTION, state.getId());
    Url url = urlConverter.getProcessUrl(path, parameters, frameworkParameters, escapeAmps);
    if (url == Url.NOT) {
      log.debug("Fall back url");
      return fallbackConverter
          .getProcessUrl(path, parameters, frameworkParameters, escapeAmps)
          .getUrl();
    } else {
      log.debug("Url converter url " + url);
      return url.getUrl();
    }
  }

  @Override
  public String getInternalUrl(String page, Map<String, ?> params, Parameters frameworkParameters)
      throws FrameworkException {
    if (log.isDebugEnabled()) {
      log.debug("calling urlConverter " + urlConverter);
    }
    return urlConverter.getInternalUrl(page, params, frameworkParameters).getUrl();
  }

  @Override
  public String getName() {
    return "BASIC";
  }

  /**
   * Configures the framework by reading its configuration file 'config/framework.xml' containing a
   * list with UrlConverters.
   */
  protected final void configure(Element el) {
    try {
      description.fillFromXml("description", el);

      NodeList urlconverters = el.getElementsByTagName("urlconverter");
      for (int i = 0; i < urlconverters.getLength(); i++) {
        Element element = (Element) urlconverters.item(i);
        UrlConverter uc;
        try {
          uc = (UrlConverter) Instantiator.getInstance(element, (Framework) this);
        } catch (NoSuchMethodException nsme) {
          uc = (UrlConverter) Instantiator.getInstance(element);
        } catch (ClassNotFoundException cnfe) {
          log.warn(org.mmbase.util.xml.XMLWriter.write(element) + " " + cnfe);
          continue;
        } catch (Throwable t) {
          log.error(org.mmbase.util.xml.XMLWriter.write(element) + ": " + t.getMessage(), t);
          if (t.getCause() != null) {
            log.error("Caused by: " + t.getCause().getMessage(), t.getCause());
          }
          continue;
        }
        urlConverter.add(uc);
      }
      parDef = null;

    } catch (Throwable e) {
      log.error(e.getMessage(), e);
    }
    /*
    BasicUrlConverter buc = new BasicUrlConverter(this);
    if (! urlConverter.contains(buc)) {
        urlConverter.add(buc);
    }
    */
    log.info(
        "Configured with "
            + el.getOwnerDocument().getDocumentURI()
            + " "
            + getClass()
            + " "
            + this);
  }

  @Override
  public Block getRenderingBlock(Parameters frameworkParameters) {
    HttpServletRequest request = frameworkParameters.get(Parameter.REQUEST);
    State state = State.getState(request);
    if (state.isRendering()) {
      return state.getBlock();
    } else {
      return null;
    }
  }

  /*public Block getBlock(Parameters frameworkParameters) throws FrameworkException {
      return urlConverter.getBlock(null, frameworkParameters);
  }
  */

  /** */
  @Override
  public Parameter<?>[] getParameterDefinition() {
    if (parDef == null) {
      parDef =
          new Parameter<?>[] {
            ACTION,
            Parameter.REQUEST,
            Parameter.CLOUD,
            new Parameter.Wrapper(urlConverter.getParameterDefinition())
          };
    }
    return parDef;
  }

  @Override
  public Parameters createParameters() {
    return new Parameters(getParameterDefinition());
  }

  public boolean makeRelativeUrl() {
    return false;
  }

  @SuppressWarnings("unchecked")
  protected void setBlockParametersForRender(State state, Parameters blockParameters) {
    ServletRequest request = state.getRequest();
    String prefix = getPrefix(state);
    log.debug("prefix " + prefix);
    blockParameters.setAutoCasting(true);
    for (Map.Entry<String, String[]> entry :
        ((Map<String, String[]>) request.getParameterMap()).entrySet()) {
      String key = entry.getKey();
      if (key.startsWith(prefix)) {
        log.trace("setting" + entry);
        blockParameters.setIfDefined(key.substring(prefix.length()), entry.getValue());
      }
    }
    if (log.isDebugEnabled()) {
      log.debug("Set " + blockParameters);
    }
  }

  /** @todo */
  protected void setBlockParametersForProcess(State state, Parameters blockParameters) {
    ServletRequest request = state.getRequest();
    for (Map.Entry<String, ?> entry : blockParameters.toMap().entrySet()) {
      request.setAttribute(entry.getKey(), entry.getValue());
    }
  }

  protected String getComponentClass() {
    return "mm_fw_basic";
  }

  /**
   * Basic Framework implicitely also processes, i'm not sure if we should require any framework to
   * do that (perhaps we could say, that the render method must process, if that is necessary, and
   * not yet done).
   */
  @Override
  public void render(
      Renderer renderer,
      Parameters blockParameters,
      Parameters frameworkParameters,
      Writer w,
      WindowState windowState)
      throws FrameworkException {
    ServletRequest request = frameworkParameters.get(Parameter.REQUEST);
    if (request == null) {
      throw new IllegalArgumentException("No request object given");
    }

    State state = State.getState(request);
    if (state
        .isRendering()) { // mm:component used during rending of a component, that's fine, but use a
                          // new State.
      state = new State(request);
      log.debug("Alreadying rendering, taking a new state for sub-block-rendering: " + state);
    }

    log.debug("Rendering " + renderer.getBlock() + " " + renderer);
    Object prevHints = request.getAttribute(RenderHints.KEY);
    try {

      request.setAttribute(COMPONENT_CLASS_KEY, getComponentClass());
      request.setAttribute(COMPONENT_CURRENTUSER_KEY, getUserNode(frameworkParameters));

      Renderer actualRenderer = state.startBlock(frameworkParameters, renderer);
      if (!actualRenderer.equals(renderer)) {
        Parameters newBlockParameters = actualRenderer.getBlock().createParameters();
        newBlockParameters.setAllIfDefined(blockParameters);
        blockParameters = newBlockParameters;
      }
      state.setAction(request.getParameter(ACTION.getName()));
      if (state.needsProcess()) {
        log.service("Performing action on " + actualRenderer.getBlock());
        Processor processor = actualRenderer.getBlock().getProcessor();
        state.process(processor);
        log.service("Processing " + actualRenderer.getBlock() + " " + processor);
        setBlockParametersForProcess(state, blockParameters);
        processor.process(blockParameters);
        state.endProcess();
      }

      state.render(actualRenderer);

      setBlockParametersForRender(state, blockParameters);

      RenderHints hints =
          new RenderHints(
              actualRenderer,
              windowState,
              state.getId(),
              getComponentClass(),
              RenderHints.Mode.NORMAL);
      request.setAttribute(RenderHints.KEY, hints);
      actualRenderer.render(blockParameters, w, hints);
      request.setAttribute("org.mmbase.framework.hints", hints);
    } catch (FrameworkException fe) {
      log.debug(fe);
      URI uri = renderer.getUri();
      Renderer error =
          new ErrorRenderer(
              renderer.getType(),
              renderer.getBlock(),
              (uri != null) ? uri.toString() : null,
              500,
              fe);
      RenderHints hints =
          new RenderHints(
              error, windowState, state.getId(), getComponentClass(), RenderHints.Mode.NORMAL);
      error.render(blockParameters, w, hints);
    } finally {
      request.setAttribute(RenderHints.KEY, prevHints);
      state.endBlock();
    }
  }

  /**
   * I think in the basic framework this method is never called explicitely, because processing is
   * done implicitly by the render
   */
  @Override
  public void process(
      Processor processor, Parameters blockParameters, Parameters frameworkParameters)
      throws FrameworkException {
    HttpServletRequest request = frameworkParameters.get(Parameter.REQUEST);
    State state = State.getState(request);
    state.startBlock(frameworkParameters, null);
    setBlockParametersForProcess(state, blockParameters);
    processor.process(blockParameters);
  }

  @Override
  public Node getUserNode(Parameters frameworkParameters) {
    Cloud cloud = frameworkParameters.get(Parameter.CLOUD);
    if (cloud == null) {
      return null;
    } else {
      try {
        int userNode = cloud.getCloudContext().getAuthentication().getNode(cloud.getUser());
        if (cloud.hasNode(userNode)) {
          return cloud.getNode(userNode);
        } else {
          return null;
        }
      } catch (UnsupportedOperationException uoe) {
        // never mind
        return null;
      }
    }
  }

  @Override
  public String getUserBuilder() {
    // TODO
    // return
    // org.mmbase.module.core.MMBase.getMMBase().getMMBaseCop().getAuthentication().getUserBuilder();
    return "mmbaseusers";
  }

  public Map<String, Object> prefix(State state, Map<String, Object> params) {
    return getMap(state, params);
  }

  protected String getPrefix(final State state) {
    // return "_" + renderer.getBlock().getComponent().getName() + "_" +
    // renderer.getBlock().getName() + "_" + count + "_";
    return state.getId() + ":";
  }

  protected Map<String, Object> getMap(final State state, final Map<String, Object> params) {
    return new AbstractMap<String, Object>() {
      @Override
      public Set<Map.Entry<String, Object>> entrySet() {
        return new AbstractSet<Map.Entry<String, Object>>() {
          @Override
          public int size() {
            return params.size();
          }

          @Override
          public Iterator<Map.Entry<String, Object>> iterator() {
            return new Iterator<Map.Entry<String, Object>>() {
              private Iterator<Map.Entry<String, Object>> i = params.entrySet().iterator();

              @Override
              public boolean hasNext() {
                return i.hasNext();
              }

              @Override
              public Map.Entry<String, Object> next() {
                Map.Entry<String, Object> e = i.next();
                return new org.mmbase.util.Entry<String, Object>(
                    getPrefix(state) + e.getKey(), e.getValue());
              }

              @Override
              public void remove() {
                throw new UnsupportedOperationException();
              }
            };
          }
        };
      }
    };
  }

  @Override
  public String toString() {
    return getName() + ": " + description + ": " + urlConverter.toString();
  }

  private static final Parameter<Boolean> USE_REQ =
      new Parameter<Boolean>("usesession", Boolean.class, Boolean.TRUE);

  @Override
  public Parameters createSettingValueParameters() {
    return new Parameters(Parameter.REQUEST, Parameter.CLOUD, USE_REQ);
  }

  protected String getKey(Setting<?> setting) {
    return "org.mmbase.framework." + setting.getComponent().getName() + "." + setting.getName();
  }

  @SuppressWarnings("unchecked")
  @Override
  public <C> C getSettingValue(Setting<C> setting, Parameters parameters) {
    boolean useSession = parameters != null && parameters.get(USE_REQ);
    if (useSession) {
      HttpServletRequest req = parameters.get(Parameter.REQUEST);
      if (req != null) {
        Object v = req.getSession(true).getAttribute(getKey(setting));
        if (v != null) {
          return setting.getDataType().cast(v, null, null);
        }
      }
    }
    if (settingValues.containsKey(setting)) {
      return (C) settingValues.get(setting);
    } else {
      C settingValue = loadSettingValue(setting);
      if (settingValue != null) {
        settingValues.put(setting, settingValue);
        return settingValue;
      }
      return setting.getDataType().getDefaultValue();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public <C> C setSettingValue(Setting<C> setting, Parameters parameters, C value) {
    if (parameters == null)
      throw new SecurityException("You should provide Cloud and request parameters");
    boolean useSession = parameters.get(USE_REQ);
    if (useSession) {
      C ret = getSettingValue(setting, parameters);
      HttpServletRequest req = parameters.get(Parameter.REQUEST);
      req.getSession(true).setAttribute(getKey(setting), value);
      return ret;
    } else {
      Cloud cloud = parameters.get(Parameter.CLOUD);
      if (cloud.getUser().getRank() == org.mmbase.security.Rank.ADMIN) {
        saveSettingValue(setting, value);
        return (C) settingValues.put(setting, value);
      } else {
        throw new SecurityException("Permission denied");
      }
    }
  }

  public <C> C loadSettingValue(Setting<C> setting) {
    String v =
        null; // TODO SystemProperties.getComponentProperty(setting.getComponent().getName(),
              // setting.getName());
    if (v != null) {
      return setting.getDataType().cast(v, null, null);
    }
    return null;
  }

  public <C> void saveSettingValue(Setting<C> setting, C value) {
    // SystemProperties.setComponentProperty(setting.getComponent().getName(), setting.getName(),
    // value.toString());
  }
}
예제 #15
0
/**
 * @javadoc
 * @deprecated is this (cacheversionfile) used? seems obsolete now
 * @author Daniel Ockeloen
 * @version $Id$
 */
class VersionCacheNode {

  private static Logger log = Logging.getLoggerInstance(VersionCacheNode.class.getName());
  private MMObjectNode versionnode;
  private List<VersionCacheWhenNode> whens = new Vector<VersionCacheWhenNode>();
  private MMBase mmb;

  public VersionCacheNode(MMBase mmb) {
    this.mmb = mmb;
  }
  /** @javadoc */
  public void handleChanged(String buildername, int number) {
    // method checks if this really something valid
    // and we should signal a new version

    boolean dirty = false;
    for (VersionCacheWhenNode whennode : whens) {
      List<String> types = whennode.getTypes();

      // check if im known in the types part
      if (types.contains(buildername)) {
        // is there only 1 builder type ?
        if (log.isDebugEnabled()) log.debug("types=" + types.toString());
        if (types.size() == 1) {
          dirty = true;
        } else {
          // so multiple prepare a multilevel !
          List<String> nodes = whennode.getNodes();

          List<String> fields = new Vector<String>();
          fields.add(buildername + ".number");
          List<String> ordervec = new Vector<String>();
          List<String> dirvec = new Vector<String>();

          List<MMObjectNode> vec =
              mmb.getClusterBuilder()
                  .searchMultiLevelVector(
                      nodes,
                      fields,
                      "YES",
                      types,
                      buildername + ".number==" + number,
                      ordervec,
                      dirvec);
          if (log.isDebugEnabled()) log.debug("VEC=" + vec);
          if (vec != null && vec.size() > 0) {
            dirty = true;
          }
        }
      }
    }

    if (dirty) {
      // add one to the version of this counter
      int version = versionnode.getIntValue("version");
      versionnode.setValue("version", version + 1);
      versionnode.commit();
      if (log.isDebugEnabled()) log.debug("Changed = " + (version + 1));
    }
  }

  public void setVersionNode(MMObjectNode versionnode) {
    this.versionnode = versionnode;
  }

  /** @javadoc */
  public void addWhen(VersionCacheWhenNode when) {
    whens.add(when);
  }
}
예제 #16
0
/**
 * Test class <code>Transaction</code> from the bridge package.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.8.6
 */
public class TransactionTest extends BridgeTest {
  private static final Logger log = Logging.getLoggerInstance(TransactionTest.class);

  public TransactionTest(String name) {
    super(name);
  }

  static int seq = 0;
  int newNode;
  int newNode2;

  public void setUp() {
    seq++;
    // Create some test nodes
    Cloud cloud = getCloud();
    {
      Node node = cloud.getNodeManager("news").createNode();
      node.setStringValue("title", "foo");
      node.commit();
      newNode = node.getNumber();
    }
    {
      Node node = cloud.getNodeManager("news").createNode();
      node.setStringValue("title", "foo");
      node.createAlias("test.news." + seq);
      node.setContext("default");
      node.commit();
      newNode2 = node.getNumber();
    }
  }

  public void testCancel() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("cancel1");
    Node node = t.getNode(newNode);
    node.setStringValue("title", "xxxxx");
    node.commit();
    t.cancel();

    node = cloud.getNode(newNode);

    assertEquals("foo", node.getStringValue("title"));
  }

  public void testCancel2() {
    Cloud cloud = getCloud();
    {
      Transaction t = cloud.getTransaction("cancel2");
      Node node = t.getNode(newNode);
      node.setStringValue("title", "xxxxx");
      node.commit();
      t.cancel();
    }
    {
      Transaction t = cloud.getTransaction("cancel2");
      Node node = t.getNode(newNode);
      assertEquals("foo", node.getStringValue("title"));
      t.cancel();
    }
  }

  public void testGetTransaction() {
    Cloud cloud = getCloud();

    {
      Transaction t = cloud.getTransaction("gettransactiontest");
      Node node = t.getNode(newNode);
      node.setStringValue("title", "xxxxx");
    }
    {
      Transaction t = cloud.getTransaction("gettransactiontest");
      Node node = t.getNode(newNode);
      assertEquals("xxxxx", node.getStringValue("title"));
      t.cancel();
    }
  }

  public void testCommit() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar3");
    Node node = t.getNode(newNode);
    node.setStringValue("title", "yyyyy");
    node.commit();
    t.commit();

    node = cloud.getNode(newNode);

    assertEquals("yyyyy", node.getStringValue("title"));
  }

  public void testMMB1546() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("test0");
    Node nt = t.getNode(newNode);
    nt.setValue("title", "bla");
    // t.cancel(); _DONT_ cancel
    Node nc = cloud.getNode(newNode);
    nc.setValue("title", "bloe");
    nc.commit();
    assertEquals("bloe", nc.getStringValue("title"));
    assertEquals("bloe", cloud.getNode(newNode).getStringValue("title"));
    t.cancel();
    assertEquals("bloe", cloud.getNode(newNode).getStringValue("title"));
  }

  // Test for http://www.mmbase.org/jira/browse/MMB-1621
  public void testGetValue() {
    Cloud cloud = getCloud();

    String value = cloud.getNode(newNode).getStringValue("title");
    assertFalse("zzzzz".equals(value));

    Transaction t = cloud.getTransaction("bar4");
    System.out.println("Transaction now " + t);
    Node node = t.getNode(newNode);
    assertEquals(1, t.getNodes().size());
    node.setStringValue("title", "zzzzz");
    assertEquals("zzzzz", node.getStringValue("title"));
    node.commit(); // committing inside transaction

    assertEquals("zzzzz", node.getStringValue("title"));
    assertEquals(value, cloud.getNode(newNode).getStringValue("title"));

    t.commit();
    assertEquals("zzzzz", cloud.getNode(newNode).getStringValue("title"));
  }

  public void testReuseTransaction() {
    Cloud cloud = getCloud();
    {
      Node node = cloud.getNode(newNode);
      node.setStringValue("title", "zzyyxx");
      node.commit();
      assertEquals("zzyyxx", cloud.getNode(newNode).getStringValue("title"));
    }
    {
      Transaction t = cloud.getTransaction("bar4");
      assertEquals(0, t.getNodes().size());
      Node node = t.getNode(newNode);
      assertEquals("zzyyxx", node.getStringValue("title"));
      assertEquals(1, t.getNodes().size());
      node.setStringValue("title", "wwwwww");
      node.commit();
      assertEquals("wwwwww", node.getStringValue("title"));
      t.cancel();
      assertEquals("zzyyxx", cloud.getNode(newNode).getStringValue("title"));
    }
    assertEquals("zzyyxx", cloud.getNode(newNode).getStringValue("title"));
  }

  public void testCancelDelete() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar5");
    Node node = t.getNode(newNode);
    node.delete();
    t.cancel();
    assertTrue(cloud.hasNode(newNode));
  }

  public void testCommitDelete() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar6");
    Node node = t.getNode(newNode);
    node.delete();
    t.commit();
    assertFalse(cloud.hasNode(newNode));
  }

  public void testSetContext() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar7");
    Node n = t.getNodeManager("news").createNode();

    assertEquals(1, t.getNodes().size());

    n.setContext("non_default");

    assertEquals(1, t.getNodes().size());

    assertEquals("non_default", n.getStringValue("owner"));
    assertEquals("non_default", n.getContext());

    assertEquals(1, t.getNodes().size());

    t.commit();

    Node n2 = cloud.getNode(n.getNumber());
    assertEquals("non_default", n2.getStringValue("owner"));
    assertEquals("non_default", n2.getContext());
  }

  public void testSetContextSubTransaction() {
    Cloud cloud = getCloud();

    Transaction ot = cloud.getTransaction("bar8");
    Transaction t = ot.getTransaction("bar9");
    Node n = t.getNodeManager("news").createNode();
    n.setContext("non_default");
    assertEquals("non_default", n.getContext());
    t.commit();

    Node n2 = ot.getNode(n.getNumber());
    assertEquals("non_default", n2.getContext());

    ot.commit();
    Node n3 = cloud.getNode(n.getNumber());
    assertEquals("non_default", n3.getContext());
  }

  public void testEditNodeOutsideTransaction() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar10");
    Node nodeInTransaction = t.getNode(newNode2);
    nodeInTransaction.setStringValue("title", "foo2");
    Node nodeOutTransaction = cloud.getNode(newNode2);
    nodeOutTransaction.setStringValue("title", "bar2");

    nodeOutTransaction.commit();
    t.commit();

    // transaction was committed _later_ so its commit of the node must have won
    assertEquals("foo2", cloud.getNode(newNode2).getStringValue("title"));
    assertEquals("foo2", nodeInTransaction.getStringValue("title"));
    // assertEquals("foo2", nodeOutTransaction.getStringValue("title")); // not sure what this
    // should have done, but anyhow, it now fails

  }

  public void testEditNodeOutsideTransaction2() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar10");
    Node nodeInTransaction = t.getNode(newNode2);
    nodeInTransaction.setStringValue("title", "foo2");
    Node nodeOutTransaction = cloud.getNode(newNode2);
    nodeOutTransaction.setStringValue("title", "bar2");

    t.commit();
    nodeOutTransaction.commit();

    // transaction was committed _earlier_ so the commit of the node must have won
    assertEquals("bar2", cloud.getNode(newNode2).getStringValue("title"));
    // assertEquals("bar2", nodeInTransaction.getStringValue("title"));// not sure what this should
    // have done, but anyhow, it now fails
    assertEquals("bar2", nodeOutTransaction.getStringValue("title"));
  }

  public void testDeleteNodeOutsideTransaction() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar11");
    Node nodeInTransaction = t.getNode(newNode2);
    nodeInTransaction.setStringValue("title", "foo2");
    {
      // now delete the node
      Node nodeOutTransaction = cloud.getNode(newNode2);
      nodeOutTransaction.delete();
      assertFalse(cloud.hasNode(newNode2));
    }

    try {
      t.commit();
    } catch (Exception e) {
      // should not give exception. MMB-1680
      log.error(e.getMessage(), e);
      fail(e.getMessage());
    }

    assertTrue(cloud.hasNode(newNode2));
  }

  // same case as above, only no changes are made to the node.
  public void testDeleteNodeOutsideTransactionNodeInTransactionButNotChanged() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("bar11");
    Node nodeInTransaction = t.getNode(newNode2);
    // nodeInTransaction.setStringValue("title", "foo2");
    {
      // now delete the node
      Node nodeOutTransaction = cloud.getNode(newNode2);
      nodeOutTransaction.delete();
      assertFalse(cloud.hasNode(newNode2));
    }

    try {
      // make a relation to the (deleted) node, but in the transaction, where the node still
      // exists.
      // This demonstrate that there is an actual problem if the node ends up non-existing now.
      Node url = t.getNodeManager("urls").createNode();
      RelationManager rm = t.getRelationManager("news", "urls", "posrel");
      Relation r = nodeInTransaction.createRelation(url, rm);
      t.commit();
    } catch (Exception e) {
      // should not give exception. MMB-1680
      log.error(e.getMessage(), e);
      fail(e.getMessage());
    }

    assertTrue(cloud.hasNode(newNode2));
    assertEquals(1, cloud.getNode(newNode2).countRelations());
  }

  public void testAlias() {
    Cloud cloud = getCloud();
    {
      Node node = cloud.getNode(newNode2);
      node.setStringValue("title", "abcdef");
      node.commit();
      assertEquals("abcdef", node.getStringValue("title"));
      node = cloud.getNode("test.news." + seq);
      assertEquals("abcdef", node.getStringValue("title"));
    }

    {
      Transaction t = cloud.getTransaction("bar12");

      Node node = t.getNode(newNode2);
      node.setStringValue("title", "abcdefg");
      node.commit();
      assertEquals("abcdefg", node.getStringValue("title"));
      t.commit();
      assertEquals("abcdefg", node.getStringValue("title"));

      node = cloud.getNode("test.news." + seq);
      assertEquals("abcdefg", node.getStringValue("title"));

      node = cloud.getNode(newNode2);
      assertEquals("abcdefg", node.getStringValue("title"));
    }
  }

  public void testGetNodeTwiceWhileChanged() {
    Cloud cloud1 = getCloud();
    String originalTitleValue = cloud1.getNode(newNode2).getStringValue("title");
    {
      Node node = cloud1.getNode(newNode2);
      String title1 = node.getStringValue("title");
      node.setStringValue("title", "bla bla");
      // don't commit
    }
    // now change something by someone else
    {
      Cloud cloud2 = getCloud("foo");
      assertTrue(cloud1 != cloud2);
      Node node = cloud2.getNode(newNode2);
      node.setStringValue("title", "new title value");
      node.commit();
    }
    // now look to the original cloud
    {
      Node node = cloud1.getNode(newNode2);
      assertEquals("new title value", node.getStringValue("title"));
    }
  }

  public void testCreateRelationBetweenNewNodes() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("createrelationtrans");
    NodeManager news = t.getNodeManager("news");
    Node n = news.createNode();
    NodeManager urls = t.getNodeManager("urls");
    Node url = urls.createNode();
    RelationManager rm = t.getRelationManager("news", "urls", "posrel");
    Relation r = n.createRelation(url, rm);
    t.commit();
  }

  // new node as argument
  public void testCreateRelationToNewNode() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("createrelationtrans");
    Node n = t.getNode(newNode);
    NodeManager urls = t.getNodeManager("urls");
    Node url = urls.createNode();
    RelationManager rm = t.getRelationManager("news", "urls", "posrel");
    Relation r = n.createRelation(url, rm);
    t.commit();
  }

  // old node as argument
  public void testCreateRelationToNewNode2() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("createrelationtrans");
    Node n = t.getNode(newNode);
    NodeManager urls = t.getNodeManager("urls");
    Node url = urls.createNode();
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(n, rm);
    t.commit();
  }

  public void testTransactionsAreEqual() {
    Cloud cloud = getCloud();
    Transaction t1 = cloud.getTransaction("testequals");
    Transaction t2 = cloud.getTransaction("testequals");
    assertEquals(t1, t2);
    Node n = t1.getNode(newNode);
    NodeManager urls = t2.getNodeManager("urls");
    Node url = urls.createNode();
    RelationManager rm = t2.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(n, rm);
    t2.commit();
    assertTrue(t2.isCommitted());
    assertTrue(t1.isCommitted());
    // assertTrue(t1 == t2); // FAILS IN RMMCI. Perhaps we should simply implement .equals on
    // transactions
  }

  // MMB-1857
  public void testGetNodes() {
    Cloud cloud = getCloud();
    Transaction t = cloud.getTransaction("testgetnodes");
    Node n = t.getNode(newNode);
    Node url = t.getNodeManager("urls").createNode();
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(n, rm);

    {
      // should not give NPE's or so
      n.commit();
      url.commit();
      r.commit();
    }

    assertEquals(3, t.getNodes().size()); // 2 nodes and one relation

    for (Node rn : t.getNodes()) {
      // should occur no exceptions
      rn.commit(); // should have little effect in trans
    }
    t.cancel();
  }

  public void testGetNode() {
    // Create new node. Request the node again.
    // Should work

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());

    Transaction t = cloud.getTransaction("testgetnode");
    Node url = t.getNodeManager("urls").createNode();
    url.setStringValue("url", "http://bla");
    url.commit();

    Node reurl = t.getNode(url.getNumber());

    assertEquals("http://bla", reurl.getStringValue("url"));
  }

  // MMB-1860
  public void testCreateAndDelete() {
    // Create new node. Delete it. Commit the transaction.
    // The new node must not exist.

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());

    Transaction t = cloud.getTransaction("testcreateandelete");
    Node url = t.getNodeManager("urls").createNode();
    url.commit();
    assertEquals(1, t.getNodes().size());
    url.delete();
    assertEquals(
        1,
        t.getNodes()
            .size()); // 0 would also be an option, but the node remaisn in the transaction as
                      // 'NOLONGER'
    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());

    assertEquals(urlCount, urlCountAfter);
  }

  public void testCreateAndDelete2() {
    // Create new node. Request the node again. Delete  that. Commit the transaction.
    // The new node must not exist.

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());

    Transaction t = cloud.getTransaction("testcreateandelete");
    Node url = t.getNodeManager("urls").createNode();
    url.commit();
    assertEquals(1, t.getNodes().size());

    Node reurl = t.getNode(url.getNumber());
    reurl.delete();

    assertEquals(
        1,
        t.getNodes()
            .size()); // 0 would also be an option, but the node remaisn in the transaction as
                      // 'NOLONGER'

    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());

    assertEquals(urlCount, urlCountAfter);
  }

  // MMB-1860 (2)
  public void testCreateRelateAndDelete() {

    // Create new node. Make a relation to it. Delete the node again. Commit the transaction.
    // The new node must not exist, but the relation shouldn't have caused errors

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());

    Transaction t = cloud.getTransaction("testcreateandelete");

    Node news = t.getNode(newNode);
    Node url = t.getNodeManager("urls").createNode();
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(news, rm);

    url.delete(true);

    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());

    assertEquals(urlCount, urlCountAfter);
  }

  // MMB-1860 (3)
  public void testCreateRelateAndDeleteRelation() {

    // Create new node. Make a relation to it. Delete the relation again. Commit the transaction.
    // The new node must exist, but the relation shouldn't.

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());
    int relCount = Queries.count(cloud.getNodeManager("insrel").createQuery());

    Transaction t = cloud.getTransaction("testcreateandelete");

    Node news = t.getNode(newNode);
    Node url = t.getNodeManager("urls").createNode();
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(news, rm);
    r.commit();

    r.delete();

    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());

    assertEquals(urlCount + 1, urlCountAfter);

    // Bit the relation should not exist, because it was deleted angain

    int relCountAfter = Queries.count(cloud.getNodeManager("insrel").createQuery());

    assertEquals(relCount, relCountAfter);
  }

  // MMB-1860 (4)
  public void testRelateAndDeleteRelation() {

    //  Make a relation between two nodes. Delete the relation again. Commit the transaction.
    // Te relation shouldn't exist

    Cloud cloud = getCloud();
    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());
    int relCount = Queries.count(cloud.getNodeManager("insrel").createQuery());

    Node newUrl = cloud.getNodeManager("urls").createNode();
    newUrl.commit();

    Transaction t = cloud.getTransaction("testrelateandeleterelation");

    Node news = t.getNode(newNode);
    Node url = t.getNode(newUrl.getNumber());
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(news, rm);
    r.commit();

    r.delete();

    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());

    assertEquals(urlCount + 1, urlCountAfter);

    // But the relation should not exist, because it was deleted angain

    int relCountAfter = Queries.count(cloud.getNodeManager("insrel").createQuery());

    assertEquals(relCount, relCountAfter);
  }

  // MMB-1889
  public void testCreateRelationAndDeleteNode() {
    // Make a relation to an existing node. Then delete that node with the 'delete relations'
    // option'. Commit the transaction.
    // The new relations should not exist, since the node was deleted.
    // No errors.

    Cloud cloud = getCloud();

    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());
    int relCount = Queries.count(cloud.getNodeManager("insrel").createQuery());

    Node url = cloud.getNodeManager("urls").createNode();
    url.commit();

    Transaction t = cloud.getTransaction("relatedandelete");

    Node turl = t.getNode(url.getNumber());
    Node news = t.getNode(newNode);
    RelationManager rm = t.getRelationManager("urls", "news", "posrel");
    Relation r = turl.createRelation(news, rm);
    r.commit();
    turl.delete(true);
    t.commit();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());
    assertEquals(urlCount, urlCountAfter);
    int relCountAfter = Queries.count(cloud.getNodeManager("insrel").createQuery());
    assertEquals(relCount, relCountAfter);
  }

  // MMB-1893
  public void testDeleteNodeWitRelationsAndCancel() {
    Cloud cloud = getCloud();

    int urlCount0 = Queries.count(cloud.getNodeManager("urls").createQuery());
    int relCount0 = Queries.count(cloud.getNodeManager("insrel").createQuery());

    Node url = cloud.getNodeManager("urls").createNode();
    url.commit();
    Node news = cloud.getNode(newNode);
    RelationManager rm = cloud.getRelationManager("urls", "news", "posrel");
    Relation r = url.createRelation(news, rm);
    r.commit();

    int urlCount = Queries.count(cloud.getNodeManager("urls").createQuery());
    int relCount = Queries.count(cloud.getNodeManager("insrel").createQuery());

    assertEquals(urlCount0 + 1, urlCount);
    assertEquals(relCount0 + 1, relCount);

    Transaction t = cloud.getTransaction("deletewithrelationsandcancel");

    Node turl = t.getNode(url.getNumber());
    turl.delete(true);

    t.cancel();

    int urlCountAfter = Queries.count(cloud.getNodeManager("urls").createQuery());
    assertEquals(urlCount, urlCountAfter);

    int relCountAfter = Queries.count(cloud.getNodeManager("insrel").createQuery());
    assertEquals(relCount, relCountAfter); // MMB-1893
  }
}
예제 #17
0
/**
 * install manager, keeps track of what is being installed, provides background threads and logs
 * errors & message to feedback to users.
 *
 * @author Daniel Ockeloen (MMBased)
 */
public class UninstallManager {
  private static Logger log = Logging.getLoggerInstance(UninstallManager.class);

  // is the uninstall manager active (for dependencies reasons)
  private static boolean active = false;

  // signal if we are installing a bundle or a package
  private static boolean bundle = false;

  // package we are uninstalling
  private static PackageInterface pkg;

  private static BundleInterface bnd;

  private static uninstallThread runner;

  private static String state;

  /** uninstall a package */
  public static synchronized boolean uninstallPackage(PackageInterface p) {
    if (!active) {
      // turn the uninstallManager to active
      active = true;

      // signal we are a package only install
      bundle = false;

      // set the package
      pkg = p;
      state = "uninstalling";
      p.clearInstallSteps();
      runner = new uninstallThread();
      return true;
    } else {
      // returning false _allways_ means we where busy
      // error feedback is provided by the processsteps
      return false;
    }
  }

  /**
   * called by the install thread class, performs the real install in the background and keeps
   * providing feedback using the steps interfaces
   */
  public static void performUninstall() {
    try {
      if (bnd != null) {
        bnd.uninstall();
        state = "waiting";
        active = false;
        bnd = null;
      } else if (pkg != null) {
        pkg.uninstall();
        state = "waiting";
        active = false;
        pkg = null;
      }
    } catch (Exception e) {
      log.error("performInstall problem");
    }
  }

  /** uninstall a package */
  public static synchronized boolean uninstallBundle(BundleInterface b) {
    if (!active) {
      // turn the uninstallManager to active
      active = true;

      // signal we are a package only install
      bundle = true;

      // set the package
      bnd = b;

      state = "uninstalling";

      b.clearInstallSteps();

      runner = new uninstallThread();

      return true;
    } else {
      // returning false _allways_ means we where busy
      // error feedback is provided by the processsteps
      return false;
    }
  }

  public void setState(String state) {
    this.state = state;
  }

  public String getState() {
    return state;
  }

  public static boolean isActive() {
    return active;
  }

  public static PackageInterface getUnInstallingPackage() {
    return pkg;
  }

  public static BundleInterface getUnInstallingBundle() {
    return bnd;
  }

  public static Iterator<installStep> getUninstallSteps() {
    return pkg.getInstallSteps();
  }
}
예제 #18
0
/**
 * If rendering of a {@link Block} fails for some reason this renderer should be used to present the
 * error.
 *
 * @author Michiel Meeuwissen
 * @version $Id$
 * @since MMBase-1.9
 */
public class ErrorRenderer extends AbstractRenderer {
  private static final Logger log = Logging.getLoggerInstance(ErrorRenderer.class);

  protected final Error error;
  protected final String url;

  protected static int MAX_CAUSES = 4;

  public ErrorRenderer(Type t, Block parent, String u, int status, String m) {
    super(t, parent);
    error = new Error(status, new Exception(m));
    url = u;
  }

  public ErrorRenderer(Type t, Block parent, String u, int status, Throwable e) {
    super(t, parent);
    error = new Error(status, e);
    url = u;
  }

  @Override
  public Parameter<?>[] getParameters() {
    return new Parameter<?>[] {Parameter.RESPONSE};
  }

  @Override
  public void render(Parameters blockParameters, Writer w, RenderHints hints)
      throws FrameworkException {
    log.debug("Error rendering " + blockParameters);
    switch (getType()) {
      case BODY:
        try {
          decorateIntro(hints, w, "error");
          w.write("<h1>" + error.status);
          w.write(": ");
          CharTransformer escape = new Xml(Xml.ESCAPE);
          w.write(escape.transform(error.exception.getMessage()));
          w.write(" ");
          w.write(escape.transform(url));
          w.write("</h1>");
          w.write("<pre>");
          HttpServletRequest request = blockParameters.get(Parameter.REQUEST);
          error.getErrorReport(w, request, escape);
          w.write("</pre>");
          decorateOutro(hints, w);
        } catch (IOException eio) {
          throw new FrameworkException(eio.getMessage(), eio);
        }
        break;
      default:
    }
  }

  @Override
  public String toString() {
    return "ERROR " + error;
  }

  @Override
  public java.net.URI getUri() {
    try {
      return new java.net.URL(url).toURI();
    } catch (Exception e) {
      return null;
    }
  }

  public static class Error {
    public int status;
    public final Throwable exception;
    private Boolean showSession = null;
    private Pattern requestIgnore = null;
    private Pattern sessionIgnore = null;
    private Boolean showMMBaseVersion = null;

    public Error(int s, Throwable e) {
      status = s;
      exception = e;
    }

    public void setShowSession(Boolean b) {
      showSession = b;
    }

    public void setRequestIgnore(String i) {
      requestIgnore = i == null ? null : Pattern.compile(i);
    }

    public void setSessionIgnore(String i) {
      sessionIgnore = i == null ? null : Pattern.compile(i);
    }

    public void setShowVersion(Boolean b) {
      showMMBaseVersion = b;
    }

    protected LinkedList<Throwable> getStack() {
      Throwable e = exception;
      LinkedList<Throwable> stack = new LinkedList<Throwable>();
      while (e != null) {
        stack.addFirst(e);
        if (e instanceof NotFoundException) {
          status = HttpServletResponse.SC_NOT_FOUND;
        }
        if (e instanceof ServletException) {
          Throwable t = ((ServletException) e).getRootCause();
          if (t == null) t = e.getCause();
          e = t;
        } else if (e instanceof javax.servlet.jsp.JspException) {
          Throwable t = ((JspException) e).getRootCause();
          if (t == null) t = e.getCause();
          e = t;
        } else {
          e = e.getCause();
        }
      }
      return stack;
    }

    protected String getTitle(Throwable t) {
      String message = t.getMessage();
      String tit = message;
      if (tit == null) {
        StackTraceElement el = t.getStackTrace()[0];
        tit =
            t.getClass().getName().substring(t.getClass().getPackage().getName().length() + 1)
                + " "
                + el.getFileName()
                + ":"
                + el.getLineNumber();
      }
      return tit;
    }

    public String getTitle() {
      LinkedList<Throwable> stack = getStack();
      if (stack.isEmpty()) {
        return "NO EXCEPTION";
      } else {
        return getTitle(stack.removeFirst());
      }
    }

    public Writer getErrorReport(
        Writer to, final HttpServletRequest request, CharTransformer escape) throws IOException {
      final Writer logMsg = new StringWriter();
      final Writer tee = new org.mmbase.util.ChainedWriter(to, logMsg);
      Writer msg = tee;

      LinkedList<Throwable> stack = getStack();
      String ticket = new Date().toString();

      Map<String, String> props;
      try {
        props = org.mmbase.util.ApplicationContextReader.getProperties("mmbase_errorpage");
      } catch (javax.naming.NamingException ne) {
        props = Collections.emptyMap();
        log.info(ne);
      }

      if (request != null) {
        {
          msg.append("Headers\n----------\n");
          // request properties
          for (Object name : Collections.list(request.getHeaderNames())) {
            msg.append(
                escape.transform(
                    name + ": " + escape.transform(request.getHeader((String) name)) + "\n"));
          }
        }
        {
          msg.append("\nAttributes\n----------\n");
          Pattern p = requestIgnore;
          if (p == null && props.get("request_ignore") != null) {
            p = Pattern.compile(props.get("request_ignore"));
          }
          for (Object name : Collections.list(request.getAttributeNames())) {
            if (p == null || !p.matcher((String) name).matches()) {
              msg.append(
                  escape.transform(name + ": " + request.getAttribute((String) name) + "\n"));
            }
          }
        }
        if (Boolean.TRUE.equals(showSession)
            || (showSession == null && !"false".equals(props.get("show_session")))) {
          HttpSession ses = request.getSession(false);
          if (ses != null) {
            msg.append("\nSession\n----------\n");
            Pattern p = sessionIgnore;
            if (p == null && props.get("session_ignore") != null) {
              p = Pattern.compile(props.get("session_ignore"));
            }
            for (Object name : Collections.list(ses.getAttributeNames())) {
              if (p == null || !p.matcher((String) name).matches()) {
                msg.append(escape.transform(name + ": " + ses.getAttribute((String) name) + "\n"));
              }
            }
          }
        }
      }
      msg.append("\n");
      msg.append("Misc. properties\n----------\n");

      if (request != null) {
        msg.append("method: ").append(escape.transform(request.getMethod())).append("\n");
        msg.append("querystring: ").append(escape.transform(request.getQueryString())).append("\n");
        msg.append("requesturl: ")
            .append(escape.transform(request.getRequestURL().toString()))
            .append("\n");
      }
      if (Boolean.TRUE.equals(showMMBaseVersion)
          || (showMMBaseVersion == null && !"false".equals(props.get("show_mmbase_version")))) {
        msg.append("mmbase version: ").append(org.mmbase.Version.get()).append("\n");
      }
      msg.append("status: ").append("").append(String.valueOf(status)).append("\n\n");

      if (request != null) {
        msg.append("Parameters\n----------\n");
        // request parameters
        Enumeration en = request.getParameterNames();
        while (en.hasMoreElements()) {
          String name = (String) en.nextElement();
          msg.append(name)
              .append(": ")
              .append(escape.transform(request.getParameter(name)))
              .append("\n");
        }
      }
      msg.append("\nException ")
          .append(ticket)
          .append("\n----------\n\n")
          .append(
              exception != null
                  ? (escape.transform(exception.getClass().getName()))
                  : "NO EXCEPTION")
          .append(": ");

      int wroteCauses = 0;
      while (!stack.isEmpty()) {

        Throwable t = stack.removeFirst();
        // add stack stacktraces
        if (t != null) {
          if (stack.isEmpty()) { // write last message always
            msg = tee;
          }
          String message = t.getMessage();
          if (msg != tee) {
            to.append("\n=== skipped(see log)  : ")
                .append(escape.transform(t.getClass().getName()))
                .append(": ")
                .append(message)
                .append("\n");
          }

          msg.append("\n\n").append(escape.transform(t.getClass().getName() + ": " + message));
          StackTraceElement[] stackTrace = t.getStackTrace();
          for (StackTraceElement e : stackTrace) {
            msg.append("\n        at ").append(escape.transform(e.toString()));
          }
          if (!stack.isEmpty()) {
            msg.append("\n-------caused:\n");
          }
          wroteCauses++;
          if (wroteCauses >= MAX_CAUSES) {
            msg = logMsg;
          }
        }
      }
      // write errors to  log
      if (status == 500) {
        try {
          if (props.get("to") != null && props.get("to").length() > 0) {
            javax.naming.Context initCtx = new javax.naming.InitialContext();
            javax.naming.Context envCtx = (javax.naming.Context) initCtx.lookup("java:comp/env");
            Object mailSession = envCtx.lookup("mail/Session");
            Class sessionClass = Class.forName("javax.mail.Session");
            Class recipientTypeClass = Class.forName("javax.mail.Message$RecipientType");
            Class messageClass = Class.forName("javax.mail.internet.MimeMessage");
            Object mail = messageClass.getConstructor(sessionClass).newInstance(mailSession);
            messageClass
                .getMethod("addRecipients", recipientTypeClass, String.class)
                .invoke(mail, recipientTypeClass.getDeclaredField("TO").get(null), props.get("to"));
            messageClass.getMethod("setSubject", String.class).invoke(mail, ticket);
            mail.getClass().getMethod("setText", String.class).invoke(mail, logMsg.toString());
            Class.forName("javax.mail.Transport")
                .getMethod("send", Class.forName("javax.mail.Message"))
                .invoke(null, mail);
            tee.append("\nmailed to (").append(String.valueOf(props)).append(")");
          }

        } catch (Exception nnfe) {
          tee.append("\nnot mailed (").append(String.valueOf(nnfe)).append(")");
          if (log.isDebugEnabled()) {
            log.debug(nnfe.getMessage(), nnfe);
          }
        }
        log.error("TICKET " + ticket + ":\n" + logMsg);
      }
      return to;
    }
  }
}
예제 #19
0
/**
 * Downloads a media stream from an url for a media item (mediafragments node) puts it in the files
 * directory and returns it's filename when finished. A timeout parameter let's you set number of
 * seconds you wish to wait for the download to finish. When you specify an email address as
 * parameter you get an email when it's really finished. The function starts a thread and calls
 * {@link Downloader} to do the actual work. The media file itself is saved in a mediasources node
 * and transcoded by the streams application when the download finishes. Url and information about
 * success or failure of the download are saved as properties on the mediafragments node.
 *
 * @author Michiel Meeuwissen
 * @author Andr&eacute; van Toly
 * @version $Id$
 */
public final class DownloadFunction extends NodeFunction<String> {
  private static final long serialVersionUID = 0L;
  private static final Logger log = Logging.getLoggerInstance(DownloadFunction.class);

  /* url to get */
  private static final Parameter<String> URL = new Parameter<String>("url", String.class);
  /* timeout: how long you are prepaired to wait for a result, default is 5 seconds */
  private static final Parameter<Integer> TIMEOUT =
      new Parameter<Integer>("timeout", Integer.class);
  /* email address to send ready to */
  private static final Parameter<String> EMAIL = new Parameter<String>("email", String.class);
  public static final Parameter[] PARAMETERS = {
    URL, EMAIL, TIMEOUT, Parameter.LOCALE, Parameter.REQUEST
  };

  private static final String URL_KEY = DownloadFunction.class.getName() + ".url";
  private static final String STATUS_KEY = DownloadFunction.class.getName() + ".status";

  private static final Map<Integer, Future<?>> runningJobs =
      new ConcurrentHashMap<Integer, Future<?>>();

  public DownloadFunction() {
    super("download", PARAMETERS);
  }

  protected void setProperty(Node node, String key, String value) {
    NodeManager properties = node.getCloud().getNodeManager("properties");
    Function set = properties.getFunction("set");
    Parameters params = set.createParameters();
    params.set("node", node);
    params.set("key", key);
    if (value.length() > 255) {
      value = value.substring(0, 255);
    }
    params.set("value", value);
    set.getFunctionValue(params);
  }

  protected String getProperty(Node node, String key) {
    NodeManager properties = node.getCloud().getNodeManager("properties");
    Function get = properties.getFunction("get");
    Parameters params = get.createParameters();
    params.set("node", node);
    params.set("key", key);
    return (String) get.getFunctionValue(params);
  }

  protected void setDownloadUrl(Node node, String link) {
    setProperty(node, URL_KEY, link);
  }

  protected void setDownloadStatus(Node node, String status) {
    log.info("Setting status of " + node.getNumber() + " to " + status);
    setProperty(node, STATUS_KEY, status);
  }

  protected String getDownloadStatus(Node node) {
    return getProperty(node, STATUS_KEY);
  }

  private Boolean sendMail(HttpServletRequest req, Node node, String email) {
    boolean send = false;

    Cloud cloud = node.getCloud();
    String emailbuilder = "email";
    try {
      Module sendmail = cloud.getCloudContext().getModule("sendmail");
      emailbuilder = sendmail.getProperty("emailbuilder");
    } catch (NotFoundException nfe) {
      log.warn("No email module " + nfe);
    }

    if (cloud.hasNodeManager(emailbuilder)) {

      NodeManager nm = cloud.getNodeManager(emailbuilder);
      Node message = nm.createNode();

      String host = req.getHeader("host");
      if (host == null || "".equals(host)) {
        try {
          host = java.net.InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException uhe) {
          log.warn("No host: " + uhe);
        }
      }
      String from = "downloader@" + host;
      // do a quick check if we've got something more or less valid
      Pattern p = Pattern.compile(".+@.+\\.[a-z]+");
      Matcher m = p.matcher(from);
      if (!m.matches()) {
        from = "*****@*****.**";
      }

      String mediaTitle = node.getStringValue("title");
      String mediaUrl = getProperty(node, URL_KEY);
      StringBuilder body = new StringBuilder();

      body.append("*This is an automated message / Dit is een geautomatiseerd bericht*");
      body.append("\n\n*English*");
      body.append("\n\nDear,");
      body.append("\n\nWe have received your file belonging to media item titled '")
          .append(mediaTitle)
          .append("'. ");
      body.append("In about 1 hour, you can find your submission at: ");
      body.append("http://").append(host).append("/media/").append(node.getNumber());
      body.append("\n\nKind regards,");
      body.append("\n\n").append(host);

      body.append("\n\n\n*Nederlands*");
      body.append("\n\nBeste,");
      body.append("\n\nWe hebben je bestand voor het media item met de titel '")
          .append(mediaTitle)
          .append("' ontvangen. ");
      body.append("Je kunt je bijdrage hier over circa een uur terugvinden: ");
      body.append("http://").append(host).append("/media/").append(node.getNumber());
      body.append("\n\nMet vriendelijke groet,");
      body.append("\n\n").append(host);

      message.setValue("from", from);
      message.setValue("to", email);
      message.setValue("subject", "Download complete / Download voltooid");
      message.setValue("body", body.toString());
      message.commit();

      Function mail = message.getFunction("mail");
      Parameters mail_params = mail.createParameters();
      mail_params.set("type", "oneshot");
      mail.getFunctionValue(mail_params);

      if (log.isDebugEnabled()) {
        log.debug("Message download ready send to: " + email);
      }
      send = true;
    } else {
      log.warn("Can not send message - no emailbuilder installed.");
    }

    return send;
  }

  protected Future<?> submit(final Node node, final Parameters parameters) {
    return ThreadPools.jobsExecutor.submit(
        new Callable() {
          public String call() {
            String result = "";
            Node source = null;
            try {
              if (log.isDebugEnabled()) {
                log.debug("media : " + node);
                log.debug("params: " + parameters);
              }
              URL url = new URL(parameters.get(URL));
              DownloadFunction.this.setDownloadUrl(node, parameters.get(URL));

              // get or create streamsource node
              source = CreateSourcesWithoutProcessFunction.getMediaSource(node, false);

              Downloader downloader = new Downloader();
              downloader.setUrl(url);
              downloader.setNode(source);
              log.info("Now calling: " + downloader);
              result = downloader.download();

              // download is ready
              DownloadFunction.this.setDownloadStatus(node, "ok");
              source =
                  CreateSourcesWithoutProcessFunction.getMediaSource(
                      node, true); // should force 'reload' of node
              source.commit();

              // send mail?
              String email = parameters.get(EMAIL);
              if (email != null && !"".equals(email)) {
                HttpServletRequest req = parameters.get(Parameter.REQUEST);
                sendMail(req, node, email);
              }

              log.info("Result: " + result + ", calling transcoders for #" + source.getNumber());
              source.getFunctionValue(
                  "triggerCaches",
                  new Parameters(org.mmbase.streams.CreateCachesFunction.PARAMETERS)
                      .set("all", true));

            } catch (IllegalArgumentException iae) {
              log.error(iae.getMessage(), iae);
              DownloadFunction.this.setDownloadStatus(node, "NONHTTP " + iae.getMessage());
            } catch (MalformedURLException ue) {
              log.error(ue.getMessage(), ue);
              DownloadFunction.this.setDownloadStatus(node, "BADURL " + ue.getMessage());
            } catch (IOException ioe) {
              log.error(ioe.getMessage(), ioe);
              DownloadFunction.this.setDownloadStatus(node, "IOERROR " + ioe.getMessage());
            } catch (Throwable t) {
              log.error(t.getMessage(), t);
              DownloadFunction.this.setDownloadStatus(node, "UNEXPECTED " + t.getMessage());
            } finally {
              DownloadFunction.this.runningJobs.remove(node.getNumber());
              log.info("Running jobs: " + DownloadFunction.this.runningJobs);
            }
            return result;
          }
        });
  }

  @Override
  public String getFunctionValue(final Node node, final Parameters parameters) {
    if (log.isDebugEnabled()) {
      log.debug("node #" + node.getNumber());
      log.debug("params: " + parameters);
    }
    String status = getDownloadStatus(node);

    int timeout = 5;
    if (parameters.get(TIMEOUT) != null) {
      timeout = parameters.get(TIMEOUT);
    }

    if (status == null) {
      Action action = ActionRepository.getInstance().get("streams", "download_media");
      if (action == null) {
        throw new IllegalStateException("Action could not be found");
      }
      if (node.getCloud().may(action, null)) {
        synchronized (runningJobs) {
          Future<?> future = runningJobs.get(node.getNumber());
          if (future == null) {
            setDownloadStatus(node, "busy: " + System.currentTimeMillis());
            future = submit(node, parameters);

            ThreadPools.identify(
                future,
                DownloadFunction.class.getName()
                    + " downloading... for #"
                    + node.getNumber()
                    + " - status: "
                    + getDownloadStatus(node));
            String fname = ThreadPools.getString(future);
            log.info("Future name: " + fname);
            try {
              status = (String) future.get(timeout, TimeUnit.SECONDS);
              log.info("status: " + status);
            } catch (TimeoutException te) {
              status = ThreadPools.getString(future);
              log.info("TimeoutException: " + status);
            } catch (Exception e) {
              log.error(e);
            }

          } else {
            status = ThreadPools.getString(future);
          }
        }
        log.info("status: " + status);
        return status;
      } else {
        throw new org.mmbase.security.SecurityException("Not allowed");
      }
    }
    return status;
  }
}
예제 #20
0
/**
 * The DataType of the field can also itself specify how the input widgets must look like. This
 * TypeHandler wraps this {@link org.mmbase.datatypes.handlers.Handler} object into a {@link
 * TypeHandler}.
 *
 * <p>Actually, as soon as all TypeHandler implementations are migrated to Handlers, this can become
 * the only way to do it.
 *
 * @author Michiel Meeuwisssen
 * @since MMBase-1.9.1
 * @version $Id$
 */
public class DataTypeHandler implements TypeHandler {

  private static final Logger log = Logging.getLoggerInstance(DataTypeHandler.class);

  protected final Handler<String> handler;
  protected final Request request;

  public DataTypeHandler(Handler<String> h, final FieldInfoTag tag) {
    handler = h;
    request =
        new Request() {
          {
            setProperty(HtmlHandler.SESSIONNAME, tag.getSessionName());
            try {
              javax.servlet.jsp.PageContext pc = tag.getContextTag().getPageContext();
              setProperty(
                  Parameter.REQUEST, (javax.servlet.http.HttpServletRequest) pc.getRequest());
              setProperty(
                  Parameter.RESPONSE, (javax.servlet.http.HttpServletResponse) pc.getResponse());
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public Cloud getCloud() {
            try {
              return tag.getCloudVar();
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public java.util.Locale getLocale() {
            try {
              return tag.getLocale();
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public void invalidate() {
            try {
              FormTag form = tag.getFormTag(false, null);
              if (form != null) {
                form.setValid(false);
              }
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public boolean isValid() {
            try {
              FormTag form = tag.getFormTag(false, null);
              if (form != null) {
                return form.isValid();
              } else {
                return true;
              }
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          protected String prefix(String s) throws JspTagException {
            return tag.getPrefix() + "_" + s;
          }

          @Override
          public Object getValue(Field field) {
            try {
              Object found =
                  tag.getContextProvider()
                      .getContextContainer()
                      .find(tag.getPageContext(), prefix(field.getName()));
              log.debug("found fv " + found);
              return found;
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public Object getValue(Field field, String part) {
            try {
              Object found =
                  tag.getContextProvider()
                      .getContextContainer()
                      .find(tag.getPageContext(), prefix(field.getName()) + "_" + part);
              log.debug("found fv " + found);
              return found;
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public String getName(Field field) {
            try {
              return prefix(field.getName());
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }

          @Override
          public <C> C setProperty(Parameter<C> name, C value) {
            C prev = getProperty(name);
            tag.getPageContext().setAttribute(name.getName(), value);
            return prev;
          }

          @Override
          public <C> C getProperty(Parameter<C> name) {
            return (C) tag.getPageContext().getAttribute(name.getName());
          }

          @Override
          public boolean isPost() {
            try {
              return "POST"
                  .equals(
                      ((javax.servlet.http.HttpServletRequest)
                              tag.getContextTag().getPageContext().getRequest())
                          .getMethod());
            } catch (JspTagException te) {
              throw new RuntimeException(te);
            }
          }
        };
  }

  @Override
  public String htmlInput(Node node, Field field, boolean search) throws JspTagException {
    return handler.input(request, node, field, search);
  }

  @Override
  public String htmlInputId(Node node, Field field) throws JspTagException {
    return handler.id(request, field);
  }

  @Override
  public String checkHtmlInput(Node node, Field field, boolean errors) throws JspTagException {
    return handler.check(request, node, field, errors);
  }

  @Override
  public boolean useHtmlInput(Node node, Field field) throws JspTagException {
    return handler.set(request, node, field);
  }

  @Override
  public String whereHtmlInput(Field field) throws JspTagException {
    throw new UnsupportedOperationException();
  }

  protected final String findString(Field field) throws JspTagException {
    String search = org.mmbase.util.Casting.toString(request.getValue(field));
    if (search == null || "".equals(search)) {
      return null;
    }
    return search;
  }

  @Override
  public void paramHtmlInput(ParamHandler handler, Field field) throws JspTagException {
    handler.addParameter(request.getName(field), findString(field));
  }

  @Override
  public Constraint whereHtmlInput(Field field, Query query) throws JspTagException {
    return handler.search(request, field, query);
  }

  @Override
  public void init() {}
}
예제 #21
0
파일: TypeRel.java 프로젝트: mihxil/mmbase
/**
 * TypeRel defines the allowed relations between two object types. Every relations also specifies a
 * 'role', which is a reference to the RelDef table.
 *
 * <p>Relations do principally have a 'source' and a 'destination' object type, but most functions
 * of this class do ignore this distinction.
 *
 * <p>TypeRel is a 'core' MMBase builder. You can get a reference to it via the MMBase instance.
 *
 * @author Daniel Ockeloen
 * @author Pierre van Rooden
 * @author Michiel Meeuwissen
 * @version $Id$
 * @see RelDef
 * @see InsRel
 * @see org.mmbase.module.core.MMBase
 */
public class TypeRel extends MMObjectBuilder implements SystemEventListener {

  private static final Logger log = Logging.getLoggerInstance(TypeRel.class);

  /** Constant for {@link #contains}: return only typerels that exactly match. */
  public static final int STRICT = 0;

  /**
   * Constant for {@link #contains}: return typerels where source/destination match with a builder
   * or its descendants
   */
  public static final int INCLUDE_DESCENDANTS = 1;

  /**
   * Constant for {@link #contains}: return typerels where source/destination match with a builder
   * or its parents
   */
  public static final int INCLUDE_PARENTS = 2;

  /**
   * Constant for {@link #contains}: return typerels where source/destination match with a builder,
   * its descendants, or its parents
   */
  public static final int INCLUDE_PARENTS_AND_DESCENDANTS = 3;

  /**
   * TypeRel should contain only a limited amount of nodes, so we can simply cache them all, and
   * avoid all further querying.
   */
  protected TypeRelSet typeRelNodes; // for searching destinations

  protected TypeRelSet parentTypeRelNodes; // for caching typerels for 'parent'

  // builders

  public InverseTypeRelSet inverseTypeRelNodes; // for searching sources

  private int defaultRelationStepDirection = RelationStep.DIRECTIONS_BOTH;

  @Override
  public boolean init() {
    if (oType != -1) return true;
    super.init();
    createIfNotExists();
    // during init not yet all builder are available so inheritance is not
    // yet possible
    // This means that calls to getAllowedRelations do not consider
    // inheritance during initializion of MMBase.
    // This occurs e.g. in one of the Community-builders.
    readCache(false);
    EventManager.getInstance().addEventListener(this);
    return true;
  }

  @Override
  public void notify(SystemEvent se) {
    if (se instanceof SystemEvent.ServletContext) {
      ServletContext sx = ((SystemEvent.ServletContext) se).getServletContext();
      String def = sx.getInitParameter("mmbase.defaultRelationStepDirection");
      if (def != null && def.length() > 0) {
        defaultRelationStepDirection = org.mmbase.bridge.util.Queries.getRelationStepDirection(def);
        log.info("Found default relation step direction " + def);
      }
    }
  }

  @Override
  public int getWeight() {
    return 0;
  }

  /**
   * The TypeRel cache contains all TypeRels MMObjectNodes. Called after init by MMBase, and when
   * something changes.
   *
   * @since MMBase-1.6.2
   */
  public void readCache() {
    readCache(true);
  }

  /** @since MMBase-1.6.2 */
  private void readCache(boolean buildersInitialized) {
    log.debug("Reading in typerels");
    typeRelNodes = new TypeRelSet();
    parentTypeRelNodes = new TypeRelSet();
    inverseTypeRelNodes = new InverseTypeRelSet();

    TypeDef typeDef = mmb.getTypeDef();
    typeDef.init();
    // Find all typerel nodes
    List<MMObjectNode> alltypes = getNodes();
    for (MMObjectNode typerel : alltypes) {
      addCacheEntry(typerel, buildersInitialized);
    }
    log.debug(
        "Done reading typerel cache "
            + (buildersInitialized ? "(considered inheritance)" : "")
            + ": "
            + typeRelNodes);
  }

  /**
   * Addes one typerel cache entries, plus inherited relations (if builder are initialized)
   *
   * @return A Set with the added entries, which can be used for logging or so, or can be
   *     disregarded
   * @since MMBase-1.6.2
   */
  protected TypeRelSet addCacheEntry(
      final MMObjectNode typeRel, final boolean buildersInitialized) {

    if (typeRel == null) {
      throw new IllegalArgumentException("typeRel cannot be null");
    }

    final TypeRelSet added =
        new TypeRelSet(); // store temporary, which will enable nice logging of what happened

    // Start to add the actual definition, this is then afterwards again,
    // except if one of the builders could not be found
    added.add(typeRel);

    if (mmb == null) {
      throw new IllegalStateException("mmb is null");
    }

    final RelDef reldef = mmb.getRelDef();
    if (reldef == null) {
      throw new IllegalStateException("No reldef found");
    }

    final MMObjectNode reldefNode = reldef.getNode(typeRel.getIntValue("rnumber"));
    if (reldefNode == null) {
      throw new RuntimeException(
          "Could not find reldef-node for rnumber= " + typeRel.getIntValue("rnumber"));
    }

    final boolean bidirectional = (!InsRel.usesdir) || (reldefNode.getIntValue("dir") > 1);

    INHERITANCE:
    if (buildersInitialized) { // handle inheritance, which is
      // not possible during
      // initialization of MMBase.

      final TypeDef typeDef = mmb.getTypeDef();

      final String sourceBuilderName = typeDef.getValue(typeRel.getIntValue("snumber"));
      final MMObjectBuilder sourceBuilder =
          sourceBuilderName != null ? mmb.getBuilder(sourceBuilderName) : null;

      final String destinationBuilderName = typeDef.getValue(typeRel.getIntValue("dnumber"));
      final MMObjectBuilder destinationBuilder =
          destinationBuilderName != null ? mmb.getBuilder(destinationBuilderName) : null;

      if (sourceBuilder == null) {
        if (destinationBuilder == null) {
          log.info(
              "Both source and destination of "
                  + typeRel
                  + " are not active builders. Cannot follow descendants.");
        } else {
          log.info(
              "The source of relation type "
                  + typeRel
                  + " is not an active builder. Cannot follow descendants.");
        }
        break INHERITANCE;
      }

      if (destinationBuilder == null) {
        log.warn(
            "The destination of relation type "
                + typeRel
                + " is not an active builder. Cannot follow descendants.");
        break INHERITANCE;
      }

      final int rnumber = typeRel.getIntValue("rnumber");

      final List<MMObjectBuilder> sources =
          new ArrayList<MMObjectBuilder>(sourceBuilder.getDescendants());
      sources.add(sourceBuilder);

      final List<MMObjectBuilder> destinations =
          new ArrayList<MMObjectBuilder>(destinationBuilder.getDescendants());
      destinations.add(destinationBuilder);

      for (MMObjectBuilder s : sources) {
        for (MMObjectBuilder d : destinations) {
          MMObjectNode vnode = new VirtualTypeRelNode(s.getNumber(), d.getNumber(), rnumber);
          added.add(vnode);
        }
      }

      // seek all parents and store typerels for them
      // this cache is used by contains(INCLUDE_PARENTS /
      // INCLUDE_PARENTS_AND_DESCENDANTS));
      MMObjectBuilder sourceParent = sourceBuilder;
      while (sourceParent != null) {
        MMObjectBuilder destinationParent = destinationBuilder;
        while (destinationParent != null) {
          MMObjectNode vnode =
              new VirtualTypeRelNode(
                  sourceParent.getNumber(), destinationParent.getNumber(), rnumber);
          parentTypeRelNodes.add(vnode);
          destinationParent = destinationParent.getParentBuilder();
        }
        sourceParent = sourceParent.getParentBuilder();
      }
      added.add(typeRel); // replaces the ones added in the 'inheritance'
      // loop (so now not any more Virtual)
    }

    for (MMObjectNode node : added) {
      if (!node.isVirtual()) {
        // make sure 'real' nodes replace virtual nodes. (real and virtual nodes are equal, so will
        // not be added to set otherwise)
        // This is especially essential whey you use STRICT in contains
        typeRelNodes.remove(node);
        if (bidirectional) inverseTypeRelNodes.remove(node);
      }
      typeRelNodes.add(node);
      if (bidirectional) inverseTypeRelNodes.add(node);
    }
    if (log.isDebugEnabled()) {
      log.debug("Added to typerelcache: " + added);
    }
    return added;
  }

  /**
   * Insert a new object (content provided) in the cloud, including an entry for the object alias
   * (if provided). This method indirectly calls {@link #preCommit}. If the typerel node specified
   * already exists (i.e. same snumber, dnumber,a nd rnumber fielfds), the typerel creation fails
   * and returns -1.
   *
   * @param owner The administrator creating the node
   * @param node The object to insert. The object need be of the same type as the current builder.
   * @return An <code>int</code> value which is the new object's unique number, -1 if the insert
   *     failed.
   */
  @Override
  public int insert(String owner, MMObjectNode node) {
    int snumber = node.getIntValue("snumber");
    int dnumber = node.getIntValue("dnumber");
    int rnumber = node.getIntValue("rnumber");
    if (contains(snumber, dnumber, rnumber, STRICT)) {
      log.error(
          "The typerel with snumber="
              + snumber
              + ", dnumber="
              + dnumber
              + ", rnumber="
              + rnumber
              + " already exists");
      throw new RuntimeException(
          "The typerel with snumber="
              + snumber
              + ", dnumber="
              + dnumber
              + ", rnumber="
              + rnumber
              + " already exists");
    }
    int res = super.insert(owner, node);
    return res;
  }

  /**
   * Remove a node from the cloud.
   *
   * @param node The node to remove.
   */
  @Override
  public void removeNode(MMObjectNode node) {
    super.removeNode(node);
  }

  /**
   * Retrieves all relations which are 'allowed' for a specified node, that is, where the node is
   * either allowed to be the source, or to be the destination (but where the corresponing relation
   * definition is bidirectional). The allowed relations are determined by the type of the node
   *
   * @param node The node to retrieve the allowed relations of.
   * @return An <code>Enumeration</code> of nodes containing the typerel relation data
   */
  public Enumeration<MMObjectNode> getAllowedRelations(MMObjectNode node) {
    return getAllowedRelations(node.getBuilder().getNumber());
  }

  public Enumeration<MMObjectNode> getAllowedRelations(int otype) {
    Set<MMObjectNode> res = getAllowedRelations(otype, 0, 0, RelationStep.DIRECTIONS_BOTH);
    return Collections.enumeration(res);
  }

  /**
   * Retrieves all relations which are 'allowed' between two specified nodes. No distinction between
   * source / destination.
   *
   * @param node1 The first objectnode
   * @param node2 The second objectnode
   * @return An <code>Enumeration</code> of nodes containing the typerel relation data
   */
  public Enumeration<MMObjectNode> getAllowedRelations(MMObjectNode node1, MMObjectNode node2) {
    return getAllowedRelations(node1.getOType(), node2.getOType());
  }

  /**
   * An enumeration of all allowed relations between two builders. No distinction is made between
   * source and destination.
   */
  public Enumeration<MMObjectNode> getAllowedRelations(int builder1, int builder2) {
    Set<MMObjectNode> res =
        getAllowedRelations(builder1, builder2, 0, RelationStep.DIRECTIONS_BOTH);
    return Collections.enumeration(res);
  }

  /**
   * A Set of all allowed relations of a certain role between two builders. No distinction between
   * source and destination.
   *
   * @since MMBase-1.6.2
   */
  public Set<MMObjectNode> getAllowedRelations(int builder1, int builder2, int role) {
    return getAllowedRelations(builder1, builder2, role, RelationStep.DIRECTIONS_BOTH);
  }

  /**
   * A Set of all allowed relations of a certain role between two builders. Distinction is made
   * between source and destination depending on passed directionality.
   *
   * @since MMBase-1.6.2
   */
  public Set<MMObjectNode> getAllowedRelations(
      int builder1, int builder2, int role, int directionality) {
    Set<MMObjectNode> res = new HashSet<MMObjectNode>();
    if (directionality != RelationStep.DIRECTIONS_SOURCE) {
      res.addAll(typeRelNodes.getBySourceDestinationRole(builder1, builder2, role));
    }
    if (directionality != RelationStep.DIRECTIONS_DESTINATION
        && (directionality != RelationStep.DIRECTIONS_EITHER || res.isEmpty())) {
      res.addAll(inverseTypeRelNodes.getByDestinationSourceRole(builder2, builder1, role));
    }
    return res;
  }

  /**
   * Retrieves all relations which are 'allowed' between two specified nodes.
   *
   * @param snum The first objectnode type (the source)
   * @param dnum The second objectnode type (the destination)
   * @return An <code>Enumeration</code> of nodes containing the reldef (not typerel!) sname field
   */
  protected Vector<String> getAllowedRelationsNames(int snum, int dnum) {
    Vector<String> results = new Vector<String>();
    for (Enumeration<MMObjectNode> e = getAllowedRelations(snum, dnum); e.hasMoreElements(); ) {
      MMObjectNode node = e.nextElement();
      int rnumber = node.getIntValue("rnumber");
      MMObjectNode snode = mmb.getRelDef().getNode(rnumber);
      results.addElement(snode.getStringValue("sname"));
    }
    return results;
  }

  /**
   * Retrieves the identifying number of the relation definition that is 'allowed' between two
   * specified node types. The results are dependent on there being only one type of relation
   * between two node types (not enforced, thus unpredictable). Makes use of a typeRelNodes.
   *
   * @param snum The first objectnode type (the source)
   * @param dnum The second objectnode type (the destination)
   * @return the number of the found relation, or -1 if either no relation was found, or more than
   *     one was found.
   */
  public int getAllowedRelationType(int snum, int dnum) {
    Set<MMObjectNode> set =
        new HashSet<MMObjectNode>(typeRelNodes.getBySourceDestination(snum, dnum));
    set.addAll(inverseTypeRelNodes.getByDestinationSource(dnum, snum));

    if (set.size() != 1) {
      return -1;
    } else {
      MMObjectNode n = set.iterator().next();
      return n.getIntValue("rnumber");
    }
  }

  /**
   * Returns the display string for this node It returns a commbination of objecttypes and rolename
   * : "source->destination (role)".
   *
   * @param node Node from which to retrieve the data
   * @return A <code>String</code> describing the content of the node
   */
  @Override
  public String getGUIIndicator(MMObjectNode node) {
    try {
      String source = mmb.getTypeDef().getValue(node.getIntValue("snumber"));
      String destination = mmb.getTypeDef().getValue(node.getIntValue("dnumber"));
      MMObjectNode role = mmb.getRelDef().getNode(node.getIntValue("rnumber"));
      return source
          + "->"
          + destination
          + " ("
          + (role != null ? role.getGUIIndicator() : "???")
          + ")";
    } catch (Exception e) {
      log.warn(e);
    }
    return null;
  }

  /**
   * Returns the display string for a specified field. Returns, for snumber and dnumber, the name of
   * the objecttype they represent, and for rnumber the display (GUI) string for the indicated
   * relation definition.
   *
   * @param field The name of the field to retrieve
   * @param node Node from which to retrieve the data
   * @return A <code>String</code> describing the content of the field
   */
  @Override
  public String getGUIIndicator(String field, MMObjectNode node) {
    try {
      if (field.equals("snumber")) {
        return mmb.getTypeDef().getValue(node.getIntValue("snumber"));
      } else if (field.equals("dnumber")) {
        return mmb.getTypeDef().getValue(node.getIntValue("dnumber"));
      } else if (field.equals("rnumber")) {
        MMObjectNode reldef = mmb.getRelDef().getNode(node.getIntValue("rnumber"));
        return (reldef != null ? reldef.getGUIIndicator() : "???");
      }
    } catch (Exception e) {
    }
    return null;
  }

  /**
   * Processes the BUILDER-typerel-ALLOWEDRELATIONSNAMES in the LIST command, and (possibly) returns
   * a Vector containing requested data (based on the content of TYPE and NODE, which can be
   * retrieved through tagger).
   *
   * @javadoc parameters
   */
  @Override
  public Vector<String> getList(PageInfo sp, StringTagger tagger, StringTokenizer tok) {
    if (tok.hasMoreTokens()) {
      String cmd = tok.nextToken(); // Retrieving command.
      if (cmd.equals("ALLOWEDRELATIONSNAMES")) {
        try {
          String tmp = tagger.Value("TYPE");
          int number1 = mmb.getTypeDef().getIntValue(tmp);
          tmp = tagger.Value("NODE");
          int number2 = Integer.parseInt(tmp);
          MMObjectNode node = getNode(number2);
          return getAllowedRelationsNames(number1, node.getOType());
        } catch (Exception e) {
          log.error(e);
        }
      }
    }
    return null;
  }

  /**
   * Tests if a specific relation type is defined.
   *
   * <p>Note that this routine returns false both when a snumber/dnumber are swapped, and when a
   * typecombo does not exist - it is not possible to derive whether one or the other has occurred.
   *
   * @deprecated use {@link #contains}instead
   * @param n1 The source type number.
   * @param n2 The destination type number.
   * @param r The relation definition (role) number, or -1 if the role does not matter
   * @return <code>true</code> when the relation exists, false otherwise.
   */
  public boolean reldefCorrect(int n1, int n2, int r) {
    return contains(n1, n2, r);
  }

  /**
   * Tests if a specific relation type is defined. The method also returns true if the typerel
   * occurs as a virtual (derived) node.
   *
   * <p>Note that this routine returns false both when a snumber/dnumber are swapped, and when a
   * typecombo does not exist - it is not possible to derive whether one or the other has occurred.
   *
   * <p>
   *
   * @param n1 The source type number.
   * @param n2 The destination type number.
   * @param r The relation definition (role) number, or -1 if the role does not matter
   * @return <code>true</code> when the relation exists, false otherwise.
   * @since MMBase-1.6.2
   */
  public boolean contains(int n1, int n2, int r) {
    return contains(n1, n2, r, INCLUDE_DESCENDANTS);
  }

  /**
   * Tests if a specific relation type is defined.
   *
   * <p>Note that this routine returns false both when a snumber/dnumber are swapped, and when a
   * typecombo does not exist - it is not possible to derive whether one or the other has occurred.
   *
   * <p>
   *
   * @param n1 The source type number.
   * @param n2 The destination type number.
   * @param r The relation definition (role) number, or -1 if the role does not matter r can only be
   *     -1 if virtual is <code>true</code>
   * @param restriction if {@link #STRICT}, contains only returns true if the typerel occurs as-is
   *     in the database. if {@link #INCLUDE_DESCENDANTS}, contains returns true if the typerel
   *     occurs as a virtual (derived) node, where source or destination may also be descendants of
   *     the specified type. if {@link #INCLUDE_PARENTS}, contains returns true if the typerel
   *     occurs as a virtual (derived) node, where source or destination may also be parents of the
   *     specified type. if {@link #INCLUDE_PARENTS_AND_DESCENDANTS}, contains returns true if the
   *     typerel occurs as a virtual (derived) node, where source or destination may also be
   *     descendants or parents of the specified type.
   * @return <code>true</code> when the relation exists, false otherwise.
   * @since MMBase-1.6.2
   */
  public boolean contains(int n1, int n2, int r, int restriction) {
    switch (restriction) {
      case INCLUDE_DESCENDANTS:
        return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r));
      case INCLUDE_PARENTS:
        return parentTypeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r));
      case INCLUDE_PARENTS_AND_DESCENDANTS:
        return typeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r))
            || parentTypeRelNodes.contains(new VirtualTypeRelNode(n1, n2, r));
      case STRICT:
        SortedSet<MMObjectNode> existingNodes = typeRelNodes.getBySourceDestinationRole(n1, n2, r);
        return (existingNodes.size() > 0 && !existingNodes.first().isVirtual());
      default:
        log.error("Unknown restriction " + restriction);
        return false;
    }
  }

  /**
   * Watch for changes on relation types and adjust our memory table accordingly
   *
   * @todo Should update artCache en relDefCorrectCache as wel
   */
  /*
   * (non-Javadoc)
   * @see org.mmbase.module.core.MMObjectBuilder#notify(org.mmbase.core.event.NodeEvent)
   */
  @Override
  public void notify(NodeEvent event) {
    if (log.isDebugEnabled()) {
      log.debug(
          "Changed "
              + event.getMachine()
              + " "
              + event.getNodeNumber()
              + " "
              + event.getBuilderName()
              + " "
              + NodeEvent.newTypeToOldType(event.getType()));
    }
    if (tableName.equals(event.getBuilderName())) {
      if (event.getType() == Event.TYPE_NEW) {
        MMObjectNode typeRelNode = getNode(event.getNodeNumber());
        if (typeRelNode != null) {
          Set<MMObjectNode> newTypeRels = addCacheEntry(typeRelNode, true);
          log.service("Added to typerelcache: " + newTypeRels);
        } else {
          log.warn("Could not found typerel node with number " + event.getNodeNumber());
        }

      } else {
        // something else changed in a typerel node? reread the complete typeRelNodes Set
        log.service(
            "Received '" + event + "' which is about typrels. Now re-reading the entire cache");
        readCache();
      }
      // also, clear all query-caches, because result may change by this. See MMB-348
      for (Cache qc : CacheManager.getMap().values()) {
        if (qc instanceof QueryResultCache) {
          qc.clear();
        }
      }
    }
    super.notify(event);
  }

  /**
   * Optimize as relation step by considering restrictions of TypeRel. TypeRel defines which type of
   * relations may be created, ergo can exist.
   *
   * @since MMBase-1.7
   */
  public boolean optimizeRelationStep(
      BasicRelationStep relationStep,
      int sourceType,
      int destinationType,
      int roleInt,
      int searchDir) {
    // Determine in what direction(s) this relation can be followed:

    // Check directionality is requested and supported.
    if (searchDir != RelationStep.DIRECTIONS_ALL && InsRel.usesdir) {
      relationStep.setCheckedDirectionality(true);
    }

    // this is a bit confusing, can the simple cases like explicit 'source'
    // or 'destination' not be handled first?

    boolean sourceToDestination =
        searchDir != RelationStep.DIRECTIONS_SOURCE
            && contains(sourceType, destinationType, roleInt, INCLUDE_PARENTS_AND_DESCENDANTS);
    boolean destinationToSource =
        searchDir != RelationStep.DIRECTIONS_DESTINATION
            && contains(destinationType, sourceType, roleInt, INCLUDE_PARENTS_AND_DESCENDANTS);

    if (destinationToSource
        && sourceToDestination
        && (searchDir == RelationStep.DIRECTIONS_EITHER)) {
      // support old
      destinationToSource = false;
    }

    if (destinationToSource) {
      // there is a typed relation from destination to src
      if (sourceToDestination) {
        // there is ALSO a typed relation from src to destination - make
        // a more complex query
        // http://www.mmbase.org/jira/browse/MMB-1653

        relationStep.setDirectionality(defaultRelationStepDirection);
      } else {
        // there is ONLY a typed relation from destination to src -
        // optimized query
        relationStep.setDirectionality(RelationStep.DIRECTIONS_SOURCE);
      }
    } else {
      if (sourceToDestination) {
        // there is no typed relation from destination to src (assume a
        // relation between src and destination) - optimized query
        relationStep.setDirectionality(RelationStep.DIRECTIONS_DESTINATION);
      } else {
        // no results possible, do something any way
        if (searchDir == RelationStep.DIRECTIONS_SOURCE) {
          // explicitely asked for source, it would be silly to try destination now
          relationStep.setDirectionality(RelationStep.DIRECTIONS_SOURCE);
        } else {
          // the 'normal' way
          relationStep.setDirectionality(RelationStep.DIRECTIONS_DESTINATION);
        }
        return false;
      }
    }
    return true;
  }

  /**
   * Implements equals for a typerel node. Two nodes are equal if the snumber and dnumber fields are
   * the same, and the rnumber fields are the same, or one of these is '-1' (don't care).
   *
   * @since MMBase-1.6.2
   */
  @Override
  public boolean equals(MMObjectNode o1, MMObjectNode o2) {
    if (o2.getBuilder() instanceof TypeRel) {
      int r1 = o1.getIntValue("rnumber");
      int r2 = o2.getIntValue("rnumber");
      return o1.getIntValue("snumber") == o2.getIntValue("snumber")
          && o1.getIntValue("dnumber") == o2.getIntValue("dnumber")
          && (r1 == -1 || r2 == -1 || r1 == r2);
    }
    return false;
  }

  /**
   * Implements for MMObjectNode
   *
   * @since MMBase-1.6.2
   */
  @Override
  public int hashCode(MMObjectNode o) {
    int result = 0;
    result = HashCodeUtil.hashCode(result, o.getIntValue("snumber"));
    result = HashCodeUtil.hashCode(result, o.getIntValue("dnumber"));
    result = HashCodeUtil.hashCode(result, o.getIntValue("rnumber"));
    return result;
  }

  @Override
  public String toString(MMObjectNode n) {
    try {
      int snumber = n.getIntValue("snumber");
      int dnumber = n.getIntValue("dnumber");
      int rnumber = n.getIntValue("rnumber");

      String sourceName = mmb.getTypeDef().getValue(snumber);
      String destName = mmb.getTypeDef().getValue(dnumber);

      if (sourceName == null) {
        sourceName = "unknown builder '" + snumber + "'";
      }
      if (destName == null) {
        destName = "unknown builder '" + dnumber + "'";
      }

      // unfilled should only happen during creation of the node.
      String source = snumber > -1 ? (sourceName + "(" + snumber + ")") : "[unfilled]";
      String destination = dnumber > -1 ? (destName + "(" + dnumber + ")") : "[unfilled]";
      MMObjectNode role = rnumber > -1 ? mmb.getRelDef().getNode(rnumber) : null;
      return source
          + "->"
          + destination
          + " ("
          + (role != null ? role.getStringValue("sname") : "???")
          + ") "
          + (isVirtual() ? "(virtual)" : "");
    } catch (Exception e) {
      log.warn(e);
    }
    return "typerel-node";
  }

  /**
   * Of course, virtual typerel nodes need a virtual typerel builder. Well 'of course', the reason
   * is not quite obvious to me, it has to do with the bridge/temporarynodemanager which sometimes
   * needs to know it.
   *
   * @since MMBase-1.6.2
   */
  static class VirtualTypeRel extends TypeRel {
    static VirtualTypeRel virtualTypeRel = null;

    VirtualTypeRel(TypeRel t) {
      mmb = t.getMMBase();
      CoreField field = Fields.createField("snumber", Field.TYPE_NODE, Field.STATE_VIRTUAL, null);
      field.finish();
      addField(field);
      field = Fields.createField("dnumber", Field.TYPE_NODE, Field.STATE_VIRTUAL, null);
      field.finish();
      addField(field);
      field = Fields.createField("rnumber", Field.TYPE_NODE, Field.STATE_VIRTUAL, null);
      field.finish();
      addField(field);
      tableName = "virtual_typerel";
      virtual = true;
    }

    static VirtualTypeRel getVirtualTypeRel(TypeRel t) {
      if (virtualTypeRel == null) virtualTypeRel = new VirtualTypeRel(t);
      return virtualTypeRel;
    }
  }

  /**
   * A TypeRelSet is a Set of typerel nodes. The TypeRel builder maintains such a Set of all typerel
   * nodes for quick reference. TypeRelSets are also instantiated when doing queries on TypeRel like
   * getAllowedRelations(MMObjectBuilder) etc.
   *
   * @since MMBase-1.6.2
   */
  protected class TypeRelSet extends TreeSet<MMObjectNode> {
    protected TypeRelSet() {
      super(
          new Comparator<MMObjectNode>() {
            // sorted by source, destination, role
            @Override
            public int compare(MMObjectNode n1, MMObjectNode n2) {
              {
                int i1 = n1.getIntValue("snumber");
                int i2 = n2.getIntValue("snumber");
                if (i1 != i2) return i1 - i2;
              }
              {
                int i1 = n1.getIntValue("dnumber");
                int i2 = n2.getIntValue("dnumber");
                if (i1 != i2) return i1 - i2;
              }
              {
                int i1 = n1.getIntValue("rnumber");
                int i2 = n2.getIntValue("rnumber");
                if (i1 > 0 && i2 > 0) return i1 - i2;
              }

              return 0;
            }
          });
    }

    // make sure only MMObjectNode's are added
    @Override
    public boolean add(MMObjectNode node) {
      return super.add(node);
    }

    // find some subsets:
    SortedSet<MMObjectNode> getBySource(MMObjectBuilder source) {
      return getBySourceDestinationRole(source.getNumber(), 0, 0);
    }

    SortedSet<MMObjectNode> getBySource(int source) {
      return getBySourceDestinationRole(source, 0, 0);
    }

    SortedSet<MMObjectNode> getBySourceDestination(
        MMObjectBuilder source, MMObjectBuilder destination) {
      return getBySourceDestinationRole(source.getNumber(), destination.getNumber(), 0);
    }

    SortedSet<MMObjectNode> getBySourceDestination(int source, int destination) {
      return getBySourceDestinationRole(source, destination, 0);
    }

    SortedSet<MMObjectNode> getBySourceDestinationRole(int source, int destination, int role) {
      // determine minimum value - corrects in case '-1' (common MMBase value for N.A.) is passed
      int roleMin = role <= 0 ? 0 : role;
      int destinationMin = destination <= 0 ? 0 : destination;
      int sourceMin = source <= 0 ? 0 : source;

      // determine maximum value
      int roleMax = role <= 0 ? 0 : role + 1; // i.e. source, destination, role
      int destinationMax =
          role <= 0 ? destinationMin + 1 : destinationMin; // i.e. source, destination, 0
      int sourceMax =
          (destination <= 0 && role <= 0)
              ? (sourceMin <= 0 ? 0 : sourceMin + 1)
              : sourceMin; // i.e. source, 0, 0

      VirtualTypeRelNode fromTypeRelNode =
          new VirtualTypeRelNode(sourceMin, destinationMin, roleMin);
      VirtualTypeRelNode toTypeRelNode = new VirtualTypeRelNode(sourceMax, destinationMax, roleMax);

      if (log.isDebugEnabled()) {
        log.debug(" " + fromTypeRelNode + " " + toTypeRelNode);
      }
      SortedSet<MMObjectNode> allowed = subSet(fromTypeRelNode, toTypeRelNode);
      return Collections.unmodifiableSortedSet(allowed);
    }
  }

  /**
   * An InverseTypeRelSet is a Set of typerel nodes. The TypeRel builder maintains such a Set of all
   * typerel nodes for quick reference.
   *
   * @since MMBase-1.6.2
   */
  protected class InverseTypeRelSet extends TreeSet<MMObjectNode> {

    protected InverseTypeRelSet() {
      super(
          new Comparator<MMObjectNode>() {
            // sorted by destination, source, role
            @Override
            public int compare(MMObjectNode n1, MMObjectNode n2) {
              int i1 = n1.getIntValue("dnumber");
              int i2 = n2.getIntValue("dnumber");
              if (i1 != i2) return i1 - i2;

              i1 = n1.getIntValue("snumber");
              i2 = n2.getIntValue("snumber");
              if (i1 != i2) return i1 - i2;

              i1 = n1.getIntValue("rnumber");
              i2 = n2.getIntValue("rnumber");
              if (i1 != -1 && i2 != -1 && i1 != i2) return i1 - i2;
              return 0;
            }
          });
    }

    // make sure only MMObjectNode's are added
    @Override
    public boolean add(MMObjectNode object) {
      return super.add(object);
    }

    SortedSet<MMObjectNode> getByDestination(MMObjectBuilder destination) {
      return getByDestinationSourceRole(0, destination.getNumber(), 0);
    }

    SortedSet<MMObjectNode> getByDestination(int destination) {
      return getByDestinationSourceRole(0, destination, 0);
    }

    SortedSet<MMObjectNode> getByDestinationSource(
        MMObjectBuilder source, MMObjectBuilder destination) {
      return getByDestinationSourceRole(source.getNumber(), destination.getNumber(), 0);
    }

    SortedSet<MMObjectNode> getByDestinationSource(int source, int destination) {
      return getByDestinationSourceRole(source, destination, 0);
    }

    SortedSet<MMObjectNode> getByDestinationSourceRole(int source, int destination, int role) {
      // determine minimum value - corrects in case '-1' (common MMBase value for N.A.) is passed
      int roleMin = role <= 0 ? 0 : role;
      int sourceMin = source <= 0 ? 0 : source;
      int destinationMin = destination <= 0 ? 0 : destination;

      // determine maximum value
      int roleMax = role <= 0 ? 0 : role + 1; // i.e. source, destination, role
      int sourceMax =
          role <= 0 ? (source <= 0 ? 0 : source + 1) : source; // i.e. source, destination, 0
      int destinationMax =
          (source <= 0 && role <= 0) ? destination + 1 : destination; // i.e. 0, destination, 0

      final VirtualTypeRelNode fromTypeRelNode =
          new VirtualTypeRelNode(sourceMin, destinationMin, roleMin);
      final VirtualTypeRelNode toTypeRelNode =
          new VirtualTypeRelNode(sourceMax, destinationMax, roleMax);

      final SortedSet allowed = subSet(fromTypeRelNode, toTypeRelNode);
      return Collections.unmodifiableSortedSet(allowed);
    }
  }

  /**
   * A VirtualTypeRelNode is a MMObjectNode which is added to the typerelset with extensions of the
   * actual builders specified. So these entries are not in the database.
   *
   * @since MMBase-1.6.2
   */
  protected class VirtualTypeRelNode extends VirtualNode {

    VirtualTypeRelNode(int snumber, int dnumber) { // only for use in lookups
      // We don't use this-constructor because some jvm get confused then
      super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this));
      setValue("snumber", snumber);
      setValue("dnumber", dnumber);
      setValue("rnumber", -1);
    }

    VirtualTypeRelNode(int snumber) { // only for use in lookups
      // We don't use this-constructor because some jvm get confused then
      super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this));
      setValue("snumber", snumber);
      setValue("dnumber", -1);
      setValue("rnumber", -1);
    }

    VirtualTypeRelNode(int snumber, int dnumber, int rnumber) {
      super(VirtualTypeRel.getVirtualTypeRel(TypeRel.this));
      setValue("snumber", snumber);
      setValue("dnumber", dnumber);
      setValue("rnumber", rnumber);
      values = Collections.unmodifiableMap(values); // make sure it is not changed any more!
    }

    @Override
    public String toString() {
      return "V:"
          + getValue("snumber")
          + "->"
          + getValue("dnumber")
          + "("
          + getValue("rnumber")
          + ")";
    }
  }
}
예제 #22
0
/** @author Daniel Ockeloen */
public class Signature {

  // logger
  private static Logger log = Logging.getLoggerInstance(Signature.class);

  private int id;
  private Poster parent;
  private String body;
  private String mode;
  private String encoding;

  public Signature(Poster parent, int id, String body, String mode, String encoding) {
    this.id = id;
    this.body = body;
    this.mode = mode;
    this.encoding = encoding;
    this.parent = parent;
  }

  public void setBody(String body) {
    if (!this.body.equals(body)) {
      this.body = body;
      save();
    }
  }

  public void setMode(String mode) {
    if (!this.mode.equals(mode)) {
      if (mode.equals("delete")) {
        delete();
      } else {
        this.mode = mode;
        save();
      }
    }
  }

  public void setEncoding(String encoding) {
    if (!this.encoding.equals(encoding)) {
      this.encoding = encoding;
      save();
    }
  }

  public String getBody() {
    return body;
  }

  public String getMode() {
    return mode;
  }

  public int getId() {
    return id;
  }

  public String getEncoding() {
    return encoding;
  }

  public boolean delete() {
    Node node = ForumManager.getCloud().getNode(id);
    if (node != null) {
      node.delete(true);
    }
    parent.deleteSignature(this);
    return true;
  }

  public boolean save() {
    Node node = ForumManager.getCloud().getNode(id);
    node.setValue("mode", mode);
    node.setValue("body", body);
    node.setValue("encoding", encoding);
    node.commit();
    return true;
  }
}