001    /*
002     * Copyright 2010 The Apache Software Foundation.
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    package org.vafer.jdeb.descriptors;
017    
018    import java.io.BufferedReader;
019    import java.io.IOException;
020    import java.io.InputStream;
021    import java.io.InputStreamReader;
022    import java.io.StringReader;
023    import java.text.ParseException;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.Map;
027    import java.util.Set;
028    
029    import org.vafer.jdeb.utils.Utils;
030    import org.vafer.jdeb.utils.VariableResolver;
031    
032    /**
033     * A descriptor holds the usual key value pairs.
034     *
035     * @see <a href="http://www.debian.org/doc/debian-policy/ch-controlfields.html">Debian Policy Manual - Control files and their fields</a>
036     * 
037     * @author Torsten Curdt <tcurdt@vafer.org>
038     */
039    public abstract class AbstractDescriptor {
040        
041        private final Map values = new HashMap();
042        private final VariableResolver resolver;
043        private static String openToken = "[[";
044        private static String closeToken = "]]";
045        
046        public AbstractDescriptor( final VariableResolver pResolver ) {
047            resolver = pResolver;
048        }
049    
050        public AbstractDescriptor( final AbstractDescriptor pDescriptor ) {
051            values.putAll(pDescriptor.values);
052            resolver = pDescriptor.resolver;
053        }
054    
055        public static void setOpenToken( final String pToken ) {
056            openToken = pToken;
057        }
058    
059        public static void setCloseToken( final String pToken ) {
060            closeToken = pToken;
061        }
062    
063        protected void parse( final InputStream pInput ) throws IOException, ParseException {
064            final BufferedReader br = new BufferedReader(new InputStreamReader(pInput));
065            StringBuffer buffer = new StringBuffer();
066            String key = null;
067            int linenr = 0;
068            while(true) {
069                final String line = br.readLine();
070                
071                if (line == null) {
072                    if (buffer.length() > 0) {
073                        // flush value of previous key
074                        set(key, buffer.toString());
075                        buffer = null;
076                    }
077                    break;
078                }
079    
080                linenr++;
081    
082                if (line.length() == 0) {
083                    throw new ParseException("Empty line", linenr);
084                }
085                
086                final char first = line.charAt(0); 
087                if (Character.isLetter(first)) {
088                    
089                    // new key
090                    
091                    if (buffer.length() > 0) {
092                        // flush value of previous key
093                        set(key, buffer.toString());
094                        buffer = new StringBuffer();
095                    }
096                    
097                    
098                    final int i = line.indexOf(':');
099                    
100                    if (i < 0) {
101                        throw new ParseException("Line misses ':' delimitter", linenr);
102                    }
103                    
104                    key = line.substring(0, i);
105                    buffer.append(line.substring(i+1).trim());
106                    
107                    continue;
108                }
109                
110                // continuing old value
111                buffer.append('\n').append(line.substring(1));
112            }
113            br.close();
114            
115        }
116        
117        public void set( final String pKey, final String pValue ) {
118    
119            if (resolver != null) {
120                try {
121                    values.put(pKey, Utils.replaceVariables(resolver, pValue, openToken, closeToken));
122                    return;
123                } catch (ParseException e) {
124                    // FIXME maybe throw an Exception?
125                }
126            }
127            
128            values.put(pKey, pValue);
129        }
130        
131        public String get( final String pKey ) {
132            return (String)values.get(pKey);
133        }
134    
135        public abstract String[] getMandatoryKeys();
136        
137        public boolean isValid() {
138            return invalidKeys().size() == 0;
139        }
140        
141        public Set invalidKeys() {
142            final Set invalid = new HashSet();
143    
144            final String[] mk = getMandatoryKeys();
145            for (int i = 0; i < mk.length; i++) {
146                if (get(mk[i]) == null) {
147                    invalid.add(mk[i]);
148                }
149            }
150            
151            return invalid;
152        }
153        
154        public String toString( final String[] pKeys ) {
155            final StringBuffer s = new StringBuffer();
156            for (int i = 0; i < pKeys.length; i++) {
157                final String key = pKeys[i];
158                final String value = (String) values.get(key);
159                if (value != null) {
160                    s.append(key).append(":");
161    
162                    try {
163                        BufferedReader reader = new BufferedReader(new StringReader(value));
164                        String line;
165                        while ((line = reader.readLine()) != null) {
166                            if (line.length() != 0 && !Character.isWhitespace(line.charAt(0))) {
167                                s.append(' ');
168                            }
169    
170                            s.append(line).append('\n');
171                        }
172                    } catch (IOException e) {
173                        e.printStackTrace();
174                    }
175                }           
176            }
177            return s.toString();
178        }
179    }