Пример #1
0
 public void testOf() {
   assertMapEquals(ImmutableBiMap.of("one", 1), "one", 1);
   assertMapEquals(ImmutableBiMap.of("one", 1).inverse(), 1, "one");
   assertMapEquals(ImmutableBiMap.of("one", 1, "two", 2), "one", 1, "two", 2);
   assertMapEquals(ImmutableBiMap.of("one", 1, "two", 2).inverse(), 1, "one", 2, "two");
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3), "one", 1, "two", 2, "three", 3);
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3).inverse(),
       1,
       "one",
       2,
       "two",
       3,
       "three");
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4),
       "one",
       1,
       "two",
       2,
       "three",
       3,
       "four",
       4);
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4).inverse(),
       1,
       "one",
       2,
       "two",
       3,
       "three",
       4,
       "four");
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5),
       "one",
       1,
       "two",
       2,
       "three",
       3,
       "four",
       4,
       "five",
       5);
   assertMapEquals(
       ImmutableBiMap.of("one", 1, "two", 2, "three", 3, "four", 4, "five", 5).inverse(),
       1,
       "one",
       2,
       "two",
       3,
       "three",
       4,
       "four",
       5,
       "five");
 }
Пример #2
0
    public void testOfNullValue() {
      try {
        ImmutableBiMap.of("one", null);
        fail();
      } catch (NullPointerException expected) {
      }

      try {
        ImmutableBiMap.of("one", 1, "two", null);
        fail();
      } catch (NullPointerException expected) {
      }
    }
Пример #3
0
    public void testOfNullKey() {
      try {
        ImmutableBiMap.of(null, 1);
        fail();
      } catch (NullPointerException expected) {
      }

      try {
        ImmutableBiMap.of("one", 1, null, 2);
        fail();
      } catch (NullPointerException expected) {
      }
    }
Пример #4
0
 public void testCopyOfEmptyMap() {
   ImmutableBiMap<String, Integer> copy =
       ImmutableBiMap.copyOf(Collections.<String, Integer>emptyMap());
   assertEquals(Collections.<String, Integer>emptyMap(), copy);
   assertSame(copy, ImmutableBiMap.copyOf(copy));
   assertSame(ImmutableBiMap.of(), copy);
 }
Пример #5
0
 public void testOfWithDuplicateKey() {
   try {
     ImmutableBiMap.of("one", 1, "one", 1);
     fail();
   } catch (IllegalArgumentException expected) {
     assertThat(expected.getMessage()).contains("one");
   }
 }
Пример #6
0
 @Override
 public ImmutableBiMap<V, K> inverse() {
   if (isEmpty()) {
     return ImmutableBiMap.of();
   }
   ImmutableBiMap<V, K> result = inverse;
   return (result == null) ? inverse = new Inverse() : result;
 }
Пример #7
0
 public void testOfWithDuplicateKey() {
   try {
     ImmutableBiMap.of("one", 1, "one", 1);
     fail();
   } catch (IllegalArgumentException expected) {
     assertEquals("duplicate key: one", expected.getMessage());
   }
 }
  private void assertCompDir(Path compDir, Optional<String> failure) throws Exception {
    ProjectFilesystem filesystem = new ProjectFilesystem(tmp.getRoot().toPath());
    CxxPlatform platform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig()));

    // Build up the paths to various files the archive step will use.
    ImmutableList<String> compiler =
        platform.getCc().getCommandPrefix(new SourcePathResolver(new BuildRuleResolver()));
    Path output = filesystem.resolve(Paths.get("output.o"));
    Path relativeInput = Paths.get("input.c");
    Path input = filesystem.resolve(relativeInput);
    filesystem.writeContentsToPath("int main() {}", relativeInput);

    ImmutableList.Builder<String> preprocessorCommand = ImmutableList.builder();
    preprocessorCommand.addAll(compiler);

    ImmutableList.Builder<String> compilerCommand = ImmutableList.builder();
    compilerCommand.addAll(compiler);
    compilerCommand.add("-g");

    DebugPathSanitizer sanitizer =
        new DebugPathSanitizer(200, File.separatorChar, compDir, ImmutableBiMap.<Path, Path>of());

    // Build an archive step.
    CxxPreprocessAndCompileStep step =
        new CxxPreprocessAndCompileStep(
            CxxPreprocessAndCompileStep.Operation.COMPILE_MUNGE_DEBUGINFO,
            output,
            relativeInput,
            CxxSource.Type.C,
            Optional.of(preprocessorCommand.build()),
            Optional.of(compilerCommand.build()),
            ImmutableMap.<Path, Path>of(),
            sanitizer);

    // Execute the archive step and verify it ran successfully.
    ExecutionContext executionContext =
        TestExecutionContext.newBuilder()
            .setProjectFilesystem(new ProjectFilesystem(tmp.getRoot().toPath()))
            .build();
    TestConsole console = (TestConsole) executionContext.getConsole();
    int exitCode = step.execute(executionContext);
    if (failure.isPresent()) {
      assertNotEquals("compile step succeeded", 0, exitCode);
      assertThat(
          console.getTextWrittenToStdErr(),
          console.getTextWrittenToStdErr(),
          Matchers.containsString(failure.get()));
    } else {
      assertEquals("compile step failed: " + console.getTextWrittenToStdErr(), 0, exitCode);
      // Verify that we find the expected compilation dir embedded in the file.
      String contents = new String(Files.readAllBytes(output));
      assertThat(contents, Matchers.containsString(sanitizer.getCompilationDirectory()));
    }

    // Cleanup.
    Files.delete(input);
    Files.deleteIfExists(output);
  }
Пример #9
0
 @SuppressWarnings("unchecked")
 <T> BiMap<String, T> getPersistentSubstitutionMap(Class<T> type) {
   if (type.equals(Item.class)) {
     return (BiMap<String, T>) itemSubstitutions;
   } else if (type.equals(Block.class)) {
     return (BiMap<String, T>) blockSubstitutions;
   } else {
     return ImmutableBiMap.of();
   }
 }
@WritingConverter
public class EstadoNotaFiscalWritingConverter implements Converter<EstadoNotaFiscal, String> {

  private static final BiMap<EstadoNotaFiscal, String> valueMap =
      ImmutableBiMap.of(EstadoNotaFiscal.FATURADA, "F", EstadoNotaFiscal.CANCELADA, "C");

  @Override
  public String convert(EstadoNotaFiscal source) {
    return valueMap.get(source);
  }
}
Пример #11
0
 public void testToImmutableBiMap() {
   Collector<Entry<String, Integer>, ?, ImmutableBiMap<String, Integer>> collector =
       ImmutableBiMap.toImmutableBiMap(Entry::getKey, Entry::getValue);
   Equivalence<ImmutableBiMap<String, Integer>> equivalence =
       Equivalence.equals()
           .<Entry<String, Integer>>pairwise()
           .onResultOf(ImmutableBiMap::entrySet);
   CollectorTester.of(collector, equivalence)
       .expectCollects(
           ImmutableBiMap.of("one", 1, "two", 2, "three", 3),
           mapEntry("one", 1),
           mapEntry("two", 2),
           mapEntry("three", 3));
 }
Пример #12
0
  public static void main(String[] args) {
    ArrayList<Integer> list = Lists.newArrayList(new Integer[] {1, 2, 3, 4});

    List<String> transform =
        Lists.transform(
            list,
            new Function<Integer, String>() {
              @Override
              public String apply(Integer integer) {
                return integer + "";
              }
            });

    List<Integer> reverseList = Lists.reverse(list);
    for (Object o : transform) {
      System.out.println(o.getClass().toString() + o);
    }
    for (Object o : reverseList) {
      System.out.println(o);
    }
    System.out.println("Hell o");
    // 不可变集合
    ImmutableList<Integer> immutableList = ImmutableList.of(1, 2, 3, 4);
    ImmutableBiMap<Integer, String> immutableBiMap = ImmutableBiMap.of(1, "1", 2, "2");
    ImmutableSet<Integer> immutableSet = ImmutableSet.of(1, 2, 3, 4);
    ImmutableCollection<Integer> immutableCollection = ImmutableList.of(1, 2, 3, 4);

    for (Integer i : immutableList) {
      System.out.print(i + "-");
    }
    System.out.println();
    for (Integer i : immutableBiMap.keySet()) {
      System.out.print(immutableBiMap.get(i) + "-");
    }
    System.out.println();
    for (Integer i : immutableList) {
      System.out.print(i + "-");
    }
    System.out.println();
    for (Integer i : immutableCollection) {
      System.out.print(i + "-");
    }
    // 新集合类型
    ArrayList arrayList = new ArrayList();
    arrayList.toArray();
    // 集合工具
    // 扩展工具类
  }
