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 */
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.BatchComponent;
029import org.sonar.api.ServerComponent;
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 */
044public 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}