001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.config.internal; 014 015import static org.apache.juneau.common.internal.StringUtils.*; 016import static org.apache.juneau.internal.CollectionUtils.*; 017 018import java.io.*; 019import java.util.*; 020 021import org.apache.juneau.common.internal.*; 022 023/** 024 * Represents a single entry in a configuration. 025 * 026 * This is a read-only object. 027 */ 028public class ConfigMapEntry { 029 final String rawLine; 030 final String key, value, comment; 031 final String modifiers; 032 final List<String> preLines; 033 034 static final ConfigMapEntry NULL = new ConfigMapEntry(null, null, null, null, null); 035 036// private final static AsciiSet MOD_CHARS = AsciiSet.create("#$%&*+^@~"); 037 038 ConfigMapEntry(String line, List<String> preLines) { 039 this.rawLine = line; 040 int i = line.indexOf('='); 041 String key = line.substring(0, i).trim(); 042 043 int m1 = key.indexOf('<'), m2 = key.indexOf('>'); 044 modifiers = nullIfEmpty((m1 > -1 && m2 > m1) ? key.substring(m1+1, m2) : null); 045 046 this.key = m1 == -1 ? key : key.substring(0, m1); 047 048 line = line.substring(i+1); 049 050 i = line.indexOf('#'); 051 if (i != -1) { 052 String[] l2 = split(line, '#', 2); 053 line = l2[0]; 054 if (l2.length == 2) 055 this.comment = l2[1].trim(); 056 else 057 this.comment = null; 058 } else { 059 this.comment = null; 060 } 061 062 this.value = StringUtils.replaceUnicodeSequences(line.trim()); 063 064 this.preLines = preLines == null ? emptyList() : unmodifiable(copyOf(preLines)); 065 } 066 067 ConfigMapEntry(String key, String value, String modifiers, String comment, List<String> preLines) { 068 this.rawLine = null; 069 this.key = key; 070 this.value = value; 071 this.comment = comment; 072 this.modifiers = modifiers; 073 this.preLines = preLines == null ? emptyList() : unmodifiable(copyOf(preLines)); 074 } 075 076 /** 077 * Returns the name of this entry. 078 * 079 * @return The name of this entry. 080 */ 081 public String getKey() { 082 return key; 083 } 084 085 /** 086 * Returns the raw value of this entry. 087 * 088 * @return The raw value of this entry. 089 */ 090 public String getValue() { 091 return value; 092 } 093 094 /** 095 * Returns the same-line comment of this entry. 096 * 097 * @return The same-line comment of this entry. 098 */ 099 public String getComment() { 100 return comment; 101 } 102 103 /** 104 * Returns the pre-lines of this entry. 105 * 106 * @return The pre-lines of this entry as an unmodifiable list. 107 */ 108 public List<String> getPreLines() { 109 return preLines; 110 } 111 112 /** 113 * Returns the modifiers for this entry. 114 * 115 * @return The modifiers for this entry, or <jk>null</jk> if it has no modifiers. 116 */ 117 public String getModifiers() { 118 return modifiers; 119 } 120 121 Writer writeTo(Writer w) throws IOException { 122 if (value == null) 123 return w; 124 for (String pl : preLines) 125 w.append(pl).append('\n'); 126 if (rawLine != null) { 127 for (int i = 0; i < rawLine.length(); i++) { 128 char c = rawLine.charAt(i); 129 if (c == '\n') 130 w.append('\n').append('\t'); 131 else if (c != '\r') 132 w.append(c); 133 } 134 w.append('\n'); 135 } else { 136 w.append(key); 137 if (modifiers != null) 138 w.append('<').append(new String(modifiers)).append('>'); 139 w.append(" = "); 140 141 String val = value; 142 for (int i = 0; i < val.length(); i++) { 143 char c = val.charAt(i); 144 if (c == '\n') 145 w.append('\n').append('\t'); 146 else if (c != '\r') { 147 if (REPLACE_CHARS.contains(c) || (Character.isISOControl(c) && ! (c == '\n' || c == '\r' || c == '\t'))) { 148 w.append(StringUtils.unicodeSequence(c)); 149 } else { 150 w.append(c); 151 } 152 } 153 } 154 155 if (isNotEmpty(comment)) 156 w.append(" # ").append(comment); 157 158 w.append('\n'); 159 } 160 return w; 161 } 162 163 private static final AsciiSet REPLACE_CHARS = AsciiSet.create("\\#"); 164}