class CraftScoreboardTranslations {
  static final int MAX_DISPLAY_SLOT = 3;
  static ImmutableBiMap<DisplaySlot, String> SLOTS =
      ImmutableBiMap.of(
          DisplaySlot.BELOW_NAME, "belowName",
          DisplaySlot.PLAYER_LIST, "list",
          DisplaySlot.SIDEBAR, "sidebar");

  static DisplaySlot toBukkitSlot(int i) {
    return (DisplaySlot) SLOTS.inverse().get(Scoreboard.getSlotName(i));
  }

  static int fromBukkitSlot(DisplaySlot slot) {
    return Scoreboard.getSlotForName((String) SLOTS.get(slot));
  }
}
  @Test
  public void shouldRewriteLineMarkers() {
    BuildRuleResolver ruleResolver =
        new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

    Path original = Paths.get("buck-out/foo#bar/world.h");
    Path finalPath = Paths.get("SANITIZED/world.h");

    HeaderPathNormalizer.Builder normalizerBuilder =
        new HeaderPathNormalizer.Builder(pathResolver, Functions.<Path>identity());
    normalizerBuilder.addHeader(new FakeSourcePath("hello/////world.h"), original);
    HeaderPathNormalizer normalizer = normalizerBuilder.build();

    DebugPathSanitizer sanitizer =
        new DebugPathSanitizer(
            9,
            File.separatorChar,
            Paths.get("PWD"),
            ImmutableBiMap.of(Paths.get("hello"), Paths.get("SANITIZED")));
    FakeProjectFilesystem fakeProjectFilesystem = new FakeProjectFilesystem();

    CxxPreprocessorOutputTransformerFactory transformer =
        new CxxPreprocessorOutputTransformerFactory(
            fakeProjectFilesystem.getRootPath(), normalizer, sanitizer);

    // Fixup line marker lines properly.
    assertThat(
        String.format("# 12 \"%s\"", Escaper.escapePathForCIncludeString(finalPath)),
        equalTo(transformer.transformLine(String.format("# 12 \"%s\"", original))));
    assertThat(
        String.format("# 12 \"%s\" 2 1", Escaper.escapePathForCIncludeString(finalPath)),
        equalTo(transformer.transformLine(String.format("# 12 \"%s\" 2 1", original))));

    // test.h isn't in the replacement map, so shouldn't be replaced.
    assertThat("# 4 \"test.h\"", equalTo(transformer.transformLine("# 4 \"test.h\"")));

    // Don't modify non-line-marker lines.
    assertThat("int main() {", equalTo(transformer.transformLine("int main() {")));
  }
Пример #15
0
 @GwtIncompatible // SerializableTester
 public void testEmptySerialization() {
   ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of();
   assertSame(bimap, SerializableTester.reserializeAndAssert(bimap));
 }
Пример #16
0
 public void testEmpty() {
   ImmutableBiMap<String, Integer> bimap = ImmutableBiMap.of();
   assertEquals(Collections.<String, Integer>emptyMap(), bimap);
   assertEquals(Collections.<String, Integer>emptyMap(), bimap.inverse());
 }
Пример #17
0
public class CxxPlatforms {

  private static final Logger LOG = Logger.get(CxxPlatforms.class);
  private static final ImmutableList<String> DEFAULT_ASFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_ASPPFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_CFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_CXXFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_CPPFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_CXXPPFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_CXXLDFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_LDFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_ARFLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_LEX_FLAGS = ImmutableList.of();
  private static final ImmutableList<String> DEFAULT_YACC_FLAGS = ImmutableList.of("-y");

  @VisibleForTesting
  static final DebugPathSanitizer DEFAULT_DEBUG_PATH_SANITIZER =
      new DebugPathSanitizer(
          250, File.separatorChar, Paths.get("."), ImmutableBiMap.<Path, Path>of());

  // Utility class, do not instantiate.
  private CxxPlatforms() {}

  public static CxxPlatform build(
      Flavor flavor,
      Platform platform,
      CxxBuckConfig config,
      Tool as,
      Tool aspp,
      Tool cc,
      Tool cxx,
      Tool cpp,
      Tool cxxpp,
      Tool cxxld,
      Optional<CxxPlatform.LinkerType> linkerType,
      Tool ld,
      Iterable<String> ldFlags,
      Tool ar,
      byte[] expectedGlobalHeader,
      ImmutableList<String> cflags,
      ImmutableList<String> cppflags,
      Optional<Tool> lex,
      Optional<Tool> yacc,
      Optional<DebugPathSanitizer> debugPathSanitizer) {
    // TODO(user, agallagher): Generalize this so we don't need all these setters.
    CxxPlatform.Builder builder = CxxPlatform.builder();

    builder
        .setFlavor(flavor)
        .setAs(getTool(flavor, "as", config).or(as))
        .setAspp(getTool(flavor, "aspp", config).or(aspp))
        .setCc(getTool(flavor, "cc", config).or(cc))
        .setCxx(getTool(flavor, "cxx", config).or(cxx))
        .setCpp(getTool(flavor, "cpp", config).or(cpp))
        .setCxxpp(getTool(flavor, "cxxpp", config).or(cxxpp))
        .setCxxld(getTool(flavor, "cxxld", config).or(cxxld))
        .setLd(getLd(flavor, platform, config, linkerType, getTool(flavor, "ld", config).or(ld)))
        .addAllLdflags(ldFlags)
        .setAr(getTool(flavor, "ar", config).or(ar))
        .setArExpectedGlobalHeader(expectedGlobalHeader)
        .setLex(getTool(flavor, "lex", config).or(lex))
        .setYacc(getTool(flavor, "yacc", config).or(yacc))
        .setSharedLibraryExtension(CxxPlatforms.getSharedLibraryExtension(platform))
        .setDebugPathSanitizer(debugPathSanitizer.or(CxxPlatforms.DEFAULT_DEBUG_PATH_SANITIZER));
    builder.addAllCflags(cflags);
    builder.addAllCxxflags(cflags);
    builder.addAllCppflags(cppflags);
    builder.addAllCxxppflags(cppflags);
    builder.addAllCxxldflags(cflags);
    CxxPlatforms.addToolFlagsFromConfig(config, builder);
    return builder.build();
  }

  private static String getSharedLibraryExtension(Platform platform) {
    switch (platform) {
      case MACOS:
        return "dylib";
      case WINDOWS:
        return "dll";
        // $CASES-OMITTED$
      default:
        return "so";
    }
  }

  private static Linker getLd(
      Flavor flavor,
      Platform platform,
      CxxBuckConfig config,
      Optional<CxxPlatform.LinkerType> linkerType,
      Tool tool) {
    CxxPlatform.LinkerType type =
        config
            .getLinkerType(flavor.toString(), CxxPlatform.LinkerType.class)
            .or(linkerType)
            .or(getLinkerTypeForPlatform(platform));
    switch (type) {
      case GNU:
        return new GnuLinker(tool);
      case DARWIN:
        return new DarwinLinker(tool);
      case WINDOWS:
        return new WindowsLinker(tool);
    }
    throw new IllegalStateException();
  }

  private static CxxPlatform.LinkerType getLinkerTypeForPlatform(Platform platform) {
    switch (platform) {
      case LINUX:
        return CxxPlatform.LinkerType.GNU;
      case MACOS:
        return CxxPlatform.LinkerType.DARWIN;
      case WINDOWS:
        return CxxPlatform.LinkerType.WINDOWS;
        // $CASES-OMITTED$
      default:
        throw new HumanReadableException(
            "cannot detect linker type, try explicitly setting it in "
                + ".buckconfig's [cxx] ld_type section");
    }
  }

