001/* 002 * (C) Copyright 2006-2007 Nuxeo SAS <http://nuxeo.com> and others 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Jean-Marc Orliaguet, Chalmers 011 * 012 * $Id$ 013 */ 014 015package org.nuxeo.theme.relations; 016 017import java.util.ArrayList; 018import java.util.Collection; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Random; 023 024import org.nuxeo.theme.Registrable; 025 026public final class RelationStorage implements Registrable { 027 028 private static final Map<Long, Relation> relationsMap = new HashMap<Long, Relation>(); 029 030 private static final Map<List<String>, List<Long>> relatesMap = new HashMap<List<String>, List<Long>>(); 031 032 private static final String[][] WILDCARDS_MONADIC = { { "" } }; 033 034 private static final String[][] WILDCARDS_DYADIC = { { "", "" }, { "*", "" }, { "", "*" } }; 035 036 private static final String[][] WILDCARDS_TRIADIC = { { "", "", "" }, { "*", "", "" }, { "", "*", "" }, 037 { "", "", "*" }, { "*", "*", "" }, { "", "*", "*" }, { "*", "", "*" } }; 038 039 public synchronized void add(Relation relation) { 040 Long key = findFreeKey(); 041 relationsMap.put(key, relation); 042 index(key, relation); 043 } 044 045 public synchronized void remove(Relation relation) { 046 List<String> indexString = computeIndexString(relation.getRelates()); 047 for (Long id : relatesMap.get(indexString)) { 048 relationsMap.remove(id); 049 } 050 relatesMap.remove(indexString); 051 } 052 053 public Collection<Relation> search(Predicate predicate, List<Relate> relates) { 054 List<Relation> relations = new ArrayList<Relation>(); 055 List<String> indexString = computeIndexString(relates); 056 if (!relatesMap.containsKey(indexString)) { 057 return relations; 058 } 059 for (Long id : relatesMap.get(indexString)) { 060 Relation relation = relationsMap.get(id); 061 if (relation == null) { 062 continue; 063 } 064 if (!relation.hasPredicate(predicate)) { 065 continue; 066 } 067 relations.add(relationsMap.get(id)); 068 } 069 return relations; 070 } 071 072 public Collection<Relation> search(Predicate predicate, Relate first) { 073 List<Relate> relates = new ArrayList<Relate>(); 074 relates.add(first); 075 return search(predicate, relates); 076 } 077 078 public Collection<Relation> search(Predicate predicate, Relate first, Relate second) { 079 List<Relate> relates = new ArrayList<Relate>(); 080 relates.add(first); 081 relates.add(second); 082 return search(predicate, relates); 083 } 084 085 public Collection<Relation> search(Predicate predicate, Relate first, Relate second, Relate third) { 086 List<Relate> relates = new ArrayList<Relate>(); 087 relates.add(first); 088 relates.add(second); 089 relates.add(third); 090 return search(predicate, relates); 091 } 092 093 public Collection<Relation> list() { 094 return relationsMap.values(); 095 } 096 097 public synchronized void clear() { 098 relationsMap.clear(); 099 relatesMap.clear(); 100 } 101 102 private synchronized Long findFreeKey() { 103 Long key; 104 Random generator = new Random(); 105 do { 106 key = generator.nextLong(); 107 } while (relationsMap.containsKey(key)); 108 return key; 109 } 110 111 private synchronized void index(Long id, Relation relation) { 112 List<Relate> relates = relation.getRelates(); 113 String[][] wildcards = null; 114 115 Integer arity = relates.size(); 116 if (arity == 1) { 117 wildcards = WILDCARDS_MONADIC; 118 } else if (arity == 2) { 119 wildcards = WILDCARDS_DYADIC; 120 } else if (arity == 3) { 121 wildcards = WILDCARDS_TRIADIC; 122 } 123 assert wildcards != null; 124 125 for (String[] wildcard : wildcards) { 126 List<String> indexString = new ArrayList<String>(); 127 for (Integer j = 0; j < arity; j++) { 128 if (wildcard[j].equals("*")) { 129 indexString.add("*"); 130 } else { 131 indexString.add(relates.get(j).hash()); 132 } 133 } 134 List<Long> ids; 135 if (relatesMap.containsKey(indexString)) { 136 ids = relatesMap.get(indexString); 137 } else { 138 ids = new ArrayList<Long>(); 139 } 140 ids.add(id); 141 relatesMap.put(indexString, ids); 142 } 143 } 144 145 private List<String> computeIndexString(List<Relate> relates) { 146 List<String> indexString = new ArrayList<String>(); 147 for (Relate relate : relates) { 148 if (relate == null || relate.hash() == null) { 149 indexString.add("*"); 150 } else { 151 indexString.add(relate.hash()); 152 } 153 } 154 return indexString; 155 } 156 157}