001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019 */
020
021/**
022 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
023 */
024package net.sourceforge.pmd.cpd;
025
026import com.google.common.io.Closeables;
027
028import java.io.*;
029import java.lang.ref.SoftReference;
030import java.util.ArrayList;
031import java.util.List;
032
033/**
034 * <p>Not intended to be instantiated by clients.</p>
035 *
036 * @since 2.2
037 */
038public class SourceCode {
039
040  public static final String EOL = System.getProperty("line.separator", "\n");
041
042  public abstract static class CodeLoader {
043    private SoftReference<List<String>> code;
044
045    public List<String> getCode() {
046      List<String> c = null;
047      if (code != null) {
048        c = code.get();
049      }
050      if (c != null) {
051        return c;
052      }
053      this.code = new SoftReference<List<String>>(load());
054      return code.get();
055    }
056
057    public abstract String getFileName();
058
059    protected abstract Reader getReader() throws Exception;
060
061    protected List<String> load() {
062      LineNumberReader lnr = null;
063      try {
064        lnr = new LineNumberReader(getReader());
065        List<String> lines = new ArrayList<String>();
066        String currentLine;
067        while ((currentLine = lnr.readLine()) != null) {
068          lines.add(currentLine);
069        }
070        return lines;
071      } catch (Exception e) {
072        throw new RuntimeException("Problem while reading " + getFileName() + ":" + e.getMessage(), e);
073      } finally {
074        Closeables.closeQuietly(lnr);
075      }
076    }
077  }
078
079  public static class FileCodeLoader extends CodeLoader {
080    private File file;
081    private String encoding;
082
083    public FileCodeLoader(File file, String encoding) {
084      this.file = file;
085      this.encoding = encoding;
086    }
087
088    @Override
089    public Reader getReader() throws Exception {
090      return new InputStreamReader(new FileInputStream(file), encoding);
091    }
092
093    @Override
094    public String getFileName() {
095      return this.file.getAbsolutePath();
096    }
097  }
098
099  public static class StringCodeLoader extends CodeLoader {
100    public static final String DEFAULT_NAME = "CODE_LOADED_FROM_STRING";
101
102    private String source_code;
103
104    private String name;
105
106    public StringCodeLoader(String code) {
107      this(code, DEFAULT_NAME);
108    }
109
110    public StringCodeLoader(String code, String name) {
111      this.source_code = code;
112      this.name = name;
113    }
114
115    @Override
116    public Reader getReader() {
117      return new StringReader(source_code);
118    }
119
120    @Override
121    public String getFileName() {
122      return name;
123    }
124  }
125
126  private CodeLoader cl;
127
128  public SourceCode(CodeLoader cl) {
129    this.cl = cl;
130  }
131
132  public List<String> getCode() {
133    return cl.getCode();
134  }
135
136  public StringBuffer getCodeBuffer() {
137    StringBuffer sb = new StringBuffer();
138    List<String> lines = cl.getCode();
139    for (String line : lines) {
140      sb.append(line);
141      sb.append(EOL);
142    }
143    return sb;
144  }
145
146  public String getSlice(int startLine, int endLine) {
147    StringBuffer sb = new StringBuffer();
148    List lines = cl.getCode();
149    for (int i = (startLine == 0 ? startLine : startLine - 1); i < endLine && i < lines.size(); i++) {
150      if (sb.length() != 0) {
151        sb.append(EOL);
152      }
153      sb.append((String) lines.get(i));
154    }
155    return sb.toString();
156  }
157
158  /**
159   * Within Sonar Ecosystem - absolute path to file containing code,
160   * whereas in fact existence of such file not guaranteed - see {@link StringCodeLoader}.
161   */
162  public String getFileName() {
163    return cl.getFileName();
164  }
165}