001
014
015 package com.liferay.portal.tools.sourceformatter;
016
017 import com.liferay.portal.kernel.util.PropertiesUtil;
018 import com.liferay.portal.kernel.util.PropsKeys;
019 import com.liferay.portal.kernel.util.StringBundler;
020 import com.liferay.portal.kernel.util.StringPool;
021 import com.liferay.portal.kernel.util.StringUtil;
022 import com.liferay.portal.kernel.util.Validator;
023 import com.liferay.portal.kernel.xml.Document;
024 import com.liferay.portal.kernel.xml.DocumentException;
025 import com.liferay.portal.kernel.xml.Element;
026 import com.liferay.portal.tools.ComparableRoute;
027 import com.liferay.util.ContentUtil;
028
029 import java.io.File;
030 import java.io.IOException;
031
032 import java.util.ArrayList;
033 import java.util.Arrays;
034 import java.util.Collections;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Properties;
038 import java.util.Set;
039 import java.util.TreeSet;
040
041
044 public class XMLSourceProcessor extends BaseSourceProcessor {
045
046 @Override
047 protected void doFormat() throws Exception {
048 String[] excludes = new String[] {
049 "**\\.idea\\**", "**\\bin\\**", "**\\classes\\**"
050 };
051 String[] includes = new String[] {"**\\*.xml"};
052
053 List<String> fileNames = getFileNames(excludes, includes);
054
055 for (String fileName : fileNames) {
056 File file = new File(BASEDIR + fileName);
057
058 fileName = StringUtil.replace(
059 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
060
061 String content = fileUtil.read(file);
062
063 String newContent = content;
064
065 if (!fileName.contains("/build")) {
066 Properties leadingSpacesExclusions = getExclusionsProperties(
067 "source_formatter_xml_leading_spaces_exclusions." +
068 "properties");
069
070 String excluded = null;
071
072 if (leadingSpacesExclusions != null) {
073 excluded = leadingSpacesExclusions.getProperty(fileName);
074 }
075
076 if (excluded == null) {
077 newContent = trimContent(newContent, false);
078 }
079 }
080
081 if (fileName.contains("/build") && !fileName.contains("/tools/")) {
082 newContent = formatAntXML(fileName, newContent);
083 }
084 else if (fileName.endsWith("structures.xml")) {
085 newContent = formatDDLStructuresXML(newContent);
086 }
087 else if (fileName.endsWith("routes.xml")) {
088 newContent = formatFriendlyURLRoutesXML(fileName, newContent);
089 }
090 else if ((portalSource &&
091 fileName.endsWith("/portlet-custom.xml")) ||
092 (!portalSource && fileName.endsWith("/portlet.xml"))) {
093
094 newContent = formatPortletXML(newContent);
095 }
096 else if (portalSource && fileName.endsWith("/service.xml")) {
097 formatServiceXML(fileName, newContent);
098 }
099 else if (portalSource && fileName.endsWith("/struts-config.xml")) {
100 formatStrutsConfigXML(fileName, content);
101 }
102 else if (portalSource && fileName.endsWith("/tiles-defs.xml")) {
103 formatTilesDefsXML(fileName, content);
104 }
105 else if (portalSource && fileName.endsWith("WEB-INF/web.xml") ||
106 !portalSource && fileName.endsWith("/web.xml")) {
107
108 newContent = formatWebXML(fileName, content);
109 }
110
111 if ((newContent != null) && !content.equals(newContent)) {
112 fileUtil.write(file, newContent);
113
114 sourceFormatterHelper.printError(fileName, file);
115 }
116 }
117 }
118
119 protected String fixAntXMLProjectName(String fileName, String content) {
120 int x = 0;
121
122 if (fileName.endsWith("-ext/build.xml")) {
123 if (fileName.startsWith("ext/")) {
124 x = 4;
125 }
126 }
127 else if (fileName.endsWith("-hook/build.xml")) {
128 if (fileName.startsWith("hooks/")) {
129 x = 6;
130 }
131 }
132 else if (fileName.endsWith("-layouttpl/build.xml")) {
133 if (fileName.startsWith("layouttpl/")) {
134 x = 10;
135 }
136 }
137 else if (fileName.endsWith("-portlet/build.xml")) {
138 if (fileName.startsWith("portlets/")) {
139 x = 9;
140 }
141 }
142 else if (fileName.endsWith("-theme/build.xml")) {
143 if (fileName.startsWith("themes/")) {
144 x = 7;
145 }
146 }
147 else if (fileName.endsWith("-web/build.xml") &&
148 !fileName.endsWith("/ext-web/build.xml")) {
149
150 if (fileName.startsWith("webs/")) {
151 x = 5;
152 }
153 }
154 else {
155 return content;
156 }
157
158 int y = fileName.indexOf("/", x);
159
160 String correctProjectElementText =
161 "<project name=\"" + fileName.substring(x, y) + "\"";
162
163 if (!content.contains(correctProjectElementText)) {
164 x = content.indexOf("<project name=\"");
165
166 y = content.indexOf("\"", x) + 1;
167 y = content.indexOf("\"", y) + 1;
168
169 content =
170 content.substring(0, x) + correctProjectElementText +
171 content.substring(y);
172
173 processErrorMessage(
174 fileName, fileName + " has an incorrect project name");
175 }
176
177 return content;
178 }
179
180 protected String formatAntXML(String fileName, String content)
181 throws DocumentException, IOException {
182
183 String newContent = trimContent(content, true);
184
185 newContent = fixAntXMLProjectName(fileName, newContent);
186
187 Document document = saxReaderUtil.read(newContent);
188
189 Element rootElement = document.getRootElement();
190
191 String previousName = StringPool.BLANK;
192
193 List<Element> targetElements = rootElement.elements("target");
194
195 for (Element targetElement : targetElements) {
196 String name = targetElement.attributeValue("name");
197
198 if (name.equals("Test")) {
199 name = name.toLowerCase();
200 }
201
202 if (name.compareTo(previousName) < -1) {
203 processErrorMessage(
204 fileName,
205 fileName + " has an unordered target " + name);
206
207 break;
208 }
209
210 previousName = name;
211 }
212
213 return newContent;
214 }
215
216 protected String formatDDLStructuresXML(String content)
217 throws DocumentException, IOException {
218
219 Document document = saxReaderUtil.read(content);
220
221 Element rootElement = document.getRootElement();
222
223 rootElement.sortAttributes(true);
224
225 rootElement.sortElementsByChildElement("structure", "name");
226
227 List<Element> structureElements = rootElement.elements("structure");
228
229 for (Element structureElement : structureElements) {
230 Element structureRootElement = structureElement.element("root");
231
232 structureRootElement.sortElementsByAttribute(
233 "dynamic-element", "name");
234
235 List<Element> dynamicElementElements =
236 structureRootElement.elements("dynamic-element");
237
238 for (Element dynamicElementElement : dynamicElementElements) {
239 Element metaDataElement = dynamicElementElement.element(
240 "meta-data");
241
242 metaDataElement.sortElementsByAttribute("entry", "name");
243 }
244 }
245
246 return document.formattedString();
247 }
248
249 protected String formatFriendlyURLRoutesXML(String fileName, String content)
250 throws DocumentException, IOException {
251
252 Properties friendlyUrlRoutesSortExclusions = getExclusionsProperties(
253 "source_formatter_friendly_url_routes_sort_exclusions.properties");
254
255 String excluded = null;
256
257 if (friendlyUrlRoutesSortExclusions != null) {
258 excluded = friendlyUrlRoutesSortExclusions.getProperty(fileName);
259 }
260
261 if (excluded != null) {
262 return content;
263 }
264
265 Document document = saxReaderUtil.read(content);
266
267 Element rootElement = document.getRootElement();
268
269 List<ComparableRoute> comparableRoutes =
270 new ArrayList<ComparableRoute>();
271
272 for (Element routeElement : rootElement.elements("route")) {
273 String pattern = routeElement.elementText("pattern");
274
275 ComparableRoute comparableRoute = new ComparableRoute(pattern);
276
277 for (Element generatedParameterElement :
278 routeElement.elements("generated-parameter")) {
279
280 String name = generatedParameterElement.attributeValue("name");
281 String value = generatedParameterElement.getText();
282
283 comparableRoute.addGeneratedParameter(name, value);
284 }
285
286 for (Element ignoredParameterElement :
287 routeElement.elements("ignored-parameter")) {
288
289 String name = ignoredParameterElement.attributeValue("name");
290
291 comparableRoute.addIgnoredParameter(name);
292 }
293
294 for (Element implicitParameterElement :
295 routeElement.elements("implicit-parameter")) {
296
297 String name = implicitParameterElement.attributeValue("name");
298 String value = implicitParameterElement.getText();
299
300 comparableRoute.addImplicitParameter(name, value);
301 }
302
303 for (Element overriddenParameterElement :
304 routeElement.elements("overridden-parameter")) {
305
306 String name = overriddenParameterElement.attributeValue("name");
307 String value = overriddenParameterElement.getText();
308
309 comparableRoute.addOverriddenParameter(name, value);
310 }
311
312 comparableRoutes.add(comparableRoute);
313 }
314
315 Collections.sort(comparableRoutes);
316
317 StringBundler sb = new StringBundler();
318
319 sb.append("<?xml version=\"1.0\"?>\n");
320 sb.append("<!DOCTYPE routes PUBLIC \"-
321 sb.append("Routes ");
322 sb.append(mainReleaseVersion);
323 sb.append("
324 sb.append("liferay-friendly-url-routes_");
325 sb.append(
326 StringUtil.replace(
327 mainReleaseVersion, StringPool.PERIOD, StringPool.UNDERLINE));
328 sb.append(".dtd\">\n\n<routes>\n");
329
330 for (ComparableRoute comparableRoute : comparableRoutes) {
331 sb.append("\t<route>\n");
332 sb.append("\t\t<pattern>");
333 sb.append(comparableRoute.getPattern());
334 sb.append("</pattern>\n");
335
336 Map<String, String> generatedParameters =
337 comparableRoute.getGeneratedParameters();
338
339 for (Map.Entry<String, String> entry :
340 generatedParameters.entrySet()) {
341
342 sb.append("\t\t<generated-parameter name=\"");
343 sb.append(entry.getKey());
344 sb.append("\">");
345 sb.append(entry.getValue());
346 sb.append("</generated-parameter>\n");
347 }
348
349 Set<String> ignoredParameters =
350 comparableRoute.getIgnoredParameters();
351
352 for (String entry : ignoredParameters) {
353 sb.append("\t\t<ignored-parameter name=\"");
354 sb.append(entry);
355 sb.append("\" />\n");
356 }
357
358 Map<String, String> implicitParameters =
359 comparableRoute.getImplicitParameters();
360
361 for (Map.Entry<String, String> entry :
362 implicitParameters.entrySet()) {
363
364 sb.append("\t\t<implicit-parameter name=\"");
365 sb.append(entry.getKey());
366 sb.append("\">");
367 sb.append(entry.getValue());
368 sb.append("</implicit-parameter>\n");
369 }
370
371 Map<String, String> overriddenParameters =
372 comparableRoute.getOverriddenParameters();
373
374 for (Map.Entry<String, String> entry :
375 overriddenParameters.entrySet()) {
376
377 sb.append("\t\t<overridden-parameter name=\"");
378 sb.append(entry.getKey());
379 sb.append("\">");
380 sb.append(entry.getValue());
381 sb.append("</overridden-parameter>\n");
382 }
383
384 sb.append("\t</route>\n");
385 }
386
387 sb.append("</routes>");
388
389 return sb.toString();
390 }
391
392 protected String formatPortletXML(String content)
393 throws DocumentException, IOException {
394
395 Document document = saxReaderUtil.read(content);
396
397 Element rootElement = document.getRootElement();
398
399 rootElement.sortAttributes(true);
400
401 List<Element> portletElements = rootElement.elements("portlet");
402
403 for (Element portletElement : portletElements) {
404 portletElement.sortElementsByChildElement("init-param", "name");
405
406 Element portletPreferencesElement = portletElement.element(
407 "portlet-preferences");
408
409 if (portletPreferencesElement != null) {
410 portletPreferencesElement.sortElementsByChildElement(
411 "preference", "name");
412 }
413 }
414
415 return document.formattedString();
416 }
417
418 protected void formatServiceXML(String fileName, String content)
419 throws DocumentException {
420
421 Document document = saxReaderUtil.read(content);
422
423 Element rootElement = document.getRootElement();
424
425 List<Element> entityElements = rootElement.elements("entity");
426
427 String previousEntityName = StringPool.BLANK;
428
429 for (Element entityElement : entityElements) {
430 String entityName = entityElement.attributeValue("name");
431
432 if (Validator.isNotNull(previousEntityName) &&
433 (previousEntityName.compareToIgnoreCase(entityName) > 0)) {
434
435 processErrorMessage(
436 fileName, "sort: " + fileName + " " + entityName);
437 }
438
439 String previousReferenceEntity = StringPool.BLANK;
440 String previousReferencePackagePath = StringPool.BLANK;
441
442 List<Element> referenceElements = entityElement.elements(
443 "reference");
444
445 for (Element referenceElement : referenceElements) {
446 String referenceEntity = referenceElement.attributeValue(
447 "entity");
448 String referencePackagePath = referenceElement.attributeValue(
449 "package-path");
450
451 if (Validator.isNotNull(previousReferencePackagePath)) {
452 if ((previousReferencePackagePath.compareToIgnoreCase(
453 referencePackagePath) > 0) ||
454 (previousReferencePackagePath.equals(
455 referencePackagePath) &&
456 (previousReferenceEntity.compareToIgnoreCase(
457 referenceEntity) > 0))) {
458
459 processErrorMessage(
460 fileName,
461 "sort: " + fileName + " " + referencePackagePath);
462 }
463 }
464
465 previousReferenceEntity = referenceEntity;
466 previousReferencePackagePath = referencePackagePath;
467 }
468
469 previousEntityName = entityName;
470 }
471
472 Element exceptionsElement = rootElement.element("exceptions");
473
474 if (exceptionsElement == null) {
475 return;
476 }
477
478 List<Element> exceptionElements = exceptionsElement.elements(
479 "exception");
480
481 String previousException = StringPool.BLANK;
482
483 for (Element exceptionElement : exceptionElements) {
484 String exception = exceptionElement.getStringValue();
485
486 if (Validator.isNotNull(previousException) &&
487 (previousException.compareToIgnoreCase(exception) > 0)) {
488
489 processErrorMessage(
490 fileName, "sort: " + fileName + " " + exception);
491 }
492
493 previousException = exception;
494 }
495 }
496
497 protected void formatStrutsConfigXML(String fileName, String content)
498 throws DocumentException {
499
500 Document document = saxReaderUtil.read(content);
501
502 Element rootElement = document.getRootElement();
503
504 Element actionMappingsElement = rootElement.element("action-mappings");
505
506 List<Element> actionElements = actionMappingsElement.elements("action");
507
508 String previousPath = StringPool.BLANK;
509
510 for (Element actionElement : actionElements) {
511 String path = actionElement.attributeValue("path");
512
513 if (Validator.isNotNull(previousPath) &&
514 (previousPath.compareTo(path) > 0) &&
515 (!previousPath.startsWith("/portal/") ||
516 path.startsWith("/portal/"))) {
517
518 processErrorMessage(fileName, "sort: " + fileName + " " + path);
519 }
520
521 previousPath = path;
522 }
523 }
524
525 protected void formatTilesDefsXML(String fileName, String content)
526 throws DocumentException {
527
528 Document document = saxReaderUtil.read(content);
529
530 Element rootElement = document.getRootElement();
531
532 List<Element> definitionElements = rootElement.elements("definition");
533
534 String previousName = StringPool.BLANK;
535
536 for (Element definitionElement : definitionElements) {
537 String name = definitionElement.attributeValue("name");
538
539 if (Validator.isNotNull(previousName) &&
540 (previousName.compareTo(name) > 0) &&
541 !previousName.equals("portlet")) {
542
543 processErrorMessage(fileName, "sort: " + fileName + " " + name);
544
545 }
546
547 previousName = name;
548 }
549 }
550
551 protected String formatWebXML(String fileName, String content)
552 throws IOException {
553
554 if (!portalSource) {
555 String webXML = ContentUtil.get(
556 "com/liferay/portal/deploy/dependencies/web.xml");
557
558 if (content.equals(webXML)) {
559 processErrorMessage(fileName, fileName);
560 }
561
562 return content;
563 }
564
565 Properties properties = new Properties();
566
567 String propertiesContent = fileUtil.read(
568 BASEDIR + "portal-impl/src/portal.properties");
569
570 PropertiesUtil.load(properties, propertiesContent);
571
572 String[] locales = StringUtil.split(
573 properties.getProperty(PropsKeys.LOCALES));
574
575 Arrays.sort(locales);
576
577 Set<String> urlPatterns = new TreeSet<String>();
578
579 for (String locale : locales) {
580 int pos = locale.indexOf(StringPool.UNDERLINE);
581
582 String languageCode = locale.substring(0, pos);
583
584 urlPatterns.add(languageCode);
585 urlPatterns.add(locale);
586 }
587
588 StringBundler sb = new StringBundler();
589
590 for (String urlPattern : urlPatterns) {
591 sb.append("\t<servlet-mapping>\n");
592 sb.append("\t\t<servlet-name>I18n Servlet</servlet-name>\n");
593 sb.append("\t\t<url-pattern>/" + urlPattern +"