001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.acacia.client.entity; 029 030import org.opencms.acacia.shared.CmsEntity; 031import org.opencms.acacia.shared.CmsEntityAttribute; 032import org.opencms.acacia.shared.CmsType; 033import org.opencms.gwt.client.util.CmsDomUtil; 034import org.opencms.gwt.shared.CmsGwtConstants; 035import org.opencms.gwt.shared.CmsGwtLog; 036 037import java.util.ArrayList; 038import java.util.HashMap; 039import java.util.List; 040import java.util.Map; 041 042import com.google.gwt.core.client.JavaScriptObject; 043import com.google.gwt.dom.client.Document; 044import com.google.gwt.dom.client.Element; 045import com.google.gwt.dom.client.NodeList; 046 047/** 048 * The editor data back-end.<p> 049 */ 050public final class CmsEntityBackend implements I_CmsEntityBackend { 051 052 /** The instance. */ 053 private static CmsEntityBackend INSTANCE; 054 055 /** CmsEntity id counter. */ 056 private int m_count; 057 058 /** The registered entities. */ 059 private Map<String, CmsEntity> m_entities; 060 061 /** The registered types. */ 062 private Map<String, CmsType> m_types; 063 064 /** 065 * Constructor.<p> 066 */ 067 public CmsEntityBackend() { 068 069 m_entities = new HashMap<String, CmsEntity>(); 070 m_types = new HashMap<String, CmsType>(); 071 } 072 073 /** 074 * Method to create an entity object from a wrapped instance.<p> 075 * 076 * @param entityWrapper the wrappe entity 077 * 078 * @return the entity 079 */ 080 public static CmsEntity createFromNativeWrapper(JavaScriptObject entityWrapper) { 081 082 CmsEntity result = new CmsEntity(null, getEntityType(entityWrapper)); 083 String[] simpleAttr = getSimpleAttributeNames(entityWrapper); 084 for (int i = 0; i < simpleAttr.length; i++) { 085 String[] simpleAttrValues = getSimpleAttributeValues(entityWrapper, simpleAttr[i]); 086 for (int j = 0; j < simpleAttrValues.length; j++) { 087 result.addAttributeValue(simpleAttr[i], simpleAttrValues[j]); 088 } 089 } 090 String[] complexAttr = getComplexAttributeNames(entityWrapper); 091 for (int i = 0; i < complexAttr.length; i++) { 092 JavaScriptObject[] complexAttrValues = getComplexAttributeValues(entityWrapper, complexAttr[i]); 093 for (int j = 0; j < complexAttrValues.length; j++) { 094 result.addAttributeValue(complexAttr[i], createFromNativeWrapper(complexAttrValues[j])); 095 } 096 } 097 return result; 098 } 099 100 /** 101 * Returns the instance.<p> 102 * 103 * @return the instance 104 */ 105 public static CmsEntityBackend getInstance() { 106 107 if (INSTANCE == null) { 108 INSTANCE = new CmsEntityBackend(); 109 } 110 return INSTANCE; 111 } 112 113 /** 114 * Returns the complex attribute names of the given entity.<p> 115 * 116 * @param entityWrapper the wrapped entity 117 * 118 * @return the complex attribute names 119 */ 120 private static native String[] getComplexAttributeNames(JavaScriptObject entityWrapper)/*-{ 121 var attr = entityWrapper.getAttributes(); 122 var result = []; 123 for (i = 0; i < attr.length; i++) { 124 if (!attr[i].isSimpleValue()) { 125 result.push(attr[i].getAttributeName()); 126 } 127 } 128 return result; 129 }-*/; 130 131 /** 132 * Returns the complex attribute values of the given entity.<p> 133 * 134 * @param entityWrapper the wrapped entity 135 * @param attributeName the attribute name 136 * 137 * @return the complex attribute values 138 */ 139 private static native JavaScriptObject[] getComplexAttributeValues( 140 JavaScriptObject entityWrapper, 141 String attributeName)/*-{ 142 return entityWrapper.getAttribute(attributeName).getComplexValues(); 143 }-*/; 144 145 /** 146 * Returns the entity type.<p> 147 * 148 * @param entityWrapper the wrapped entity 149 * 150 * @return the entity type name 151 */ 152 private static native String getEntityType(JavaScriptObject entityWrapper)/*-{ 153 return entityWrapper.getTypeName(); 154 }-*/; 155 156 /** 157 * Returns the simple attribute names of the given entity.<p> 158 * 159 * @param entityWrapper the wrapped entity 160 * 161 * @return the simple attribute names 162 */ 163 private static native String[] getSimpleAttributeNames(JavaScriptObject entityWrapper)/*-{ 164 var attr = entityWrapper.getAttributes(); 165 var result = []; 166 for (i = 0; i < attr.length; i++) { 167 if (attr[i].isSimpleValue()) { 168 result.push(attr[i].getAttributeName()); 169 } 170 } 171 return result; 172 }-*/; 173 174 /** 175 * Returns the simple attribute values of the given entity.<p> 176 * 177 * @param entityWrapper the wrapped entity 178 * @param attributeName the attribute name 179 * 180 * @return the simple attribute values 181 */ 182 private static native String[] getSimpleAttributeValues(JavaScriptObject entityWrapper, String attributeName)/*-{ 183 return entityWrapper.getAttribute(attributeName).getSimpleValues(); 184 }-*/; 185 186 /** 187 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#changeEntityContentValues(org.opencms.acacia.shared.CmsEntity, org.opencms.acacia.shared.CmsEntity) 188 */ 189 public void changeEntityContentValues(CmsEntity original, CmsEntity newContent) { 190 191 clearEntityAttributes(original); 192 for (CmsEntityAttribute attribute : newContent.getAttributes()) { 193 if (attribute.isSimpleValue()) { 194 for (String value : attribute.getSimpleValues()) { 195 original.addAttributeValue(attribute.getAttributeName(), value); 196 } 197 } else { 198 for (CmsEntity value : attribute.getComplexValues()) { 199 original.addAttributeValue(attribute.getAttributeName(), registerEntity(value)); 200 } 201 } 202 } 203 } 204 205 /** 206 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#clearEntities() 207 */ 208 public void clearEntities() { 209 210 m_entities.clear(); 211 } 212 213 /** 214 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#createEntity(java.lang.String, java.lang.String) 215 */ 216 public CmsEntity createEntity(String entityId, String entityType) { 217 218 if (entityId == null) { 219 entityId = generateId(); 220 } 221 if (!m_types.containsKey(entityType)) { 222 throw new IllegalArgumentException("Type " + entityType + " is not registered yet"); 223 } 224 if (m_entities.containsKey(entityId)) { 225 throw new IllegalArgumentException("CmsEntity " + entityId + " is already registered"); 226 } 227 CmsEntity entity = new CmsEntity(entityId, entityType); 228 m_entities.put(entityId, entity); 229 return entity; 230 } 231 232 /** 233 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#createType(java.lang.String) 234 */ 235 public CmsType createType(String id) { 236 237 if (m_types.containsKey(id)) { 238 throw new IllegalArgumentException("Type " + id + " is already registered"); 239 } 240 CmsType type = new CmsType(id); 241 m_types.put(id, type); 242 return type; 243 } 244 245 /** 246 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#getAttributeElements(org.opencms.acacia.shared.CmsEntity, java.lang.String, com.google.gwt.dom.client.Element) 247 */ 248 public List<Element> getAttributeElements(CmsEntity entity, String attributeName, Element context) { 249 250 return getAttributeElements(entity.getId(), attributeName, context); 251 } 252 253 /** 254 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#getAttributeElements(java.lang.String, java.lang.String, com.google.gwt.dom.client.Element) 255 */ 256 public List<Element> getAttributeElements(String entityId, String attributeName, Element context) { 257 258 StringBuffer select = new StringBuffer(); 259 select.append("[").append(CmsGwtConstants.ATTR_DATA_ID).append("='").append(entityId).append("'][").append( 260 CmsGwtConstants.ATTR_DATA_FIELD).append("$='").append(attributeName).append("'], "); 261 select.append("[").append(CmsGwtConstants.ATTR_DATA_ID).append("='").append(entityId).append("'] [").append( 262 CmsGwtConstants.ATTR_DATA_FIELD).append("$='").append(attributeName).append("'], "); 263 select.append("[").append(CmsGwtConstants.ATTR_DATA_ID).append("='").append(entityId).append("'][").append( 264 CmsGwtConstants.ATTR_DATA_FIELD).append("*='").append(attributeName).append("['], "); 265 select.append("[").append(CmsGwtConstants.ATTR_DATA_ID).append("='").append(entityId).append("'] [").append( 266 CmsGwtConstants.ATTR_DATA_FIELD).append("*='").append(attributeName).append("[']"); 267 268 if (context == null) { 269 context = Document.get().getDocumentElement(); 270 } 271 return select(select.toString(), context); 272 } 273 274 /** 275 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#getEntity(java.lang.String) 276 */ 277 public CmsEntity getEntity(String entityId) { 278 279 return m_entities.get(entityId); 280 } 281 282 /** 283 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#getType(java.lang.String) 284 */ 285 public CmsType getType(String id) { 286 287 return m_types.get(id); 288 } 289 290 /** 291 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#registerEntity(org.opencms.acacia.shared.CmsEntity) 292 */ 293 public CmsEntity registerEntity(CmsEntity entity) { 294 295 if (m_entities.containsKey(entity.getId())) { 296 CmsGwtLog.warn("CmsEntity " + entity.getId() + " is already registered"); 297 throw new IllegalArgumentException("CmsEntity " + entity.getId() + " is already registered"); 298 } 299 if (!m_types.containsKey(entity.getTypeName())) { 300 CmsGwtLog.warn("Type " + entity.getTypeName() + " is not registered yet"); 301 throw new IllegalArgumentException("Type " + entity.getTypeName() + " is not registered yet"); 302 } 303 for (CmsEntityAttribute attr : entity.getAttributes()) { 304 if (attr.isComplexValue()) { 305 for (CmsEntity child : attr.getComplexValues()) { 306 try { 307 registerEntity(child); 308 } catch (Exception e) { 309 // in case registering the entity attribute fails, remove it 310 entity.removeAttributeSilent(attr.getAttributeName()); 311 } 312 } 313 } 314 } 315 entity.ensureChangeHandlers(); 316 m_entities.put(entity.getId(), entity); 317 return entity; 318 } 319 320 /** 321 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#registerEntity(org.opencms.acacia.shared.CmsEntity, boolean) 322 */ 323 public CmsEntity registerEntity(CmsEntity entity, boolean discardIds) { 324 325 if (!discardIds) { 326 return registerEntity(entity); 327 } else { 328 if (!m_types.containsKey(entity.getTypeName())) { 329 throw new IllegalArgumentException("Type " + entity.getTypeName() + " is not registered yet"); 330 } 331 CmsEntity result = createEntity(null, entity.getTypeName()); 332 for (CmsEntityAttribute attr : entity.getAttributes()) { 333 if (attr.isComplexValue()) { 334 for (CmsEntity child : attr.getComplexValues()) { 335 try { 336 result.addAttributeValue(attr.getAttributeName(), registerEntity(child, discardIds)); 337 } catch (Exception e) { 338 // in case registering the entity attribute fails, do not add the attribute value 339 } 340 } 341 } else { 342 for (String value : attr.getSimpleValues()) { 343 result.addAttributeValue(attr.getAttributeName(), value); 344 } 345 } 346 347 } 348 result.ensureChangeHandlers(); 349 m_entities.put(result.getId(), result); 350 return result; 351 } 352 } 353 354 /** 355 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#registerTypes(org.opencms.acacia.shared.CmsType, java.util.Map) 356 */ 357 public void registerTypes(CmsType type, Map<String, CmsType> types) { 358 359 if (!m_types.containsKey(type.getId())) { 360 for (String attrName : type.getAttributeNames()) { 361 String subTypeId = type.getAttributeTypeName(attrName); 362 CmsType subType = types.get(subTypeId); 363 if (subType == null) { 364 throw new IllegalArgumentException("Type information for " + subTypeId + " is missing"); 365 } 366 registerTypes(subType, types); 367 } 368 m_types.put(type.getId(), type); 369 } 370 } 371 372 /** 373 * @see org.opencms.acacia.client.entity.I_CmsEntityBackend#removeEntity(java.lang.String) 374 */ 375 public void removeEntity(String entityId) { 376 377 if (m_entities.containsKey(entityId)) { 378 CmsEntity entity = m_entities.get(entityId); 379 for (CmsEntityAttribute attr : entity.getAttributes()) { 380 if (attr.isComplexValue()) { 381 for (CmsEntity child : attr.getComplexValues()) { 382 removeEntity(child.getId()); 383 } 384 } 385 } 386 m_entities.remove(entityId); 387 } 388 } 389 390 /** 391 * Returns a list of DOM elements matching the given selector.<p> 392 * 393 * @param selector the CSS selector 394 * @param context the context element 395 * 396 * @return the matching elements 397 */ 398 protected List<Element> select(String selector, Element context) { 399 400 NodeList<Element> elements = CmsDomUtil.querySelectorAll(selector, context); 401 List<Element> result = new ArrayList<Element>(); 402 for (int i = 0; i < elements.getLength(); i++) { 403 result.add(elements.getItem(i)); 404 } 405 return result; 406 } 407 408 /** 409 * Removes all attributes from the given entity.<p> 410 * 411 * @param entity the entity 412 */ 413 private void clearEntityAttributes(CmsEntity entity) { 414 415 for (CmsEntityAttribute attribute : entity.getAttributes()) { 416 if (attribute.isComplexValue()) { 417 for (CmsEntity child : attribute.getComplexValues()) { 418 clearEntityAttributes(child); 419 removeEntity(child.getId()); 420 } 421 } 422 entity.removeAttributeSilent(attribute.getAttributeName()); 423 } 424 } 425 426 /** 427 * Generates a new entity id.<p> 428 * 429 * @return the generated id 430 */ 431 private String generateId() { 432 433 m_count++; 434 String id = "generic_id" + m_count; 435 while (m_entities.containsKey(id)) { 436 m_count++; 437 id = "generic_id" + m_count; 438 } 439 return id; 440 } 441}