  public static void addToolFlagsFromConfig(CxxBuckConfig config, CxxPlatform.Builder builder) {
    ImmutableList<String> asflags = config.getFlags("asflags").or(DEFAULT_ASFLAGS);
    ImmutableList<String> cflags = config.getFlags("cflags").or(DEFAULT_CFLAGS);
    ImmutableList<String> cxxflags = config.getFlags("cxxflags").or(DEFAULT_CXXFLAGS);
    builder
        .addAllAsflags(asflags)
        .addAllAsppflags(config.getFlags("asppflags").or(DEFAULT_ASPPFLAGS))
        .addAllAsppflags(asflags)
        .addAllCflags(cflags)
        .addAllCxxflags(cxxflags)
        .addAllCppflags(config.getFlags("cppflags").or(DEFAULT_CPPFLAGS))
        .addAllCppflags(cflags)
        .addAllCxxppflags(config.getFlags("cxxppflags").or(DEFAULT_CXXPPFLAGS))
        .addAllCxxppflags(cxxflags)
        .addAllCxxldflags(config.getFlags("cxxldflags").or(DEFAULT_CXXLDFLAGS))
        .addAllLdflags(config.getFlags("ldflags").or(DEFAULT_LDFLAGS))
        .addAllArflags(config.getFlags("arflags").or(DEFAULT_ARFLAGS))
        .addAllLexFlags(config.getFlags("lexflags").or(DEFAULT_LEX_FLAGS))
        .addAllYaccFlags(config.getFlags("yaccflags").or(DEFAULT_YACC_FLAGS));
  }

  public static CxxPlatform getConfigDefaultCxxPlatform(
      CxxBuckConfig cxxBuckConfig,
      ImmutableMap<Flavor, CxxPlatform> cxxPlatformsMap,
      CxxPlatform systemDefaultCxxPlatform) {
    CxxPlatform defaultCxxPlatform;
    Optional<String> defaultPlatform = cxxBuckConfig.getDefaultPlatform();
    if (defaultPlatform.isPresent()) {
      defaultCxxPlatform = cxxPlatformsMap.get(ImmutableFlavor.of(defaultPlatform.get()));
      if (defaultCxxPlatform == null) {
        LOG.warn(
            "Couldn't find default platform %s, falling back to system default",
            defaultPlatform.get());
      } else {
        LOG.debug("Using config default C++ platform %s", defaultCxxPlatform);
        return defaultCxxPlatform;
      }
    } else {
      LOG.debug("Using system default C++ platform %s", systemDefaultCxxPlatform);
    }

    return systemDefaultCxxPlatform;
  }

  private static Optional<Tool> getTool(Flavor flavor, String name, CxxBuckConfig config) {
    return config
        .getPath(flavor.toString(), name)
        .transform(HashedFileTool.FROM_PATH)
        .transform(Functions.<Tool>identity());
  }
}
Пример #18
0
  @Test
  public void sanitizedPathsInFlagsDoNotAffectRuleKey() {
    SourcePathResolver pathResolver =
        new SourcePathResolver(
            new BuildRuleResolver(TargetGraph.EMPTY, new BuildTargetNodeToBuildRuleTransformer()));
    BuildTarget target = BuildTargetFactory.newInstance("//foo:bar");
    BuildRuleParams params = new FakeBuildRuleParamsBuilder(target).build();
    RuleKeyBuilderFactory ruleKeyBuilderFactory =
        new DefaultRuleKeyBuilderFactory(
            FakeFileHashCache.createFromStrings(
                ImmutableMap.<String, String>builder()
                    .put("preprocessor", Strings.repeat("a", 40))
                    .put("compiler", Strings.repeat("a", 40))
                    .put("test.o", Strings.repeat("b", 40))
                    .put("test.cpp", Strings.repeat("c", 40))
                    .put("different", Strings.repeat("d", 40))
                    .put("foo/test.h", Strings.repeat("e", 40))
                    .put("path/to/a/plugin.so", Strings.repeat("f", 40))
                    .put("path/to/a/different/plugin.so", Strings.repeat("a0", 40))
                    .build()),
            pathResolver);

    // Set up a map to sanitize the differences in the flags.
    int pathSize = 10;
    DebugPathSanitizer sanitizer1 =
        new DebugPathSanitizer(
            pathSize,
            File.separatorChar,
            Paths.get("PWD"),
            ImmutableBiMap.of(Paths.get("something"), Paths.get("A")));
    DebugPathSanitizer sanitizer2 =
        new DebugPathSanitizer(
            pathSize,
            File.separatorChar,
            Paths.get("PWD"),
            ImmutableBiMap.of(Paths.get("different"), Paths.get("A")));

    // Generate a rule key for the defaults.
    ImmutableList<String> platformFlags1 = ImmutableList.of("-Isomething/foo");
    ImmutableList<String> ruleFlags1 = ImmutableList.of("-Isomething/bar");

    RuleKey ruleKey1 =
        ruleKeyBuilderFactory.build(
            CxxPreprocessAndCompile.preprocess(
                params,
                pathResolver,
                new PreprocessorDelegate(
                    pathResolver,
                    sanitizer1,
                    DEFAULT_WORKING_DIR,
                    DEFAULT_PREPROCESSOR,
                    platformFlags1,
                    ruleFlags1,
                    DEFAULT_INCLUDE_ROOTS,
                    DEFAULT_SYSTEM_INCLUDE_ROOTS,
                    DEFAULT_HEADER_MAPS,
                    DEFAULT_FRAMEWORK_ROOTS,
                    DEFAULT_FRAMEWORK_PATH_SEARCH_PATH_FUNCTION,
                    Optional.<SourcePath>absent(),
                    DEFAULT_INCLUDES),
                DEFAULT_OUTPUT,
                DEFAULT_INPUT,
                DEFAULT_INPUT_TYPE,
                sanitizer1));

    // Generate a rule key for the defaults.
    ImmutableList<String> platformFlags2 = ImmutableList.of("-Idifferent/foo");
    ImmutableList<String> ruleFlags2 = ImmutableList.of("-Idifferent/bar");

    RuleKey ruleKey2 =
        ruleKeyBuilderFactory.build(
            CxxPreprocessAndCompile.preprocess(
                params,
                pathResolver,
                new PreprocessorDelegate(
                    pathResolver,
                    sanitizer2,
                    DEFAULT_WORKING_DIR,
                    DEFAULT_PREPROCESSOR,
                    platformFlags2,
                    ruleFlags2,
                    DEFAULT_INCLUDE_ROOTS,
                    DEFAULT_SYSTEM_INCLUDE_ROOTS,
                    DEFAULT_HEADER_MAPS,
                    DEFAULT_FRAMEWORK_ROOTS,
                    DEFAULT_FRAMEWORK_PATH_SEARCH_PATH_FUNCTION,
                    Optional.<SourcePath>absent(),
                    DEFAULT_INCLUDES),
                DEFAULT_OUTPUT,
                DEFAULT_INPUT,
                DEFAULT_INPUT_TYPE,
                sanitizer2));

    assertEquals(ruleKey1, ruleKey2);
  }
Пример #19
0
 @Override
 protected Map<String, Integer> makePopulatedMap() {
   return ImmutableBiMap.of(1, "one", 2, "two", 3, "three").inverse();
 }
Пример #20
0
 public void testEmptyBuilder() {
   ImmutableBiMap<String, Integer> map = new Builder<String, Integer>().build();
   assertEquals(Collections.<String, Integer>emptyMap(), map);
   assertEquals(Collections.<Integer, String>emptyMap(), map.inverse());
   assertSame(ImmutableBiMap.of(), map);
 }
Пример #21
0
/**
 * A set of helpful tools for converting JCR properties to RDF
 *
 * @author Chris Beer
 * @date May 10, 2013
 */
public class JcrRdfTools {

  private static final Logger LOGGER = getLogger(JcrRdfTools.class);

