1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     David Carver - STAR - bug 213255
14  *******************************************************************************/
15 package org.eclipse.pde.internal.core.schema;
16 
17 import java.io.PrintWriter;
18 import org.eclipse.pde.internal.core.ischema.ISchema;
19 import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
20 import org.eclipse.pde.internal.core.ischema.ISchemaElement;
21 import org.eclipse.pde.internal.core.ischema.ISchemaObject;
22 import org.eclipse.pde.internal.core.ischema.ISchemaSimpleType;
23 import org.eclipse.pde.internal.core.util.SchemaUtil;
24 import org.eclipse.pde.internal.core.util.XMLComponentRegistry;
25 
26 public class SchemaAttribute extends SchemaObject implements ISchemaAttribute {
27 
28 	private static final long serialVersionUID = 1L;
29 
30 	private int kind = STRING;
31 
32 	private int use = OPTIONAL;
33 
34 	private String valueFilter;
35 
36 	private ISchemaSimpleType type;
37 
38 	private String basedOn;
39 
40 	private Object value;
41 
42 	public static final String P_USE = "useProperty"; //$NON-NLS-1$
43 
44 	public static final String P_VALUE_FILTER = "valueFilterProperty"; //$NON-NLS-1$
45 
46 	public static final String P_VALUE = "value"; //$NON-NLS-1$
47 
48 	public static final String P_KIND = "kindProperty"; //$NON-NLS-1$
49 
50 	public static final String P_TYPE = "typeProperty"; //$NON-NLS-1$
51 
52 	public static final String P_BASED_ON = "basedOnProperty"; //$NON-NLS-1$
53 
54 	private boolean fTranslatable;
55 
56 	private boolean fDeprecated;
57 
SchemaAttribute(ISchemaAttribute att, String newName)58 	public SchemaAttribute(ISchemaAttribute att, String newName) {
59 		super(att.getParent(), newName);
60 		kind = att.getKind();
61 		use = att.getUse();
62 		value = att.getValue();
63 		type = new SchemaSimpleType(att.getType());
64 		basedOn = att.getBasedOn();
65 	}
66 
SchemaAttribute(ISchemaObject parent, String name)67 	public SchemaAttribute(ISchemaObject parent, String name) {
68 		super(parent, name);
69 	}
70 
71 	@Override
getBasedOn()72 	public String getBasedOn() {
73 		if (getKind() == JAVA || getKind() == IDENTIFIER) {
74 			return basedOn;
75 		}
76 		return null;
77 	}
78 
79 	@Override
getKind()80 	public int getKind() {
81 		return kind;
82 	}
83 
84 	@Override
getType()85 	public ISchemaSimpleType getType() {
86 		return type;
87 	}
88 
89 	@Override
getUse()90 	public int getUse() {
91 		return use;
92 	}
93 
94 	@Override
getValue()95 	public Object getValue() {
96 		return value;
97 	}
98 
getValueFilter()99 	public String getValueFilter() {
100 		return valueFilter;
101 	}
102 
setBasedOn(String newBasedOn)103 	public void setBasedOn(String newBasedOn) {
104 		String oldValue = basedOn;
105 		basedOn = newBasedOn;
106 		getSchema().fireModelObjectChanged(this, P_BASED_ON, oldValue, basedOn);
107 	}
108 
setKind(int newKind)109 	public void setKind(int newKind) {
110 		Integer oldValue = Integer.valueOf(kind);
111 		kind = newKind;
112 		getSchema().fireModelObjectChanged(this, P_KIND, oldValue, Integer.valueOf(kind));
113 	}
114 
setTranslatableProperty(boolean translatable)115 	public void setTranslatableProperty(boolean translatable) {
116 		boolean oldValue = fTranslatable;
117 		fTranslatable = translatable;
118 		getSchema().fireModelObjectChanged(this, P_TRANSLATABLE, Boolean.valueOf(oldValue), Boolean.valueOf(translatable));
119 	}
120 
setDeprecatedProperty(boolean deprecated)121 	public void setDeprecatedProperty(boolean deprecated) {
122 		boolean oldValue = fDeprecated;
123 		fDeprecated = deprecated;
124 		getSchema().fireModelObjectChanged(this, P_DEPRECATED, Boolean.valueOf(oldValue), Boolean.valueOf(deprecated));
125 	}
126 
setType(ISchemaSimpleType newType)127 	public void setType(ISchemaSimpleType newType) {
128 		Object oldValue = type;
129 		type = newType;
130 		getSchema().fireModelObjectChanged(this, P_TYPE, oldValue, type);
131 	}
132 
133 	@Override
setParent(ISchemaObject obj)134 	public void setParent(ISchemaObject obj) {
135 		super.setParent(obj);
136 		if (type != null) {
137 			type.setSchema(getSchema());
138 		}
139 	}
140 
setUse(int newUse)141 	public void setUse(int newUse) {
142 		Integer oldValue = Integer.valueOf(use);
143 		use = newUse;
144 		getSchema().fireModelObjectChanged(this, P_USE, oldValue, Integer.valueOf(use));
145 	}
146 
setValue(String value)147 	public void setValue(String value) {
148 		String oldValue = (String) this.value;
149 		this.value = value;
150 		getSchema().fireModelObjectChanged(this, P_VALUE, oldValue, value);
151 	}
152 
setValueFilter(String valueFilter)153 	public void setValueFilter(String valueFilter) {
154 		String oldValue = this.valueFilter;
155 		this.valueFilter = valueFilter;
156 		getSchema().fireModelObjectChanged(this, P_VALUE_FILTER, oldValue, valueFilter);
157 	}
158 
159 	@Override
write(String indent, PrintWriter writer)160 	public void write(String indent, PrintWriter writer) {
161 		boolean annotation = false;
162 		ISchemaSimpleType type = getType();
163 		String typeName = type.getName();
164 		writer.print(indent);
165 		writer.print("<attribute name=\"" + getName() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
166 		if (type.getRestriction() == null) {
167 			writer.print(" type=\"" + typeName + "\""); //$NON-NLS-1$ //$NON-NLS-2$
168 		}
169 		String useString = null;
170 		switch (getUse()) {
171 			case OPTIONAL :
172 				// don't write default setting
173 				// useString="optional";
174 				break;
175 			case DEFAULT :
176 				useString = "default"; //$NON-NLS-1$
177 				break;
178 			case REQUIRED :
179 				useString = "required"; //$NON-NLS-1$
180 				break;
181 		}
182 		if (useString != null) {
183 			writer.print(" use=\"" + useString + "\""); //$NON-NLS-1$ //$NON-NLS-2$
184 		}
185 		if (value != null && getUse() == DEFAULT) {
186 			writer.print(" value=\"" + value + "\""); //$NON-NLS-1$ //$NON-NLS-2$
187 		}
188 		String documentation = getWritableDescription();
189 		if (documentation != null || this.getBasedOn() != null || getKind() != STRING) {
190 			// Add annotation
191 			annotation = true;
192 			writer.println(">"); //$NON-NLS-1$
193 			String annIndent = indent + Schema.INDENT;
194 			String indent2 = annIndent + Schema.INDENT;
195 			String indent3 = indent2 + Schema.INDENT;
196 			writer.print(annIndent);
197 			writer.println("<annotation>"); //$NON-NLS-1$
198 			if (documentation != null) {
199 				writer.println(indent2 + "<documentation>"); //$NON-NLS-1$
200 				writer.println(indent3 + documentation);
201 				writer.println(indent2 + "</documentation>"); //$NON-NLS-1$
202 			}
203 			if (getBasedOn() != null || getKind() != STRING || isDeprecated() || isTranslatable()) {
204 				writer.println(indent2 + (getSchema().getSchemaVersion() >= 3.4 ? "<appinfo>" : "<appInfo>")); //$NON-NLS-1$ //$NON-NLS-2$
205 				writer.print(indent3 + "<meta.attribute"); //$NON-NLS-1$
206 				String kindValue = null;
207 				switch (getKind()) { // TODO let's use some constants ;D
208 					case JAVA :
209 						kindValue = "java"; //$NON-NLS-1$
210 						break;
211 					case RESOURCE :
212 						kindValue = "resource"; //$NON-NLS-1$
213 						break;
214 					case IDENTIFIER :
215 						kindValue = "identifier"; //$NON-NLS-1$
216 				}
217 				if (kindValue != null) {
218 					writer.print(" kind=\"" + kindValue + "\""); //$NON-NLS-1$ //$NON-NLS-2$
219 				}
220 				if (getBasedOn() != null) {
221 					writer.print(" basedOn=\"" + getBasedOn() + "\""); //$NON-NLS-1$ //$NON-NLS-2$
222 				}
223 				if (isTranslatable()) {
224 					writer.print(" translatable=\"true\""); //$NON-NLS-1$
225 				}
226 				if (isDeprecated()) {
227 					writer.print(" deprecated=\"true\""); //$NON-NLS-1$
228 				}
229 				writer.println("/>"); //$NON-NLS-1$
230 				writer.println(indent2 + (getSchema().getSchemaVersion() >= 3.4 ? "</appinfo>" : "</appInfo>")); //$NON-NLS-1$ //$NON-NLS-2$
231 			}
232 			writer.println(annIndent + "</annotation>"); //$NON-NLS-1$
233 		}
234 		if (type.getRestriction() != null) {
235 			type.write(indent + Schema.INDENT, writer);
236 		}
237 		if (annotation || type.getRestriction() != null) {
238 			writer.println(indent + "</attribute>"); //$NON-NLS-1$
239 		} else {
240 			writer.println("/>"); //$NON-NLS-1$
241 		}
242 	}
243 
244 	@Override
isTranslatable()245 	public boolean isTranslatable() {
246 		if (getKind() == STRING && fTranslatable) {
247 			return type == null || "string".equals(type.getName()); //$NON-NLS-1$
248 		}
249 		return false;
250 	}
251 
252 	@Override
isDeprecated()253 	public boolean isDeprecated() {
254 		return fDeprecated;
255 	}
256 
257 	@Override
getDescription()258 	public String getDescription() {
259 		if (super.getDescription() != null) {
260 			return super.getDescription();
261 		}
262 		ISchema schema = getSchema();
263 		if ((schema == null) || (schema.getURL() == null)) {
264 			return null;
265 		}
266 		String elementName = null;
267 		if (getParent() instanceof ISchemaElement) {
268 			elementName = ((ISchemaElement) getParent()).getName();
269 			if (elementName == null) {
270 				return null;
271 			}
272 		}
273 		String hashkey = schema.getURL().toExternalForm().hashCode() + "_" + elementName + "_" + getName(); //$NON-NLS-1$ //$NON-NLS-2$
274 		String description = XMLComponentRegistry.Instance().getDescription(hashkey, XMLComponentRegistry.F_ATTRIBUTE_COMPONENT);
275 		if (description == null) {
276 			SchemaAttributeHandler handler = new SchemaAttributeHandler(elementName, getName());
277 			SchemaUtil.parseURL(schema.getURL(), handler);
278 			description = handler.getDescription();
279 			XMLComponentRegistry.Instance().putDescription(hashkey, description, XMLComponentRegistry.F_ATTRIBUTE_COMPONENT);
280 		}
281 
282 		return description;
283 	}
284 
285 }
286