/* * Copyright 2003-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.smodel.runtime; import jetbrains.mps.classloading.ModuleClassLoader; import jetbrains.mps.util.annotation.ToRemove; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; public class IconResource { private static final Logger LOG = LogManager.getLogger(IconResource.class); private String myIconResId; private String myClassName; //used to make IconResources unique and avoid things like MPS-24005 private WeakReference<Class> myResourceProvider; //in 3.5, both parameters must become @NotNull public IconResource(String iconResId, Class resourceProvider) { myIconResId = iconResId; myClassName = resourceProvider == null ? null : resourceProvider.getName(); myResourceProvider = new WeakReference<Class>(resourceProvider); } /** * For internal use only * Tmp solution until we migrate to non-static IconManager. */ @Deprecated @ToRemove(version = 3.5) public boolean isAlreadyReloaded() { Class c = myResourceProvider.get(); if (c == null) { return true; } ClassLoader cl = c.getClassLoader(); return cl instanceof ModuleClassLoader && ((ModuleClassLoader) cl).isDisposed(); } @Deprecated @ToRemove(version = 3.4) //left for compatibility purposes. Does not allow to use 2x & dark icons public InputStream getResource() { Class c = myResourceProvider.get(); if (c == null) { showDisposedError("<class already GC'ed>"); return null; } ClassLoader cl = c.getClassLoader(); if (cl instanceof ModuleClassLoader && ((ModuleClassLoader) cl).isDisposed()) { String rp = c.getSimpleName(); showDisposedError(rp); } InputStream result = c.getResourceAsStream(myIconResId); if (result == null) { LOG.warn("Unable to get icon's InputStream. Resource provider=" + c.getSimpleName() + "; iconId:=" + myIconResId); } return result; } public String getResourceId() { return myIconResId; } @Nullable public Class getProvider() { return myResourceProvider.get(); } private void showDisposedError(String rp) { LOG.error("Icon is acquired from a disposed classloader. This will lead to a memleak. \n" + "Do care about classes reloading when you hold an IconResource for a long time. \n" + "Resource provider=" + rp + "; iconId=" + myIconResId, new Throwable()); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } IconResource that = (IconResource) o; if (myIconResId != null ? !myIconResId.equals(that.myIconResId) : that.myIconResId != null) { return false; } return myClassName != null ? myClassName.equals(that.myClassName) : that.myClassName == null; } @Override public int hashCode() { int result = myIconResId != null ? myIconResId.hashCode() : 0; result = 31 * result + (myClassName != null ? myClassName.hashCode() : 0); return result; } }