  /** A map of JCR namespaces to Fedora's RDF namespaces */
  public static BiMap<String, String> jcrNamespacesToRDFNamespaces =
      ImmutableBiMap.of(JCR_NAMESPACE, RdfLexicon.REPOSITORY_NAMESPACE);

  /** A map of Fedora's RDF namespaces to the JCR equivalent */
  public static BiMap<String, String> rdfNamespacesToJcrNamespaces =
      jcrNamespacesToRDFNamespaces.inverse();

  private LowLevelStorageService llstore;

  private final IdentifierTranslator graphSubjects;

  private Session session;

  /**
   * Factory method to create a new JcrRdfTools utility with a graph subjects converter
   *
   * @param graphSubjects
   */
  public JcrRdfTools(final IdentifierTranslator graphSubjects) {
    this(graphSubjects, null, null);
  }

  /**
   * Factory method to create a new JcrRdfTools utility with a graph subjects converter
   *
   * @param graphSubjects
   * @param session
   */
  public JcrRdfTools(final IdentifierTranslator graphSubjects, final Session session) {
    this(graphSubjects, session, null);
  }

  /**
   * Contructor with even more context.
   *
   * @param graphSubjects
   * @param session
   * @param lls
   */
  public JcrRdfTools(
      final IdentifierTranslator graphSubjects,
      final Session session,
      final LowLevelStorageService lls) {
    this.graphSubjects = graphSubjects;
    this.session = session;
    this.llstore = lls;
  }

  /**
   * Factory method to create a new JcrRdfTools instance
   *
   * @param graphSubjects
   * @return
   */
  public static JcrRdfTools withContext(final IdentifierTranslator graphSubjects) {
    return new JcrRdfTools(graphSubjects);
  }

  /**
   * Factory method to create a new JcrRdfTools instance
   *
   * @param graphSubjects
   * @param session
   * @return
   */
  public static JcrRdfTools withContext(
      final IdentifierTranslator idTranslator, final Session session) {
    checkNotNull(
        idTranslator, "JcrRdfTools must operate with a non-null IdentifierTranslator for context!");
    return new JcrRdfTools(idTranslator, session);
  }

  /**
   * Factory method to create a new JcrRdfTools instance with full context.
   *
   * @param graphSubjects
   * @param session
   * @param lls
   * @return
   */
  public static JcrRdfTools withContext(
      final IdentifierTranslator graphSubjects,
      final Session session,
      final LowLevelStorageService lls) {
    return new JcrRdfTools(graphSubjects, session, lls);
  }

  /**
   * Convert a Fedora RDF Namespace into its JCR equivalent
   *
   * @param rdfNamespaceUri a namespace from an RDF document
   * @return the JCR namespace, or the RDF namespace if no matching JCR namespace is found
   */
  public static String getJcrNamespaceForRDFNamespace(final String rdfNamespaceUri) {
    if (rdfNamespacesToJcrNamespaces.containsKey(rdfNamespaceUri)) {
      return rdfNamespacesToJcrNamespaces.get(rdfNamespaceUri);
    }
    return rdfNamespaceUri;
  }

  /**
   * Convert a JCR namespace into an RDF namespace fit for downstream consumption.
   *
   * @param jcrNamespaceUri a namespace from the JCR NamespaceRegistry
   * @return an RDF namespace for downstream consumption.
   */
  public static String getRDFNamespaceForJcrNamespace(final String jcrNamespaceUri) {
    if (jcrNamespacesToRDFNamespaces.containsKey(jcrNamespaceUri)) {
      return jcrNamespacesToRDFNamespaces.get(jcrNamespaceUri);
    }
    return jcrNamespaceUri;
  }

  /**
   * Get a model in which to collect statements of RDF extraction problems
   *
   * @return
   */
  public static Model getProblemsModel() {
    return createDefaultModel();
  }

  /**
   * Using the same graph subjects, create a new JcrRdfTools with the given session
   *
   * @param session
   * @return
   */
  public JcrRdfTools withSession(final Session session) {
    return new JcrRdfTools(graphSubjects, session);
  }

  /**
   * Get an {@link RdfStream} for the given JCR NodeIterator
   *
   * @param nodeIterator
   * @param iteratorSubject
   * @return
   * @throws RepositoryException
   */
  public RdfStream getJcrPropertiesModel(
      final Iterator<Node> nodeIterator, final Resource iteratorSubject)
      throws RepositoryException {

    final RdfStream results = new RdfStream();
    while (nodeIterator.hasNext()) {
      final Node node = nodeIterator.next();
      results.concat(new PropertiesRdfContext(node, graphSubjects, llstore));
      if (iteratorSubject != null) {
        results.concat(
            singleton(
                create(
                    iteratorSubject.asNode(),
                    HAS_MEMBER_OF_RESULT.asNode(),
                    graphSubjects.getSubject(node.getPath()).asNode())));
      }
    }
    return results;
  }

  /**
   * Get an {@link RdfStream} for a node that includes all its own JCR properties, as well as the
   * properties of its immediate children. TODO add triples for root node, ala
   * addRepositoryMetricsToModel()
   *
   * @param node
   * @return
   * @throws RepositoryException
   */
  public RdfStream getJcrTriples(final Node node) throws RepositoryException {
    return new PropertiesRdfContext(node, graphSubjects, llstore);
  }

  /**
   * Get an {@link RdfStream} for the JCR version history information for a node
   *
   * @param node
   * @return
   * @throws RepositoryException
   */
  public RdfStream getVersionTriples(final Node node) throws RepositoryException {
    return new VersionsRdfContext(node, graphSubjects, llstore);
  }

  /**
   * Serialize the JCR fixity information in an {@link RdfStream}
   *
   * @param node
   * @param blobs
   * @return
   * @throws RepositoryException
   */
  public RdfStream getJcrTriples(final Node node, final Iterable<FixityResult> blobs)
      throws RepositoryException {
    return new FixityRdfContext(node, graphSubjects, llstore, blobs);
  }

  /**
   * Get an {@link RdfStream} of the registered JCR namespaces
   *
   * @return
   * @throws RepositoryException
   */
  public RdfStream getNamespaceTriples() throws RepositoryException {
    return new NamespaceRdfContext(session);
  }

  /**
   * Get an {@link RdfStream} of the registered JCR workspaces
   *
   * @return
   * @throws RepositoryException
   */
  public RdfStream getWorkspaceTriples(final IdentifierTranslator subjects)
      throws RepositoryException {
    return new WorkspaceRdfContext(session, subjects);
  }

  /**
   * Add the properties of a Node's parent and immediate children (as well as the jcr:content of
   * children) to the given {@link RdfStream}
   *
   * @param node
   * @throws RepositoryException
   */
  public RdfStream getTreeTriples(final Node node, final HierarchyRdfContextOptions options)
      throws RepositoryException {
    return new HierarchyRdfContext(node, graphSubjects, llstore, options);
  }

  /**
   * Add the properties of a Node's parent and immediate children using the default serialization
   * options
   *
   * @param node
   * @return
   * @throws RepositoryException
   */
  public RdfStream getTreeTriples(final Node node) throws RepositoryException {
    return getTreeTriples(node, HierarchyRdfContextOptions.DEFAULT);
  }

  /**
   * Decides whether the RDF representation of this {@link Node} will receive LDP Container status.
   *
   * @param node
   * @return
   * @throws RepositoryException
   */
  public static boolean isContainer(final Node node) throws RepositoryException {
    return HAS_CHILD_NODE_DEFINITIONS.apply(node.getPrimaryNodeType())
        || any(ImmutableList.copyOf(node.getMixinNodeTypes()), HAS_CHILD_NODE_DEFINITIONS);
  }

  static Predicate<NodeType> HAS_CHILD_NODE_DEFINITIONS =
      new Predicate<NodeType>() {

        @Override
        public boolean apply(final NodeType input) {
          return input.getChildNodeDefinitions().length > 0;
        }
      };

