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