/* * Copyright 2013-2017 consulo.io * * 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 consulo.components.impl.stores; import com.intellij.diagnostic.PluginException; import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.components.*; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.RoamingTypeDisabled; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; /** * @author VISTALL * @since 27-Feb-17 */ public class StateComponentInfo<T> { private static final Logger LOGGER = Logger.getInstance(StateComponentInfo.class); @NonNls private static final String OPTION_WORKSPACE = "workspace"; @Nullable public static <K> StateComponentInfo<K> of(@NotNull Object o, @Nullable Project project) { if (!(o instanceof PersistentStateComponent) && !(o instanceof JDOMExternalizable)) { return null; } PersistentStateComponent<?> stateComponent = null; State state = null; if (o instanceof PersistentStateComponent) { state = getStateSpec(o.getClass()); stateComponent = (PersistentStateComponent<?>)o; if (project != null) { final ComponentConfig config = ((ComponentManagerImpl)project).getConfig(o.getClass()); if (config != null && isWorkspace(config.options)) { LOGGER.warn("Marker 'workspace' is ignored for component: " + o.getClass().getName()); } } } else if (o instanceof JDOMExternalizable) { state = getStateSpec(o.getClass()); if (state == null) { RoamingType type = o instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER; String name = ComponentManagerImpl.getComponentName(o); String file; if (project == null) { file = StoragePathMacros.DEFAULT_FILE; } else { final ComponentConfig config = ((ComponentManagerImpl)project).getConfig(o.getClass()); assert config != null : "Couldn't find old storage for " + o.getClass().getName(); final boolean workspace = isWorkspace(config.options); file = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.DEFAULT_FILE; } state = new SimpleState(name, file, type); } stateComponent = new JDOMExternalizableWrapper((JDOMExternalizable)o); } PluginId pluginId = PluginManagerCore.getPluginId(o.getClass()); if (state != null && state.storages().length == 0) { if (pluginId == null) { throw new RuntimeException("No @State.storages() define in " + o.getClass().getName()); } else { throw new PluginException("No @State.storages() define in " + o.getClass().getName(), pluginId); } } if (stateComponent != null && state != null) { return new StateComponentInfo<>((PersistentStateComponent<K>)stateComponent, state); } if (pluginId != null) { throw new PluginException("No @State annotation found in " + o.getClass().getName(), pluginId); } throw new RuntimeException("No @State annotation found in " + o.getClass().getName()); } private static boolean isWorkspace(@Nullable Map<?, ?> options) { return options != null && Boolean.parseBoolean((String)options.get(OPTION_WORKSPACE)); } @Nullable private static State getStateSpec(@NotNull Class<?> aClass) { do { State stateSpec = aClass.getAnnotation(State.class); if (stateSpec != null) { return stateSpec; } } while ((aClass = aClass.getSuperclass()) != null); return null; } private PersistentStateComponent<T> myComponent; private State myState; public StateComponentInfo(PersistentStateComponent<T> component, State state) { myComponent = component; myState = state; } @NotNull public PersistentStateComponent<T> getComponent() { return myComponent; } @NotNull public String getName() { return myState.name(); } @NotNull public State getState() { return myState; } @Override public boolean equals(Object obj) { return obj instanceof StateComponentInfo && ((StateComponentInfo)obj).getComponent().equals(((StateComponentInfo)obj).getComponent()); } }