  /**
   * Determine if a predicate is an internal property of a node (and should not be modified from
   * external sources)
   *
   * @param subjectNode
   * @param predicate
   * @return
   */
  public boolean isInternalProperty(final Node subjectNode, final Resource predicate) {
    switch (predicate.getNameSpace()) {
      case REPOSITORY_NAMESPACE:
      case JCR_NAMESPACE:
      case LDP_NAMESPACE:
        return true;
      default:
        return false;
    }
  }

  /**
   * Create a JCR value from an RDFNode, either by using the given JCR PropertyType or by looking at
   * the RDFNode Datatype
   *
   * @param data an RDF Node (possibly with a DataType)
   * @param type a JCR PropertyType value
   * @return a JCR Value
   * @throws javax.jcr.RepositoryException
   */
  public Value createValue(final Node node, final RDFNode data, final int type)
      throws RepositoryException {
    final ValueFactory valueFactory = node.getSession().getValueFactory();
    return createValue(valueFactory, data, type);
  }

  /**
   * Create a JCR value (with an undefined type) from a RDFNode
   *
   * @param data
   * @return
   * @throws RepositoryException
   */
  public Value createValue(final RDFNode data) throws RepositoryException {
    return createValue(data, UNDEFINED);
  }

  /**
   * Create a JCR value from an RDFNode with the given JCR type
   *
   * @param data
   * @param type
   * @return
   * @throws RepositoryException
   */
  public Value createValue(final RDFNode data, final int type) throws RepositoryException {
    return createValue(session.getValueFactory(), data, type);
  }

  /**
   * Create a JCR value from an RDF node with the given JCR type
   *
   * @param valueFactory
   * @param data
   * @param type
   * @return
   * @throws RepositoryException
   */
  public Value createValue(final ValueFactory valueFactory, final RDFNode data, final int type)
      throws RepositoryException {
    assert (valueFactory != null);

    if (data.isURIResource() && (type == REFERENCE || type == WEAKREFERENCE)) {
      // reference to another node (by path)
      final Node nodeFromGraphSubject =
          session.getNode(graphSubjects.getPathFromSubject(data.asResource()));
      return valueFactory.createValue(nodeFromGraphSubject, type == WEAKREFERENCE);
    } else if (data.isURIResource() || type == URI) {
      // some random opaque URI
      return valueFactory.createValue(data.toString(), PropertyType.URI);
    } else if (data.isResource()) {
      // a non-URI resource (e.g. a blank node)
      return valueFactory.createValue(data.toString(), UNDEFINED);
    } else if (data.isLiteral() && type == UNDEFINED) {
      // the JCR schema doesn't know what this should be; so introspect
      // the RDF and try to figure it out
      final Literal literal = data.asLiteral();
      final RDFDatatype dataType = literal.getDatatype();
      final Object rdfValue = literal.getValue();

      if (rdfValue instanceof Boolean) {
        return valueFactory.createValue((Boolean) rdfValue);
      } else if (rdfValue instanceof Byte
          || (dataType != null && dataType.getJavaClass() == Byte.class)) {
        return valueFactory.createValue(literal.getByte());
      } else if (rdfValue instanceof Double) {
        return valueFactory.createValue((Double) rdfValue);
      } else if (rdfValue instanceof Float) {
        return valueFactory.createValue((Float) rdfValue);
      } else if (rdfValue instanceof Long
          || (dataType != null && dataType.getJavaClass() == Long.class)) {
        return valueFactory.createValue(literal.getLong());
      } else if (rdfValue instanceof Short
          || (dataType != null && dataType.getJavaClass() == Short.class)) {
        return valueFactory.createValue(literal.getShort());
      } else if (rdfValue instanceof Integer) {
        return valueFactory.createValue((Integer) rdfValue);
      } else if (rdfValue instanceof XSDDateTime) {
        return valueFactory.createValue(((XSDDateTime) rdfValue).asCalendar());
      } else {
        return valueFactory.createValue(literal.getString(), STRING);
      }

    } else {
      LOGGER.debug("Using default JCR value creation for RDF literal: {}", data);
      return valueFactory.createValue(data.asLiteral().getString(), type);
    }
  }

  /**
   * Given an RDF predicate value (namespace URI + local name), figure out what JCR property to use
   *
   * @param node the JCR node we want a property for
   * @param predicate the predicate to map to a property name
   * @return
   * @throws RepositoryException
   */
  public String getPropertyNameFromPredicate(
      final Node node, final com.hp.hpl.jena.rdf.model.Property predicate)
      throws RepositoryException {
    final Map<String, String> s = emptyMap();
    return getPropertyNameFromPredicate(node, predicate, s);
  }

  /**
   * Given an RDF predicate value (namespace URI + local name), figure out what JCR property to use
   *
   * @param node the JCR node we want a property for
   * @param predicate the predicate to map to a property name
   * @param namespaceMapping prefix => uri namespace mapping
   * @return the JCR property name
   * @throws RepositoryException
   */
  public String getPropertyNameFromPredicate(
      final Node node,
      final com.hp.hpl.jena.rdf.model.Property predicate,
      final Map<String, String> namespaceMapping)
      throws RepositoryException {

    final NamespaceRegistry namespaceRegistry = getNamespaceRegistry.apply(node);

    return getPropertyNameFromPredicate(namespaceRegistry, predicate, namespaceMapping);
  }

  /**
   * Get the property name for an RDF predicate
   *
   * @param predicate
   * @param namespaceMapping
   * @return
   * @throws RepositoryException
   */
  public String getPropertyNameFromPredicate(
      final com.hp.hpl.jena.rdf.model.Property predicate,
      final Map<String, String> namespaceMapping)
      throws RepositoryException {

    final NamespaceRegistry namespaceRegistry =
        (org.modeshape.jcr.api.NamespaceRegistry) session.getWorkspace().getNamespaceRegistry();

    return getPropertyNameFromPredicate(namespaceRegistry, predicate, namespaceMapping);
  }

  /**
   * Get a property name for an RDF predicate
   *
   * @param predicate
   * @return
   * @throws RepositoryException
   */
  public String getPropertyNameFromPredicate(final com.hp.hpl.jena.rdf.model.Property predicate)
      throws RepositoryException {

    final Map<String, String> emptyNamespaceMapping = emptyMap();
    return getPropertyNameFromPredicate(predicate, emptyNamespaceMapping);
  }

  /**
   * Get the JCR property name for an RDF predicate
   *
   * @param namespaceRegistry
   * @param predicate
   * @param namespaceMapping
   * @return
   * @throws RepositoryException
   */
  public String getPropertyNameFromPredicate(
      final NamespaceRegistry namespaceRegistry,
      final com.hp.hpl.jena.rdf.model.Property predicate,
      final Map<String, String> namespaceMapping)
      throws RepositoryException {

    final String prefix;

    final String namespace = getJcrNamespaceForRDFNamespace(predicate.getNameSpace());

    assert (namespaceRegistry != null);

    if (namespaceRegistry.isRegisteredUri(namespace)) {
      LOGGER.debug("Discovered namespace: {} in namespace registry.", namespace);
      prefix = namespaceRegistry.getPrefix(namespace);
    } else {
      LOGGER.debug("Didn't discover namespace: {} in namespace registry.", namespace);
      final ImmutableBiMap<String, String> nsMap = ImmutableBiMap.copyOf(namespaceMapping);
      if (nsMap.containsValue(namespace)) {
        LOGGER.debug("Discovered namespace: {} in namespace map: {}.", namespace, nsMap);
        prefix = nsMap.inverse().get(namespace);
        namespaceRegistry.registerNamespace(prefix, namespace);
      } else {
        prefix = namespaceRegistry.registerNamespace(namespace);
      }
    }

    final String localName = predicate.getLocalName();

    final String propertyName = prefix + ":" + localName;

    LOGGER.debug(
        "Took RDF predicate {} and translated it to JCR property {}", predicate, propertyName);

    return propertyName;
  }

  /** Set the Low-level storage server implementation */
  public void setLlstore(final LowLevelStorageService lowLevelStorageService) {
    llstore = lowLevelStorageService;
  }

