001/* 002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Jean-Marc Orliaguet, Chalmers 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.theme.relations; 023 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029import java.util.Random; 030 031import org.nuxeo.theme.Registrable; 032 033public final class RelationStorage implements Registrable { 034 035 private static final Map<Long, Relation> relationsMap = new HashMap<Long, Relation>(); 036 037 private static final Map<List<String>, List<Long>> relatesMap = new HashMap<List<String>, List<Long>>(); 038 039 private static final String[][] WILDCARDS_MONADIC = { { "" } }; 040 041 private static final String[][] WILDCARDS_DYADIC = { { "", "" }, { "*", "" }, { "", "*" } }; 042 043 private static final String[][] WILDCARDS_TRIADIC = { { "", "", "" }, { "*", "", "" }, { "", "*", "" }, 044 { "", "", "*" }, { "*", "*", "" }, { "", "*", "*" }, { "*", "", "*" } }; 045 046 public synchronized void add(Relation relation) { 047 Long key = findFreeKey(); 048 relationsMap.put(key, relation); 049 index(key, relation); 050 } 051 052 public synchronized void remove(Relation relation) { 053 List<String> indexString = computeIndexString(relation.getRelates()); 054 for (Long id : relatesMap.get(indexString)) { 055 relationsMap.remove(id); 056 } 057 relatesMap.remove(indexString); 058 } 059 060 public Collection<Relation> search(Predicate predicate, List<Relate> relates) { 061 List<Relation> relations = new ArrayList<Relation>(); 062 List<String> indexString = computeIndexString(relates); 063 if (!relatesMap.containsKey(indexString)) { 064 return relations; 065 } 066 for (Long id : relatesMap.get(indexString)) { 067 Relation relation = relationsMap.get(id); 068 if (relation == null) { 069 continue; 070 } 071 if (!relation.hasPredicate(predicate)) { 072 continue; 073 } 074 relations.add(relationsMap.get(id)); 075 } 076 return relations; 077 } 078 079 public Collection<Relation> search(Predicate predicate, Relate first) { 080 List<Relate> relates = new ArrayList<Relate>(); 081 relates.add(first); 082 return search(predicate, relates); 083 } 084 085 public Collection<Relation> search(Predicate predicate, Relate first, Relate second) { 086 List<Relate> relates = new ArrayList<Relate>(); 087 relates.add(first); 088 relates.add(second); 089 return search(predicate, relates); 090 } 091 092 public Collection<Relation> search(Predicate predicate, Relate first, Relate second, Relate third) { 093 List<Relate> relates = new ArrayList<Relate>(); 094 relates.add(first); 095 relates.add(second); 096 relates.add(third); 097 return search(predicate, relates); 098 } 099 100 public Collection<Relation> list() { 101 return relationsMap.values(); 102 } 103 104 public synchronized void clear() { 105 relationsMap.clear(); 106 relatesMap.clear(); 107 } 108 109 private synchronized Long findFreeKey() { 110 Long key; 111 Random generator = new Random(); 112 do { 113 key = generator.nextLong(); 114 } while (relationsMap.containsKey(key)); 115 return key; 116 } 117 118 private synchronized void index(Long id, Relation relation) { 119 List<Relate> relates = relation.getRelates(); 120 String[][] wildcards = null; 121 122 Integer arity = relates.size(); 123 if (arity == 1) { 124 wildcards = WILDCARDS_MONADIC; 125 } else if (arity == 2) { 126 wildcards = WILDCARDS_DYADIC; 127 } else if (arity == 3) { 128 wildcards = WILDCARDS_TRIADIC; 129 } 130 assert wildcards != null; 131 132 for (String[] wildcard : wildcards) { 133 List<String> indexString = new ArrayList<String>(); 134 for (Integer j = 0; j < arity; j++) { 135 if (wildcard[j].equals("*")) { 136 indexString.add("*"); 137 } else { 138 indexString.add(relates.get(j).hash()); 139 } 140 } 141 List<Long> ids; 142 if (relatesMap.containsKey(indexString)) { 143 ids = relatesMap.get(indexString); 144 } else { 145 ids = new ArrayList<Long>(); 146 } 147 ids.add(id); 148 relatesMap.put(indexString, ids); 149 } 150 } 151 152 private List<String> computeIndexString(List<Relate> relates) { 153 List<String> indexString = new ArrayList<String>(); 154 for (Relate relate : relates) { 155 if (relate == null || relate.hash() == null) { 156 indexString.add("*"); 157 } else { 158 indexString.add(relate.hash()); 159 } 160 } 161 return indexString; 162 } 163 164}