001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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 License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.api.utils;
021    
022    import com.google.common.annotations.VisibleForTesting;
023    import com.google.common.base.Preconditions;
024    import com.google.common.base.Throwables;
025    import com.google.common.collect.Lists;
026    import com.google.common.collect.Maps;
027    import com.google.common.io.Files;
028    import org.sonar.api.BatchComponent;
029    import org.sonar.api.ServerComponent;
030    
031    import java.io.File;
032    import java.io.IOException;
033    import java.net.URI;
034    import java.nio.charset.Charset;
035    import java.util.List;
036    import java.util.Locale;
037    import java.util.Map;
038    
039    /**
040     * Reads different types of URI. Supported schemes are http and file.
041     *
042     * @since 3.2
043     */
044    public class UriReader implements BatchComponent, ServerComponent {
045    
046      private final Map<String, SchemeProcessor> processorsByScheme = Maps.newHashMap();
047    
048      public UriReader(SchemeProcessor[] processors) {
049        List<SchemeProcessor> allProcessors = Lists.asList(new FileProcessor(), processors);
050        for (SchemeProcessor processor : allProcessors) {
051          for (String scheme : processor.getSupportedSchemes()) {
052            processorsByScheme.put(scheme.toLowerCase(Locale.ENGLISH), processor);
053          }
054        }
055      }
056    
057      /**
058       * Reads all bytes from uri. It throws an unchecked exception if an error occurs.
059       */
060      public byte[] readBytes(URI uri) {
061        return searchForSupportedProcessor(uri).readBytes(uri);
062      }
063    
064      /**
065       * Reads all characters from uri, using the given character set.
066       * It throws an unchecked exception if an error occurs.
067       */
068      public String readString(URI uri, Charset charset) {
069        return searchForSupportedProcessor(uri).readString(uri, charset);
070      }
071    
072      /**
073       * Returns a detailed description of the given uri. For example HTTP URIs are completed
074       * with the configured HTTP proxy.
075       */
076      public String description(URI uri) {
077        SchemeProcessor reader = searchForSupportedProcessor(uri);
078    
079        return reader.description(uri);
080      }
081    
082      @VisibleForTesting
083      SchemeProcessor searchForSupportedProcessor(URI uri) {
084        SchemeProcessor processor = processorsByScheme.get(uri.getScheme().toLowerCase(Locale.ENGLISH));
085        Preconditions.checkArgument(processor != null, "URI schema is not supported: " + uri.getScheme());
086        return processor;
087      }
088    
089      abstract static class SchemeProcessor {
090        abstract String[] getSupportedSchemes();
091    
092        abstract byte[] readBytes(URI uri);
093    
094        abstract String readString(URI uri, Charset charset);
095    
096        abstract String description(URI uri);
097      }
098    
099    
100      /**
101       * This implementation is not exposed in API and is kept private.
102       */
103      private static class FileProcessor extends SchemeProcessor {
104    
105        @Override
106        public String[] getSupportedSchemes() {
107          return new String[]{"file"};
108        }
109    
110        @Override
111        byte[] readBytes(URI uri) {
112          try {
113            return Files.toByteArray(new File(uri));
114          } catch (IOException e) {
115            throw Throwables.propagate(e);
116          }
117        }
118    
119        @Override
120        String readString(URI uri, Charset charset) {
121          try {
122            return Files.toString(new File(uri), charset);
123          } catch (IOException e) {
124            throw Throwables.propagate(e);
125          }
126        }
127    
128        @Override
129        String description(URI uri) {
130          return new File(uri).getAbsolutePath();
131        }
132      }
133    }