  /**
   * Given a node type and a property name, figure out an appropriate jcr value type
   *
   * @param nodeType
   * @param propertyName
   * @return
   * @throws RepositoryException
   */
  public int getPropertyType(final String nodeType, final String propertyName)
      throws RepositoryException {
    return getPropertyType(
        session.getWorkspace().getNodeTypeManager().getNodeType(nodeType), propertyName);
  }

  /**
   * Given a node type and a property name, figure out an appropraite jcr value type
   *
   * @param nodeType
   * @param propertyName
   * @return
   */
  public int getPropertyType(final NodeType nodeType, final String propertyName) {
    final PropertyDefinition[] propertyDefinitions = nodeType.getPropertyDefinitions();
    int type = UNDEFINED;
    for (final PropertyDefinition propertyDefinition : propertyDefinitions) {
      if (propertyDefinition.getName().equals(propertyName)) {
        if (type != UNDEFINED) {
          return UNDEFINED;
        }

        type = propertyDefinition.getRequiredType();
      }
    }

    return type;
  }

  /** Map a JCR property to an RDF property with the right namespace URI and local name */
  public static Function<Property, com.hp.hpl.jena.rdf.model.Property> getPredicateForProperty =
      new Function<Property, com.hp.hpl.jena.rdf.model.Property>() {

        @Override
        public com.hp.hpl.jena.rdf.model.Property apply(final Property property) {
          LOGGER.trace("Creating predicate for property: {}", property);
          try {
            if (property instanceof Namespaced) {
              final Namespaced nsProperty = (Namespaced) property;
              final String uri = nsProperty.getNamespaceURI();
              return createProperty(getRDFNamespaceForJcrNamespace(uri), nsProperty.getLocalName());
            }
            return createProperty(property.getName());
          } catch (final RepositoryException e) {
            throw propagate(e);
          }
        }
      };
}
/**
 * Portlet property manager that just translates properties to/from the portal request attributes
 *
 * @author Eric Dalquist
 * @version $Revision$
 */
@Service
public class PropertyToAttributePropertiesManager extends BaseRequestPropertiesManager {
  private IPortalRequestUtils portalRequestUtils;
  private BiMap<String, String> propertyToAttributeMappings = ImmutableBiMap.of();
  private BiMap<String, String> attributeToPropertyMappings = ImmutableBiMap.of();
  private Set<String> nonNamespacedProperties = Collections.emptySet();

  /**
   * Map of portlet property names to attribute names, if the value is null the key will be used for
   * both the property and attribute name
   */
  @Resource(name = "portletPropertyToAttributeMappings")
  public void setPropertyMappings(Map<String, String> propertyMappings) {
    this.propertyToAttributeMappings = ImmutableBiMap.copyOf(propertyMappings);
    this.attributeToPropertyMappings = this.propertyToAttributeMappings.inverse();
  }

  /**
   * Properties that should not be namespaced with the portlet's windowId when stored as request
   * attributes
   */
  @Resource(name = "nonNamespacedPortletProperties")
  public void setNonNamespacedProperties(Set<String> nonNamespacedProperties) {
    this.nonNamespacedProperties = ImmutableSet.copyOf(nonNamespacedProperties);
  }

  @Autowired
  public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) {
    this.portalRequestUtils = portalRequestUtils;
  }

  /* (non-Javadoc)
   * @see org.jasig.portal.portlet.container.properties.BaseRequestPropertiesManager#addResponseProperty(javax.servlet.http.HttpServletRequest, org.jasig.portal.portlet.om.IPortletWindow, java.lang.String, java.lang.String)
   */
  @Override
  public void addResponseProperty(
      HttpServletRequest portletRequest,
      IPortletWindow portletWindow,
      String property,
      String value) {
    if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) {
      return;
    }

    final HttpServletRequest portalRequest =
        this.portalRequestUtils.getOriginalPortalRequest(portletRequest);

    final String attributeName = getAttributeName(portletWindow, property);

    final Object existingValue = portalRequest.getAttribute(attributeName);
    if (!(existingValue instanceof List)) {
      this.logger.warn(
          "Attribute {} for property {} exists but is NOT a List, it will be replaced",
          attributeName,
          property);
      this.setResponseProperty(portletRequest, portletWindow, property, value);
      return;
    }

    logger.debug("Adding property {} as attribute {}", property, attributeName);

    final List<String> values = (List<String>) existingValue;
    values.add(value);
    portalRequest.setAttribute(attributeName, values);
  }

  /* (non-Javadoc)
   * @see org.jasig.portal.portlet.container.properties.BaseRequestPropertiesManager#setResponseProperty(javax.servlet.http.HttpServletRequest, org.jasig.portal.portlet.om.IPortletWindow, java.lang.String, java.lang.String)
   */
  @Override
  public void setResponseProperty(
      HttpServletRequest portletRequest,
      IPortletWindow portletWindow,
      String property,
      String value) {
    if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) {
      return;
    }

    final HttpServletRequest portalRequest =
        this.portalRequestUtils.getOriginalPortalRequest(portletRequest);

    final String attributeName = getAttributeName(portletWindow, property);

    logger.debug("Setting property {} as attribute {}", property, attributeName);

    final List<String> values = new LinkedList<String>();
    values.add(value);
    portalRequest.setAttribute(attributeName, values);
  }

  protected String getAttributeName(IPortletWindow portletWindow, String property) {
    final String mappedAttributeName = this.propertyToAttributeMappings.get(property);
    final String attributeName;
    if (mappedAttributeName == null) {
      attributeName = property;
    } else {
      attributeName = mappedAttributeName;
    }

    if (this.nonNamespacedProperties.contains(property)) {
      return attributeName;
    }

    final IPortletWindowId portletWindowId = portletWindow.getPortletWindowId();
    return portletWindowId.getStringId() + attributeName;
  }

  /* (non-Javadoc)
   * @see org.jasig.portal.portlet.container.properties.BaseRequestPropertiesManager#getRequestProperties(javax.servlet.http.HttpServletRequest, org.jasig.portal.portlet.om.IPortletWindow)
   */
  @Override
  public Map<String, String[]> getRequestProperties(
      HttpServletRequest portletRequest, IPortletWindow portletWindow) {
    if (this.propertyToAttributeMappings.isEmpty() && this.nonNamespacedProperties.isEmpty()) {
      return Collections.emptyMap();
    }

    final HttpServletRequest portalRequest =
        this.portalRequestUtils.getOriginalPortalRequest(portletRequest);
    final String windowIdStr = portletWindow.getPortletWindowId().getStringId();

    final Builder<String, String[]> properties = ImmutableMap.builder();
    for (final Enumeration<String> attributeNames = portalRequest.getAttributeNames();
        attributeNames.hasMoreElements(); ) {
      final String fullAttributeName = attributeNames.nextElement();
      final String propertyName = getPropertyName(windowIdStr, fullAttributeName);
      if (propertyName == null) {
        continue;
      }

      logger.debug(
          "Found portal request attribute {} returning as property {}",
          fullAttributeName,
          propertyName);

      final Object value = portalRequest.getAttribute(fullAttributeName);
      final String[] values = convertValue(value);

      properties.put(propertyName, values);
    }

    return properties.build();
  }

  /** Convert a request attribute name to a portlet property name */
  private String getPropertyName(final String windowIdStr, final String fullAttributeName) {
    final String attributeName;
    if (this.nonNamespacedProperties.contains(fullAttributeName)) {
      attributeName = fullAttributeName;
    } else if (fullAttributeName.startsWith(windowIdStr)) {
      attributeName = fullAttributeName.substring(windowIdStr.length());
    } else {
      return null;
    }

    final String mappedPropertyName = this.attributeToPropertyMappings.get(attributeName);
    if (mappedPropertyName == null) {
      logger.warn(
          "Attribute {} found that matches the portlet window ID but it is not listed in the propertyMappings or nonNamespacedProperties and will not be returned to the portlet",
          attributeName);
      return null;
    }

    return mappedPropertyName;
  }

  protected String[] convertValue(Object value) {
    if (value == null) {
      return new String[] {null};
    } else if (value instanceof Collection) {
      final Collection<?> valuesCol = (Collection<?>) value;
      final String[] values = new String[valuesCol.size()];
      int i = 0;
      for (final Object obj : valuesCol) {
        values[i++] = String.valueOf(obj);
      }
      return values;
    } else {
      return new String[] {String.valueOf(value)};
    }
  }
}
Пример #23
0
/**
 * Supplies an arbitrary "default" instance for a wide range of types, often useful in testing
 * utilities.
 *
 * <p>Covers arrays, enums and common types defined in {@code java.lang}, {@code java.lang.reflect},
 * {@code java.io}, {@code java.nio}, {@code java.math}, {@code java.util}, {@code
 * java.util.concurrent}, {@code java.util.regex}, {@code com.google.common.base}, {@code
 * com.google.common.collect} and {@code com.google.common.primitives}. In addition, if the type
 * exposes at least one public static final constant of the same type, one of the constants will be
 * used; or if the class exposes a public parameter-less constructor then it will be "new"d and
 * returned.
 *
 * <p>All default instances returned by {@link #get} are generics-safe. Clients won't get type
 * errors for using {@code get(Comparator.class)} as a {@code Comparator<Foo>}, for example.
 * Immutable empty instances are returned for collection types; {@code ""} for string; {@code 0} for
 * number types; reasonable default instance for other stateless types. For mutable types, a fresh
 * instance is created each time {@code get()} is called.
 *
 * @author Kevin Bourrillion
 * @author Ben Yu
 * @since 12.0
 */
