Permalink
Browse files

Fixed plugin loader. Thanks Wolvereness!

  • Loading branch information...
EvilSeph committed Jan 25, 2012
1 parent e2d2767 commit 0a0fee8be25bf8a732abff2d66a89a64614b6327
@@ -29,6 +29,7 @@
/**
* Loads the plugin contained in the specified file
*
* @deprecated SoftDependencies are always ignored
* @param file File to attempt to load
* @param ignoreSoftDependencies Loader will ignore soft dependencies if this flag is set to true
* @return Plugin that was contained in the specified file, or null if
@@ -37,8 +38,19 @@
* @throws InvalidDescriptionException If the plugin description file was invalid
* @throws UnknownDependencyException If a required dependency could not be found
*/
@Deprecated
public Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException;
/**
* Loads a PluginDescriptionFile from the specified file
*
* @param file File to attempt to load from
* @return A new PluginDescriptionFile loaded from the plugin.yml in the specified file
* @throws InvalidPluginException If when the specified file does not contain a plugin description file
* @throws InvalidDescriptionException If the plugin description file could not be created
*/
public PluginDescriptionFile getPluginDescription(File file) throws InvalidPluginException, InvalidDescriptionException;
/**
* Returns a list of all filename filters expected by this PluginLoader
*
@@ -8,6 +8,7 @@
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.PluginCommandYamlParser;
@@ -85,54 +86,170 @@ public void registerInterface(Class<? extends PluginLoader> loader) throws Illeg
* @return A list of all plugins loaded
*/
public Plugin[] loadPlugins(File directory) {
List<Plugin> result = new ArrayList<Plugin>();
File[] files = directory.listFiles();
boolean allFailed = false;
boolean finalPass = false;
Validate.notNull(directory, "Directory cannot be null");
Validate.isTrue(directory.isDirectory(), "Directory must be a directory");
LinkedList<File> filesList = new LinkedList<File>(Arrays.asList(files));
List<Plugin> result = new ArrayList<Plugin>();
Set<Pattern> filters = fileAssociations.keySet();
if (!(server.getUpdateFolder().equals(""))) {
updateDirectory = new File(directory, server.getUpdateFolder());
}
while (!allFailed || finalPass) {
allFailed = true;
Iterator<File> itr = filesList.iterator();
Map<String, File> plugins = new HashMap<String, File>();
Set<String> loadedPlugins = new HashSet<String>();
Map<String, Collection<String>> dependencies = new HashMap<String, Collection<String>>();
Map<String, Collection<String>> softDependencies = new HashMap<String, Collection<String>>();
while (itr.hasNext()) {
File file = itr.next();
Plugin plugin = null;
// This is where it figures out all possible plugins
for (File file : directory.listFiles()) {
PluginLoader loader = null;
for (Pattern filter : filters) {
Matcher match = filter.matcher(file.getName());
if (match.find()) {
loader = fileAssociations.get(filter);
}
}
try {
plugin = loadPlugin(file, finalPass);
} catch (UnknownDependencyException ex) {
if (finalPass) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
itr.remove();
} else {
plugin = null;
if (loader == null) continue;
PluginDescriptionFile description = null;
try {
description = loader.getPluginDescription(file);
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
continue;
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
continue;
}
plugins.put(description.getName(), file);
Collection<? extends String> softDependencySet = (Collection<? extends String>) description.getSoftDepend();
if (softDependencySet != null) {
softDependencies.put(description.getName(), new LinkedList<String>(softDependencySet));
}
Collection<? extends String> dependencySet = (Collection<? extends String>) description.getDepend();
if (dependencySet != null) {
dependencies.put(description.getName(), new LinkedList<String>(dependencySet));
}
}
while (!plugins.isEmpty()) {
boolean missingDependency = true;
Iterator<String> pluginIterator = plugins.keySet().iterator();
while (pluginIterator.hasNext()) {
String plugin = pluginIterator.next();
if (dependencies.containsKey(plugin)) {
Iterator<String> dependencyIterator = dependencies.get(plugin).iterator();
while (dependencyIterator.hasNext()) {
String dependency = dependencyIterator.next();
// Dependency loaded
if (loadedPlugins.contains(dependency)) {
dependencyIterator.remove();
// We have a dependency not found
} else if (!plugins.containsKey(dependency)) {
missingDependency = false;
File file = plugins.get(plugin);
pluginIterator.remove();
softDependencies.remove(plugin);
dependencies.remove(plugin);
server.getLogger().log(
Level.SEVERE,
"Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': ",
new UnknownDependencyException(dependency));
break;
}
}
if (dependencies.containsKey(plugin) && dependencies.get(plugin).isEmpty()) {
dependencies.remove(plugin);
}
}
if (softDependencies.containsKey(plugin)) {
Iterator<String> softDependencyIterator = softDependencies.get(plugin).iterator();
while (softDependencyIterator.hasNext()) {
String softDependency = softDependencyIterator.next();
// Soft depend is no longer around
if (!plugins.containsKey(softDependency)) {
softDependencyIterator.remove();
}
}
if (softDependencies.get(plugin).isEmpty()) {
softDependencies.remove(plugin);
}
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': ", ex.getCause());
itr.remove();
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
itr.remove();
}
if (!(dependencies.containsKey(plugin) || softDependencies.containsKey(plugin)) && plugins.containsKey(plugin)) {
// We're clear to load, no more soft or hard dependencies left
File file = plugins.get(plugin);
pluginIterator.remove();
missingDependency = false;
if (plugin != null) {
result.add(plugin);
allFailed = false;
finalPass = false;
itr.remove();
try {
result.add(loadPlugin(file));
loadedPlugins.add(plugin);
continue;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': ", ex.getCause());
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
} catch (UnknownDependencyException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
}
}
}
if (finalPass) {
break;
} else if (allFailed) {
finalPass = true;
if (missingDependency) {
// We now iterate over plugins until something loads
// This loop will ignore soft dependencies
pluginIterator = plugins.keySet().iterator();
while (pluginIterator.hasNext()) {
String plugin = pluginIterator.next();
if (!dependencies.containsKey(plugin)) {
softDependencies.remove(plugin);
dependencies.remove(plugin);
missingDependency = false;
File file = plugins.get(plugin);
pluginIterator.remove();
try {
result.add(loadPlugin(file));
loadedPlugins.add(plugin);
break;
} catch (InvalidPluginException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': ", ex.getCause());
} catch (InvalidDescriptionException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
} catch (UnknownDependencyException ex) {
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': " + ex.getMessage(), ex);
}
}
}
// We have no plugins left without a depend
if (missingDependency) {
softDependencies.clear();
dependencies.clear();
Iterator<File> failedPluginIterator = plugins.values().iterator();
while (failedPluginIterator.hasNext()) {
File file = failedPluginIterator.next();
failedPluginIterator.remove();
server.getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "' in folder '" + directory.getPath() + "': circular dependency detected");
}
}
}
}
@@ -151,29 +268,9 @@ public void registerInterface(Class<? extends PluginLoader> loader) throws Illeg
* @throws UnknownDependencyException If a required dependency could not be found
*/
public synchronized Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException {
return loadPlugin(file, true);
}
Validate.notNull(file, "File cannot be null");
/**
* Loads the plugin in the specified file
* <p />
* File must be valid according to the current enabled Plugin interfaces
*
* @param file File containing the plugin to load
* @param ignoreSoftDependencies Loader will ignore soft dependencies if this flag is set to true
* @return The Plugin loaded, or null if it was invalid
* @throws InvalidPluginException Thrown when the specified file is not a valid plugin
* @throws InvalidDescriptionException Thrown when the specified file contains an invalid description
* @throws UnknownDependencyException If a required dependency could not be found
*/
public synchronized Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException {
File updateFile = null;
if (updateDirectory != null && updateDirectory.isDirectory() && (updateFile = new File(updateDirectory, file.getName())).isFile()) {
if (FileUtil.copy(updateFile, file)) {
updateFile.delete();
}
}
checkUpdate(file);
Set<Pattern> filters = fileAssociations.keySet();
Plugin result = null;
@@ -185,7 +282,7 @@ public synchronized Plugin loadPlugin(File file, boolean ignoreSoftDependencies)
if (match.find()) {
PluginLoader loader = fileAssociations.get(filter);
result = loader.loadPlugin(file, ignoreSoftDependencies);
result = loader.loadPlugin(file);
}
}
@@ -197,6 +294,35 @@ public synchronized Plugin loadPlugin(File file, boolean ignoreSoftDependencies)
return result;
}
private void checkUpdate(File file) {
if (updateDirectory == null || !updateDirectory.isDirectory()) {
return;
}
File updateFile = new File(updateDirectory, file.getName());
if (updateFile.isFile() && FileUtil.copy(updateFile, file)) {
updateFile.delete();
}
}
/**
* Loads the plugin in the specified file
* <p />
* File must be valid according to the current enabled Plugin interfaces
*
* @deprecated soft-dependencies are now ignored
* @param file File containing the plugin to load
* @param ignoreSoftDependencies Loader will ignore soft dependencies if this flag is set to true
* @return The Plugin loaded, or null if it was invalid
* @throws InvalidPluginException Thrown when the specified file is not a valid plugin
* @throws InvalidDescriptionException Thrown when the specified file contains an invalid description
* @throws UnknownDependencyException If a required dependency could not be found
*/
@Deprecated
public synchronized Plugin loadPlugin(File file, boolean ignoreSoftDependencies) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException {
return loadPlugin(file);
}
/**
* Checks if the given plugin is loaded and returns it when applicable
* <p />
Oops, something went wrong.

17 comments on commit 0a0fee8

@JeBobs

This comment has been minimized.

JeBobs replied Sep 9, 2014

(To Wolvereness) I know this is probably not the place to post this but Dude, chill out. Look at what you are taking down because of your FLIMSY code being moved to Mojang. Take down the copyright (ik, sounds bad) because TRUST ME I know Mojang enough that I would know that your code would be replaced if you did not want it in there. facepalms so hard cracks head open

@oberhamsi

This comment has been minimized.

oberhamsi replied Sep 11, 2014

@JeBobs i tried to understand the situation from reading DMCA + pull request but can't follow. would you care to elaborate why this particular commit is so problematic? is it because this is where they link to proprietary code but the result (has always been) licensed as GPL? and what do you mean with " because of your FLIMSY code being moved to Mojang"?

@KillerKozmo

This comment has been minimized.

KillerKozmo replied Sep 13, 2014

Really!!!!!!!!!!!!

From: Wesley Wolfe
Date: 3 September 2014 03:48
Subject: [SL] [abuse-google] Copyright

My name is Wesley Wolfe. A site hosted on an IP address owned by Multiplay
(ip redacted) is infringing on my software copyright by the distribution
of a software known as CraftBukkit.

Original content can be found at

https://github.com/Wolvereness/Bukkit-Bleeding/commits?author=Wolvereness

0a0fee8

and the appropriate license for previously mentioned content can be found at

https://github.com/Wolvereness/Bukkit-Bleeding/blob/f210234e59275330f83b994e199c76f6abd41ee7/LICENCE.txt

The provided license requires the use of included or linking code to
provide the original source under the GNU GPL license version 3, or any
later version. An official notice has been sent to Mojang AB, whereas the
Chief Operating Officer, Vu Bui, responded with the clear text:

Mojang has not authorized the inclusion of any of its proprietary
Minecraft software (including its Minecraft Server software) within the
Bukkit project to be included in or made subject to any GPL or LGPL
license, or indeed any other open source license

As the Minecraft Server software is included in CraftBukkit, and the
original code has not been provided or its use authorized, this is a
violation of my copyright. I have a good faith belief the distribution of
CraftBukkit includes content of which the distribution is not authorized by
the copyright owner, it's agent, or the law.

Pages including infringing content:
http://dl.bukkit.org/ - links to:
http://dl.bukkit.org/latest-rb/craftbukkit.jar
http://dl.bukkit.org/latest-beta/craftbukkit-beta.jar
http://dl.bukkit.org/downloads/craftbukkit/ - links to 45 pages, with
infringing content beginning on craftbukkit build #1597 and currently
ending at craftbukkit build #3115, but please allow me not to enumerate
them all
http://dl.bukkit.org/downloads/craftbukkit/view/00703_1.1-R1/ (the
first infringing build)

I have a good faith belief that the above information is accurate and that
I am the copyright owner or authorized to act on the copyright owner's
behalf.

Pursuant to the Digital Millennium Copyright Act (17 U.S.C. § 512(c)), the
above mentioned pages need to be expeditiously removed or access-of
disabled.

Electronically Signed:

Wesley Wolfe
address redacted

email redacted

You choose to do this to bukkit? They never did anything to you what so ever! They didn't f-ing copy your code. Thanks to you bukkit is ruined. You had no right to claim something like this because contacting Bukkit. You had no proof whatsoever. You should have shame. But guess what just because they quit doesn't mean CraftBukkit is over -.-. Mojang is continuing it so your little stupid plan to get Bukkit shut down isn't really working out so well. -KillerKozmo

@thaellin

This comment has been minimized.

thaellin replied Sep 13, 2014

I feel badly for Mr Wolfe, since he authored this commit over two years ago. I believe this fact could easily be used in a court of law to show that Mr Wolfe is NOT in fact issuing this DMCA takedown request "in good faith". As such, he may be in a position to be taken to court for malicious misuse of the legal process. Additionally, if Mojang were to quantify any loss of sales they may experience as a result of this request, Mr Wolfe may be liable for the amount in question.

I am not a lawyer, but I do hope Mr Wolfe secured legal counsel and took the appropriate preliminary measures before firing off the big guns. I'm not familiar with DMCA takedown requests, (un?)fortunately, but I doubt he can just make it go away.

I'm also uncertain if Mr Wolfe has any employment position in which he would have enjoyed similar opportunity to leverage his internal knowledge to effect a takedown of a useful product; however, I am quite certain that this event would make his potential employment at most companies a non-starter.

The action was not heroic, whistleblowing, or even the act of a good samaritan; it seems more likely to have been a childish tantrum which will have negative short term consequences for the community and negative long term consequences for Mr Wolfe.

I doubt Mr Wolfe is reading this, but the term that comes to mind is 'own goal' sir.

@CrimsonDream

This comment has been minimized.

CrimsonDream replied Sep 13, 2014

This was a highly predictable breakdown of a relationship that used to suit both parties, and then something happened that changed everything, and uncomfortability seeped into the cracks around pride. Change always has an effect on everything it touches; and whilst some touches are daggerlike prods made with sharp fingernails and fiery breath, some are staining brushes that splashed unintendedly on both minds and egos.

But Mojang and CB need relationship counselling that's all, someone to step in as a third party and project a working compromise. Believing that much is enough because there's always a middle way; especially when children are considered ;) Will things ever be the same? No. But a brighter future is there if it is noticed, it shines outwardly from a courage found dripping from the cold showers of all egos concerned. The alternative is more tepid, and growingly resentful.

@mrmix57

This comment has been minimized.

mrmix57 replied Sep 17, 2014

Gee thanks for having bukkit.org stop giving tons of people CraftBukkit. I'm sure your copyright is having such a huge positive effect on people who actually frequently visited Bukkit.org for the program AND plugins that work with the program. Since this is text on a site found on the Internet you probably aren't able to pick up on my sarcasm for I actually hate you a lot right now)

@dsonbill

This comment has been minimized.

dsonbill replied Oct 25, 2014

@mrmix57 I honestly believe CraftBukkit and the other Bukkit derivatives will be back up eventually. @thaellin is more than likely correct in assuming an ill fate for Mr. Wolfe. Not only in the intention, of course: Mr. Wolfe sent the DMCA for content owned by Microsoft, who he was (almost certainly) not authorized to act on behalf of. Additionally, as there has been a VERY noticeable diminishment of the Minecraft brand (not that it has had an impact, but the brand itself as well as brand trust has taken a hit recently), it may be seen as... something I forget the word for. In any case, he will likely face perjury and/or fraud charges.

@pavilion99

This comment has been minimized.

pavilion99 replied Nov 9, 2014

It is very frustrating to me that you would decide to file this complaint. You have cut off so many people from downloading Bukkit. As a developer, I understand your frustration but there were so many other ways to go about this.

@Noiwex

This comment has been minimized.

Noiwex replied Nov 17, 2014

What a prick.

@beast5888

This comment has been minimized.

beast5888 replied Nov 26, 2014

One Word he is such a bitch for doing this all he wanted was to get attention

@BringBukkitBack

This comment has been minimized.

BringBukkitBack replied Dec 10, 2014

Umm excuse me Mr. Wolfe... I was told (by you) that the original software is available here. Might I ask where it is, or am I going to have to figure that out by myself? At least dl.bukkit.org, had a "Download" button.

@Noiwex

This comment has been minimized.

Noiwex replied Dec 11, 2014

@JoshCode

This comment has been minimized.

JoshCode replied Dec 21, 2014

Perhaps I'm missing something...
Where does Wolfe actually prove that the allegedly copied code is his?
He links us this commit and he links the commits he authored, but none of the commits he authored contain the code that EvilSeph allegedly copied here.

Can somebody explain what I'm not seeing here, because I now I am puzzled as to why the DMCA takedown was accepted and executed, because I cannot find any evidence that this allegedly copied code was originally authored by Wolfe.

@BringBukkitBack

This comment has been minimized.

BringBukkitBack replied Dec 25, 2014

@clarissa-au

This comment has been minimized.

clarissa-au replied Jan 5, 2015

I think that you didn't issue the DMCA notification "in good faith" AND I really think that he did that in personal purposes,on three statements:
1)This commit is committed 3 years ago.The whole project is updated(the last)2 years ago(2013-2015).I can't agree on you that you are issuing this on good faith.
2)Are you sure that you are posting the "correct" copyrights?You should use this one:
http://creativecommons.org/licenses/by-nc-nd/4.0/
(Read about licensing at:http://choosealicense.com/licenses/)
3)Last thing to mention:If you can raise a case on Bukkit on it's license(GPL),the previous two can also raise a case on you if they want!
-> means forked in the follows:
Wolvereness/Bukkit-Bleeding->Bukkit/Bukkit-Bleeding->Bukkit/Bukkit
So,I posted it on good faith,that you issued the DMCA notice on personal purposes,that we don't know and ever not know.

@battlestarsc2

This comment has been minimized.

battlestarsc2 replied Feb 2, 2015

So I still have no Idea what is going on. I don't really see a whole lot copied, and if so, you still don't really have a good case, and this is a problem easily fixed. I don't even know what grounds and reasons you had for reporting this to Mojang.

@faizaand

This comment has been minimized.

faizaand replied Aug 14, 2016

Bukkit would probably still be alive and have found a workaround like Spigot has, if the whole staff team hadn't LEFT.

Please sign in to comment.