001/* 002 * (C) Copyright 2017 Nuxeo (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 * Kevin Leturc 018 */ 019package org.nuxeo.ecm.core.api.model.impl; 020 021import java.io.Serializable; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Iterator; 025import java.util.Objects; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029import org.nuxeo.ecm.core.api.NuxeoException; 030import org.nuxeo.ecm.core.api.PropertyException; 031import org.nuxeo.ecm.core.api.model.Property; 032import org.nuxeo.ecm.core.api.model.PropertyNotFoundException; 033import org.nuxeo.ecm.core.api.model.PropertyVisitor; 034import org.nuxeo.ecm.core.schema.types.ComplexTypeImpl; 035import org.nuxeo.ecm.core.schema.types.Field; 036import org.nuxeo.ecm.core.schema.types.Type; 037 038/** 039 * Property used to declare property removed from schema. 040 * 041 * @since 9.2 042 */ 043public class RemovedProperty extends AbstractProperty { 044 045 private static final long serialVersionUID = 1L; 046 047 private static final Log log = LogFactory.getLog(RemovedProperty.class); 048 049 protected final String fieldName; 050 051 protected final Property fallback; 052 053 public RemovedProperty(Property parent, String fieldName) { 054 this(parent, fieldName, null); 055 } 056 057 public RemovedProperty(Property parent, String fieldName, Property fallback) { 058 super(parent); 059 this.fieldName = fieldName; 060 this.fallback = fallback; 061 } 062 063 @Override 064 public void internalSetValue(Serializable value) throws PropertyException { 065 StringBuilder msg = newRemovedMessage(); 066 if (fallback == null) { 067 msg.append("Do nothing"); 068 } else { 069 msg.append("Set value to fallback property '").append(fallback.getXPath()).append("'"); 070 } 071 if (log.isTraceEnabled()) { 072 log.error(msg, new NuxeoException("debug stack trace")); 073 } else { 074 log.error(msg); 075 } 076 if (fallback != null) { 077 fallback.setValue(value); 078 } 079 } 080 081 @Override 082 public Serializable internalGetValue() throws PropertyException { 083 StringBuilder msg = newRemovedMessage(); 084 if (fallback == null) { 085 msg.append("Return null"); 086 } else { 087 msg.append("Return value from '").append(fallback.getXPath()).append("'"); 088 } 089 if (log.isTraceEnabled()) { 090 log.error(msg, new NuxeoException()); 091 } else { 092 log.error(msg); 093 } 094 if (fallback == null) { 095 return null; 096 } 097 return fallback.getValue(); 098 } 099 100 protected StringBuilder newRemovedMessage() { 101 StringBuilder builder = new StringBuilder().append("Property '") 102 .append(getXPath()) 103 .append("' is marked as removed from '") 104 .append(getSchema().getName()) 105 .append("' schema"); 106 RemovedProperty removedParent = getRemovedParent(); 107 if (removedParent != this) { 108 builder.append(" because property '").append(removedParent.getXPath()).append("' is marked as removed"); 109 } 110 return builder.append(", don't use it anymore. "); 111 } 112 113 protected RemovedProperty getRemovedParent() { 114 RemovedProperty property = this; 115 while (property.getParent() instanceof RemovedProperty) { 116 property = (RemovedProperty) property.getParent(); 117 } 118 return property; 119 } 120 121 @Override 122 public String getName() { 123 return fieldName; 124 } 125 126 @Override 127 public Type getType() { 128 if (fallback == null) { 129 // TODO try to do something better - currently RemovedProperty is always a container if there's no fallback 130 // Simulate a complex type 131 return new ComplexTypeImpl(getSchema(), getSchema().getName(), fieldName); 132 } 133 return fallback.getType(); 134 } 135 136 @Override 137 public boolean isContainer() { 138 // TODO try to do something better - currently RemovedProperty is always a container if there's no fallback 139 return fallback == null || fallback.isContainer(); 140 } 141 142 @Override 143 public Collection<Property> getChildren() { 144 return Collections.emptyList(); 145 } 146 147 @Override 148 public Property get(String name) throws PropertyNotFoundException { 149 if (fallback != null) { 150 return new RemovedProperty(this, name, fallback.get(name)); 151 } else if (name.matches("\\d+")) { 152 return get(Integer.parseInt(name)); 153 } 154 return new RemovedProperty(this, name); 155 } 156 157 @Override 158 public Property get(int index) throws PropertyNotFoundException { 159 // TODO try to do something better - currently RemovedProperty is always a container if there's no fallback 160 return new RemovedProperty(this, fieldName); 161 } 162 163 @Override 164 public Property addValue(Object value) throws PropertyException { 165 throw new UnsupportedOperationException("Removed properties don't have children"); 166 } 167 168 @Override 169 public Property addValue(int index, Object value) throws PropertyException { 170 throw new UnsupportedOperationException("Removed properties don't have children"); 171 } 172 173 @Override 174 public Property addEmpty() throws PropertyException { 175 throw new UnsupportedOperationException("Removed properties don't have children"); 176 } 177 178 @Override 179 public Field getField() { 180 throw new UnsupportedOperationException("Removed properties don't have field"); 181 } 182 183 @Override 184 public void accept(PropertyVisitor visitor, Object arg) throws PropertyException { 185 // Nothing to do 186 } 187 188 @Override 189 public boolean isSameAs(Property property) throws PropertyException { 190 if (!(property instanceof RemovedProperty)) { 191 return false; 192 } 193 RemovedProperty rp = (RemovedProperty) property; 194 return Objects.equals(getSchema(), rp.getSchema()) && Objects.equals(getName(), getName()) 195 && Objects.equals(getRemovedParent().getName(), rp.getRemovedParent().getName()); 196 } 197 198 @Override 199 public Iterator<Property> getDirtyChildren() { 200 return Collections.emptyIterator(); 201 } 202 203}