@Beta
public final class ArbitraryInstances {

  private static final Ordering<Field> BY_FIELD_NAME =
      new Ordering<Field>() {
        @Override
        public int compare(Field left, Field right) {
          return left.getName().compareTo(right.getName());
        }
      };

  /**
   * Returns a new {@code MatchResult} that corresponds to a successful match. Apache Harmony (used
   * in Android) requires a successful match in order to generate a {@code MatchResult}:
   * http://goo.gl/5VQFmC
   */
  private static MatchResult newMatchResult() {
    Matcher matcher = Pattern.compile(".").matcher("X");
    matcher.find();
    return matcher.toMatchResult();
  }

  private static final ClassToInstanceMap<Object> DEFAULTS =
      ImmutableClassToInstanceMap.builder()
          // primitives
          .put(Object.class, "")
          .put(Number.class, 0)
          .put(UnsignedInteger.class, UnsignedInteger.ZERO)
          .put(UnsignedLong.class, UnsignedLong.ZERO)
          .put(BigInteger.class, BigInteger.ZERO)
          .put(BigDecimal.class, BigDecimal.ZERO)
          .put(CharSequence.class, "")
          .put(String.class, "")
          .put(Pattern.class, Pattern.compile(""))
          .put(MatchResult.class, newMatchResult())
          .put(TimeUnit.class, TimeUnit.SECONDS)
          .put(Charset.class, Charsets.UTF_8)
          .put(Currency.class, Currency.getInstance(Locale.US))
          .put(Locale.class, Locale.US)
          // common.base
          .put(CharMatcher.class, CharMatcher.NONE)
          .put(Joiner.class, Joiner.on(','))
          .put(Splitter.class, Splitter.on(','))
          .put(Optional.class, Optional.absent())
          .put(Predicate.class, Predicates.alwaysTrue())
          .put(Equivalence.class, Equivalence.equals())
          .put(Ticker.class, Ticker.systemTicker())
          .put(Stopwatch.class, Stopwatch.createUnstarted())
          // io types
          .put(InputStream.class, new ByteArrayInputStream(new byte[0]))
          .put(ByteArrayInputStream.class, new ByteArrayInputStream(new byte[0]))
          .put(Readable.class, new StringReader(""))
          .put(Reader.class, new StringReader(""))
          .put(StringReader.class, new StringReader(""))
          .put(Buffer.class, ByteBuffer.allocate(0))
          .put(CharBuffer.class, CharBuffer.allocate(0))
          .put(ByteBuffer.class, ByteBuffer.allocate(0))
          .put(ShortBuffer.class, ShortBuffer.allocate(0))
          .put(IntBuffer.class, IntBuffer.allocate(0))
          .put(LongBuffer.class, LongBuffer.allocate(0))
          .put(FloatBuffer.class, FloatBuffer.allocate(0))
          .put(DoubleBuffer.class, DoubleBuffer.allocate(0))
          .put(File.class, new File(""))
          .put(ByteSource.class, ByteSource.empty())
          .put(CharSource.class, CharSource.empty())
          .put(ByteSink.class, NullByteSink.INSTANCE)
          .put(CharSink.class, NullByteSink.INSTANCE.asCharSink(Charsets.UTF_8))
          // All collections are immutable empty. So safe for any type parameter.
          .put(Iterator.class, ImmutableSet.of().iterator())
          .put(PeekingIterator.class, Iterators.peekingIterator(ImmutableSet.of().iterator()))
          .put(ListIterator.class, ImmutableList.of().listIterator())
          .put(Iterable.class, ImmutableSet.of())
          .put(Collection.class, ImmutableList.of())
          .put(ImmutableCollection.class, ImmutableList.of())
          .put(List.class, ImmutableList.of())
          .put(ImmutableList.class, ImmutableList.of())
          .put(Set.class, ImmutableSet.of())
          .put(ImmutableSet.class, ImmutableSet.of())
          .put(SortedSet.class, ImmutableSortedSet.of())
          .put(ImmutableSortedSet.class, ImmutableSortedSet.of())
          .put(NavigableSet.class, Sets.unmodifiableNavigableSet(Sets.newTreeSet()))
          .put(Map.class, ImmutableMap.of())
          .put(ImmutableMap.class, ImmutableMap.of())
          .put(SortedMap.class, ImmutableSortedMap.of())
          .put(ImmutableSortedMap.class, ImmutableSortedMap.of())
          .put(NavigableMap.class, Maps.unmodifiableNavigableMap(Maps.newTreeMap()))
          .put(Multimap.class, ImmutableMultimap.of())
          .put(ImmutableMultimap.class, ImmutableMultimap.of())
          .put(ListMultimap.class, ImmutableListMultimap.of())
          .put(ImmutableListMultimap.class, ImmutableListMultimap.of())
          .put(SetMultimap.class, ImmutableSetMultimap.of())
          .put(ImmutableSetMultimap.class, ImmutableSetMultimap.of())
          .put(
              SortedSetMultimap.class,
              Multimaps.unmodifiableSortedSetMultimap(TreeMultimap.create()))
          .put(Multiset.class, ImmutableMultiset.of())
          .put(ImmutableMultiset.class, ImmutableMultiset.of())
          .put(SortedMultiset.class, ImmutableSortedMultiset.of())
          .put(ImmutableSortedMultiset.class, ImmutableSortedMultiset.of())
          .put(BiMap.class, ImmutableBiMap.of())
          .put(ImmutableBiMap.class, ImmutableBiMap.of())
          .put(Table.class, ImmutableTable.of())
          .put(ImmutableTable.class, ImmutableTable.of())
          .put(RowSortedTable.class, Tables.unmodifiableRowSortedTable(TreeBasedTable.create()))
          .put(ClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
          .put(ImmutableClassToInstanceMap.class, ImmutableClassToInstanceMap.builder().build())
          .put(Comparable.class, ByToString.INSTANCE)
          .put(Comparator.class, AlwaysEqual.INSTANCE)
          .put(Ordering.class, AlwaysEqual.INSTANCE)
          .put(Range.class, Range.all())
          .put(MapConstraint.class, MapConstraints.notNull())
          .put(MapDifference.class, Maps.difference(ImmutableMap.of(), ImmutableMap.of()))
          .put(
              SortedMapDifference.class,
              Maps.difference(ImmutableSortedMap.of(), ImmutableSortedMap.of()))
          // reflect
          .put(AnnotatedElement.class, Object.class)
          .put(GenericDeclaration.class, Object.class)
          .put(Type.class, Object.class)
          .build();

  /**
   * type -> implementation. Inherently mutable interfaces and abstract classes are mapped to their
   * default implementations and are "new"d upon get().
   */
  private static final ConcurrentMap<Class<?>, Class<?>> implementations = Maps.newConcurrentMap();

  private static <T> void setImplementation(Class<T> type, Class<? extends T> implementation) {
    checkArgument(type != implementation, "Don't register %s to itself!", type);
    checkArgument(
        !DEFAULTS.containsKey(type), "A default value was already registered for %s", type);
    checkArgument(
        implementations.put(type, implementation) == null,
        "Implementation for %s was already registered",
        type);
  }

  static {
    setImplementation(Appendable.class, StringBuilder.class);
    setImplementation(BlockingQueue.class, LinkedBlockingDeque.class);
    setImplementation(BlockingDeque.class, LinkedBlockingDeque.class);
    setImplementation(ConcurrentMap.class, ConcurrentHashMap.class);
    setImplementation(ConcurrentNavigableMap.class, ConcurrentSkipListMap.class);
    setImplementation(CountDownLatch.class, Dummies.DummyCountDownLatch.class);
    setImplementation(Deque.class, ArrayDeque.class);
    setImplementation(OutputStream.class, ByteArrayOutputStream.class);
    setImplementation(PrintStream.class, Dummies.InMemoryPrintStream.class);
    setImplementation(PrintWriter.class, Dummies.InMemoryPrintWriter.class);
    setImplementation(Queue.class, ArrayDeque.class);
    setImplementation(Random.class, Dummies.DeterministicRandom.class);
    setImplementation(
        ScheduledThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class);
    setImplementation(ThreadPoolExecutor.class, Dummies.DummyScheduledThreadPoolExecutor.class);
    setImplementation(Writer.class, StringWriter.class);
    setImplementation(Runnable.class, Dummies.DummyRunnable.class);
    setImplementation(ThreadFactory.class, Dummies.DummyThreadFactory.class);
    setImplementation(Executor.class, Dummies.DummyExecutor.class);
  }

  @SuppressWarnings("unchecked") // it's a subtype map
  @Nullable
  private static <T> Class<? extends T> getImplementation(Class<T> type) {
    return (Class<? extends T>) implementations.get(type);
  }

  private static final Logger logger = Logger.getLogger(ArbitraryInstances.class.getName());

  /**
   * Returns an arbitrary instance for {@code type}, or {@code null} if no arbitrary instance can be
   * determined.
   */
  @Nullable
  public static <T> T get(Class<T> type) {
    T defaultValue = DEFAULTS.getInstance(type);
    if (defaultValue != null) {
      return defaultValue;
    }
    Class<? extends T> implementation = getImplementation(type);
    if (implementation != null) {
      return get(implementation);
    }
    if (type.isEnum()) {
      T[] enumConstants = type.getEnumConstants();
      return (enumConstants.length == 0) ? null : enumConstants[0];
    }
    if (type.isArray()) {
      return createEmptyArray(type);
    }
    T jvmDefault = Defaults.defaultValue(Primitives.unwrap(type));
    if (jvmDefault != null) {
      return jvmDefault;
    }
    if (Modifier.isAbstract(type.getModifiers()) || !Modifier.isPublic(type.getModifiers())) {
      return arbitraryConstantInstanceOrNull(type);
    }
    final Constructor<T> constructor;
    try {
      constructor = type.getConstructor();
    } catch (NoSuchMethodException e) {
      return arbitraryConstantInstanceOrNull(type);
    }
    constructor.setAccessible(true); // accessibility check is too slow
    try {
      return constructor.newInstance();
    } catch (InstantiationException impossible) {
      throw new AssertionError(impossible);
    } catch (IllegalAccessException impossible) {
      throw new AssertionError(impossible);
    } catch (InvocationTargetException e) {
      logger.log(Level.WARNING, "Exception while invoking default constructor.", e.getCause());
      return arbitraryConstantInstanceOrNull(type);
    }
  }

  @Nullable
  private static <T> T arbitraryConstantInstanceOrNull(Class<T> type) {
    Field[] fields = type.getDeclaredFields();
    Arrays.sort(fields, BY_FIELD_NAME);
    for (Field field : fields) {
      if (Modifier.isPublic(field.getModifiers())
          && Modifier.isStatic(field.getModifiers())
          && Modifier.isFinal(field.getModifiers())) {
        if (field.getGenericType() == field.getType() && type.isAssignableFrom(field.getType())) {
          field.setAccessible(true);
          try {
            T constant = type.cast(field.get(null));
            if (constant != null) {
              return constant;
            }
          } catch (IllegalAccessException impossible) {
            throw new AssertionError(impossible);
          }
        }
      }
    }
    return null;
  }

  private static <T> T createEmptyArray(Class<T> arrayType) {
    return arrayType.cast(Array.newInstance(arrayType.getComponentType(), 0));
  }

  // Internal implementations of some classes, with public default constructor that get() needs.
  private static final class Dummies {

    public static final class InMemoryPrintStream extends PrintStream {
      public InMemoryPrintStream() {
        super(new ByteArrayOutputStream());
      }
    }

    public static final class InMemoryPrintWriter extends PrintWriter {
      public InMemoryPrintWriter() {
        super(new StringWriter());
      }
    }

    public static final class DeterministicRandom extends Random {
      public DeterministicRandom() {
        super(0);
      }
    }

    public static final class DummyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
      public DummyScheduledThreadPoolExecutor() {
        super(1);
      }
    }

    public static final class DummyCountDownLatch extends CountDownLatch {
      public DummyCountDownLatch() {
        super(0);
      }
    }

    public static final class DummyRunnable implements Runnable, Serializable {
      @Override
      public void run() {}
    }

    public static final class DummyThreadFactory implements ThreadFactory, Serializable {
      @Override
      public Thread newThread(Runnable r) {
        return new Thread(r);
      }
    }

    public static final class DummyExecutor implements Executor, Serializable {
      @Override
      public void execute(Runnable command) {}
    }
  }

  private static final class NullByteSink extends ByteSink implements Serializable {
    private static final NullByteSink INSTANCE = new NullByteSink();

    @Override
    public OutputStream openStream() {
      return ByteStreams.nullOutputStream();
    }
  }

  // Compare by toString() to satisfy 2 properties:
  // 1. compareTo(null) should throw NullPointerException
  // 2. the order is deterministic and easy to understand, for debugging purpose.
  private static final class ByToString implements Comparable<Object>, Serializable {
    private static final ByToString INSTANCE = new ByToString();

    @Override
    public int compareTo(Object o) {
      return toString().compareTo(o.toString());
    }

    @Override
    public String toString() {
      return "BY_TO_STRING";
    }

    private Object readResolve() {
      return INSTANCE;
    }
  }

  // Always equal is a valid total ordering. And it works for any Object.
  private static final class AlwaysEqual extends Ordering<Object> implements Serializable {
    private static final AlwaysEqual INSTANCE = new AlwaysEqual();

    @Override
    public int compare(Object o1, Object o2) {
      return 0;
    }

    @Override
    public String toString() {
      return "ALWAYS_EQUAL";
    }

    private Object readResolve() {
      return INSTANCE;
    }
  }

  private ArbitraryInstances() {}
}
Пример #24
0
 /**
  * Returns an immutable map containing a single entry. This map behaves and performs comparably to
  * {@link Collections#singletonMap} but will not accept a null key or value. It is preferable
  * mainly for consistency and maintainability of your code.
  */
 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
   return ImmutableBiMap.of(k1, v1);
 }
Пример #25
0
 /**
  * Returns the empty map. This map behaves and performs comparably to {@link
  * Collections#emptyMap}, and is preferable mainly for consistency and maintainability of your
  * code.
  */
 public static <K, V> ImmutableMap<K, V> of() {
   return ImmutableBiMap.of();
 }
Пример #26
0
 @Override
 protected Map<String, Integer> makeEmptyMap() {
   return ImmutableBiMap.of();
 }
Пример #27
0
 private FMLDeobfuscatingRemapper() {
   classNameBiMap = ImmutableBiMap.of();
   mcpNameBiMap = ImmutableBiMap.of();
 }